Quantcast
RSS Entries RSS
RSS Subscribe by Email

Security Lockdown for Linux

Automatic updates

If you’re using Ubuntu you can do this by editing /etc/apt/apt.conf.d/50unattended-upgrades. Running out of date packages with security holes is a good way to get your machine pwnd.

Remove unused software

Every piece of software installed on your system provides one more attack point for malicious users. You should inventory your system and remove anything you don’t need. E.g. to remove Ubuntu One from your system:

sudo apt-get purge ubuntuone*

Secure SSH

Edit /etc/ssh/sshd_config:

PermitRootLogin no
AllowUsers bmccann nx gitolite

You may also disable password authentication and replace it with public key authentication:

PasswordAuthentication no
PubkeyAuthentication yes

Restart the SSH daemon:

sudo service ssh restart

or

sudo /etc/init.d/ssh restart

This disallows login via password and instead replaces it with login via public/private key pair. To setup your public key encryption run ssh-keygen on the client and put ~/.ssh/id_rsa.pub from the client into ~/.ssh/authorized_keys on server.

Sometimes while messing around with SSH settings, you’ll lock yourself out. I this case it’s nice to use the -v option with the ssh client.

You can also setup shortcuts in ~/.ssh/config. E.g. the shortcut below turns ssh gitolite into an alias for ssh -l gitolite -p 77777 bensdynamicdns.getmyip.com.

Host gitolite
   User gitolite
   Hostname bensdynamicdns.getmyip.com
   Port 77777
   IdentityFile ~/.ssh/id_rsa

Secure NX

If you’d like to setup NX with this configuration it takes a couple extra steps than a normal NX installation. Note that every additional service you run on the machine provides one more attack point for hackers, so you’re more secure not running NX at all. However, if you choose to run NX for the benefits that it provides then here are some steps to help keep you safe:

  • Download and install the client, node, and server in that order
  • In /etc/ssh/sshd_config add the nx user by setting AllowUsers nx and restart the ssh daemon sudo /etc/init.d/ssh restart.
  • NX uses a deprecated location for the ssh authorized_keys file, so you must fix that or you will get a public key authentication failed error. Open /usr/NX/etc/server.cfg and change #SSHAuthorizedKeys = "authorized_keys2" to SSHAuthorizedKeys = "authorized_keys". Now run sudo mv /usr/NX/home/nx/.ssh/authorized_keys2 /usr/NX/home/nx/.ssh/authorized_keys if there’s an authorized_key2 file present.
  • Run sudo /usr/NX/scripts/setup/nxserver –install
  • If you’ve disabled SSH passwords then you’ll also need to set EnableUserDB = "1" and EnablePasswordDB = "1" in /usr/NX/etc/server.cfg and then run sudo /usr/NX/bin/nxserver –useradd $USER since we’ve disabled passwords when we locked down SSH.
  • Change the default NX key.  Run sudo /usr/NX/bin/nxserver –keygen.  In your NX client, open “Configure…” > “General” tab > “Key …” and copy the contents of “/usr/NX/share/keys/default.id_dsa.key” into the key window and save it.
  • Optional for connecting to multiple servers at once:  Change DisplayBase in /usr/NX/etc/server.cfg.
  • Restart the NX server to pickup your changes: sudo /etc/init.d/nxserver restart

Secure MySQL

Run mysql_secure_installation

Install fail2ban

  • Install fail2ban by running sudo apt-get install fail2ban, which will lockout users who repeatedly try to access your system by guessing passwords.
  • Make your own copy of the configuration file: sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
  • Check if fail2ban is running properly: sudo fail2ban-client status

More
Andrew Ault wrote a good article as well.
The NSA has a comprehensive guide to securing a Linux system

Comments (1)

Apache CXF Tutorial – WS-Security with Spring

This tutorial will cover adding an authentication component to your web service though WS-Security. If you need an overview of how to setup CXF then you may find our previous tutorial helpful. Another helpful resource is CXF’s own WS-Security tutorial. However, it does not include information on how to setup the client through Spring.

To begin with, make sure you have at least the following .jars in addition to the required base CXF .jars:

spring-beans-2.0.6.jar
spring-context-2.0.6.jar
spring-core-2.0.6.jar
spring-web-2.0.6.jar
wss4j-1.5.1.jar
xmlsec-1.3.0.jar

Now we will add a security interceptor to the server’s Spring configuration file, which we named cxf.xml in the last tutorial in order to match the CXF documentation.

<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:jaxws="http://cxf.apache.org/jaxws"
      xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd

http://cxf.apache.org/jaxws

                          http://cxf.apache.org/schemas/jaxws.xsd">

  <import resource="classpath:META-INF/cxf/cxf.xml" />
  <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml"/>
  <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

  <jaxws:endpoint id="auth"
                  implementor="com.company.auth.service.AuthServiceImpl"
                  address="/corporateAuth">

    <jaxws:inInterceptors>
      <bean class="org.apache.cxf.binding.soap.saaj.SAAJInInterceptor" />
      <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
        <constructor-arg>
          <map>
            <entry key="action" value="UsernameToken" />
            <entry key="passwordType" value="PasswordText" />
            <entry key="passwordCallbackClass" value="com.company.auth.service.ServerPasswordCallback" />
          </map>
        </constructor-arg>
      </bean>
    </jaxws:inInterceptors>

  </jaxws:endpoint>

</beans>

You can change the action and passwordType to do more advanced authentication. In this example, we will simply require all authenticating clients to know a single password specified by the server. If you’d like each client to have it’s own password you can specify that in the callback, which is the next thing we must implement:

package com.company.auth.service;

import java.io.IOException;
import java.util.ResourceBundle;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

import org.apache.ws.security.WSPasswordCallback;

public class ServerPasswordCallback implements CallbackHandler {

    private static final String BUNDLE_LOCATION = "com.company.auth.authServer";
    private static final String PASSWORD_PROPERTY_NAME = "auth.manager.password";

    private static String password;
    static {
        final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_LOCATION);
        password = bundle.getString(PASSWORD_PROPERTY_NAME);
    }

    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {

        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];

        // Set the password on the callback. This will be compared to the
        //     password which was sent from the client.
        // We can call pc.getIdentifer() right here to check the username
        //     if we want each client to have it's own password.
        pc.setPassword(password);
    }

}

The server is now setup to require a password. The password we are requiring is one that we specified in a properties file and then read in through a ResourceBundle. You may find it easier to simply hard code the password on the initial run and then replace it with your own means of authentication once the service is up and running.

If you are running on WebLogic 9, as I was, then you will get an error “java.lang.UnsupportedOperationException: This class does not support SAAJ 1.1“. In order to correct that, make sure your version of the SAAJ classes are being used by adding the following to your weblogic.xml descriptor file:

<container-descriptor>
    <prefer-web-inf-classes>true</prefer-web-inf-classes>
</container-descriptor>

You WebLogic folks must also then set two properties in your WebLogic JDK:

-Djavax.xml.soap.MessageFactory=com.sun.xml.messaging.saaj.soap.ver1_1.SOAPMessageFactory1_1Impl
-Djavax.xml.soap.SOAPConnectionFactory=weblogic.wsee.saaj.SOAPConnectionFactoryImpl

We now have to setup the client to supply a password. Firstly, we will create another Spring file at com/company/auth/service/cxfClient.xml to setup the application context for the client:

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:jaxws="http://cxf.apache.org/jaxws"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
                      http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

  <bean id="proxyFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
    <property name="serviceClass" value="com.company.auth.service.AuthService"/>
    <property name="address" value="http://localhost:7001/authManager/services/corporateAuth"/>
    <property name="inInterceptors">
      <list>
        <ref bean="logIn" />
      </list>
    </property>
    <property name="outInterceptors">
      <list>
        <ref bean="logOut" />
        <ref bean="saajOut" />
        <ref bean="wss4jOut" />
      </list>
    </property>
  </bean>

  <bean id="client" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean" factory-bean="proxyFactory" factory-method="create" />

  <bean id="logIn" class="org.apache.cxf.interceptor.LoggingInInterceptor" />
  <bean id="logOut" class="org.apache.cxf.interceptor.LoggingOutInterceptor" />
  <bean id="saajOut" class="org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor" />
  <bean id="wss4jOut" class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
    <constructor-arg>
      <map>
        <entry key="action" value="UsernameToken" />
        <entry key="user" value="ws-client" />
        <entry key="passwordType" value="PasswordText" />
        <entry key="passwordCallbackClass" value="com.company.auth.service.ClientPasswordCallback" />
      </map>
    </constructor-arg>
  </bean>    

</beans>

We then need to set the password for our message:

package com.company.auth.service;

import java.io.IOException;
import java.util.ResourceBundle;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;

import org.apache.ws.security.WSPasswordCallback;

public class ClientPasswordCallback implements CallbackHandler {

    private static final String BUNDLE_LOCATION = "com.company.auth.authClient";
    private static final String PASSWORD_PROPERTY_NAME = "auth.manager.password";	

    private static String password;
    static {
        final ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_LOCATION);
        password = bundle.getString(PASSWORD_PROPERTY_NAME);
    }	

    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {

        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];

        // set the password for our message.
        pc.setPassword(password);
    }

}

Finally, we create the service factory, which is extremely easy since all the work was done in the Spring file:

package com.company.auth.service;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public final class AuthServiceFactory {

    private static final ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {
                "com/company/auth/service/cxfClient.xml"
            });

    public AuthServiceFactory() {
    }

    public AuthService getService() {
        return (AuthService) context.getBean("client");
    }
}

Congratulations. Your web service now utilizes a basic implementation of WS-Security. Hopefully, that will be enough background to get you on your way.

Comments (58)