miércoles, 14 de noviembre de 2012

Secure LAMP server for production use


Secure LAMP server for production use


Medidas especificas para un Web sever:
Check out Bastille, it's a series of scripts that implements best practices in Linux.
Don't send authentication data over plaintext protocols. For example, disable FTP. If you send authentication data via Apache, use SSL.
Disable and remove any unnecessary software including the GUI interface.
Audit any files with the SUID bit set and remove. (This will severely limit non-root abilities. Understand the implications for each individual change.)
Audit public writable directories and remove the writable bit. (Leave /tmp alone.)
Avoid running any daemon as root.
Research all multi-user software that listens on sockets in detail for security best practices.
Avoiding adding users to the system is one of the best approaches. Multi-user systems require greater attention to detail.
Enforce password standards. For example: minimum 10 characters, non-alphanumeric characters, using letters and numbers. This is to make brute forcing more difficult in case of password file compromise. Enforce this via the system.
Lock out users after 5 failed authentication attempts with a minimum of 10 minute lockout. Maintain a password history so users can't use the past 5 passwords.
If you have a larger environment, using network segregation with multiple subnets to isolate risk is an absolute requirement. If a smaller environment, running a firewall on the local system to limit exposure is recommended. For example, only allowing SSH to your IP. tcpwrappers can be used too for an extra layer. (/etc/hosts.allow, /etc/hosts.deny)
And, of course, keeping all software up to date. Especially public facing daemons.
With SSH:
  • Disable SSH protocol 1
  • Only allow root authentication without-password (only keypair)
With Apache:
  • Disable any modules that are not needed
  • Disable .htaccess and public directories
  • Disable FollowSymlink and any unnecessary options
  • Do not install PHP if you don't need it.
With MySQL:
  • Disable default users.
  • Don't use wildcard hosts.
  • Be sure to set unique host for every user.
  • Don't listen on tcp unless necessary. (Unusually unavoidable.)
  • Limit application user privileges as much as possible. (SELECT,INSERT,UPDATE,DELETE ideal for write and SELECT for read)

Install and configure common services

At this stage, you should have a solid base to build upon. The next step is to compile and install the software servers you will use to serve up your web applications. Installing software from source can be tedious; and there is a great temptation to use the packaged binaries that come with your distribution of choice. I would recommend against this. In a world of zero day exploits, the time it takes the package maintainer to compile and distribute the binaries may be unacceptable. By compiling from the source, you will be in full control of your security situation.

Apache 2.2.0

Now to start compiling and install the services you will be using. Apache is a good place to start, since other packages have compile time dependencies on it.
Always verify the `checksums` of packages you download, if there is a mismatch start over and download it again
    md5sum httpd-2.2.0.tar.gz  
    tar -xzvf httpd-2.2.0.tar.gz 
    ./configure --prefix=/usr/local/apache \
           --enable-ssl --enable-speling \ 
           --enable-rewrite --enable-proxy  
    make  
    make install 

MySQL 5.0.18

Download the MySQL binaries from the mysql site (see resources). This is an exception to my mantra of compiling from source—since the binaries come directly from MySQL, as soon as there is an update you can download the latest version.
Note: due to space constraints {.} is shorthand for the version of the tarball.
  md5sum mysql-{.}-linux-i686-glibc23.tar.gz
  cp mysql-{.}-linux-i686-glibc23.tar.gz /usr/local
  tar -xzvf mysql-{.}-linux-i686-glibc23.tar.gz
  ln -s /usr/local/mysql-{.}-linux-i686-glibc23 \
                                   /usr/local/mysql
        
  groupadd mysql
  useradd -g mysql mysql
  cd mysql
  scripts/mysql_install_db --user=mysql
  chown -R root  .
  chown -R mysql data
  chgrp -R mysql .
  bin/mysqld_safe --user=mysql &
  cp  support-files/mysql.server /etc/init.d/mysql
     
  # Make sure that mysql is started if 
  # there is a reboot
  
  cd /etc/rc3.d/
  ln -s /etc/init.d/mysql S90mysql
  ln -s /etc/init.d/mysql K90mysql

  # Copy the configuration file
  cp support-files/my-medium.cnf /etc/my.cnf

PHP 5.1.2

Now download the php package from the php.net site (see resources).
  md5sum php-5.1.2.tar.gz
  tar -xzvf php-5.1.2.tar.gz
  ./configure --with-prefix=/usr/local/php \ 
      --with-apxs2=/usr/local/apache/bin/apxs \
      --with-mysql=/usr/local/mysql
  make
  make install
  cp php.ini-dist /usr/local/php/php.ini

Tomcat 5.5.16

Apache-Tomcat is also an exception to my always compile rule.
  md5sum apache-tomcat-5.5.16.tar.gz
  tar -xzvf apache-tomcat-5.5.16.tar.gz

mod_jk

Download mod_jk from the the tomcat project page (see resources).
  tar -xzvf jakarta-tomcat-connectors.tar.gz
  cd jakarta/jk/native
  ./configure --with-apxs=/usr/local/apache/bin/apxs
  make
  make install

mod_security

mod_security is the most excellent Apache module written by Ivan Ristic.
  md5sum modsecurity-apache-1.9.2.tar.gz
  tar -xzvf modsecurity-apache-1.9.2.tar.gz
  cd modsecurity-apache-1.9.2/apache2
  /usr/local/apache/bin/apxs -cia mod_security.c

Configuring Apache 2.2.0

By this point, you should have installed all of the services and apache modules needed to host and secure PHP and Java environments. Now it’s time to take a look at properly configuring everything for security.
_Apache 2.2.0_ has the ability to list both statically compiled and shared modules with the `-M` option to `apachectl`
Apache 2.2.0 introduces a new configuration layout and new default options in the httpd.conf file. In previous versions of Apache, there was only one configuration file by default, which wasconf/httpd.conf; in the current version, the Apache project has taken another step towards its goal of making configuration more managable and modular. The conf/httpd.conf is the main configuration file with include statements for the various configuration files under conf/extra such as httpd-ssl.conf and httpd-vhosts.conf.
Another new and exciting security feature in Apache 2.2.0 is that the root httpd.conf access is denied to all directories. This can be confusing to users coming from previous versions such as 2.0.55 but it is a great step forward in terms of security.
Here is the configuration directive mentioned above; I would suggest leaving it the way it is. We will allow access for specific virtual-hosts and directories later on.
  # Default access control  \
  # Highly restrictive and applies \
  # to everything below it.


  
    Options FollowSymLinks
    AllowOverride None
    Order deny,allow
    Deny from all
  
Every host, which Apache will be responsible for, will be a virtual host or “vhost”. So, start by uncommenting the Include directives at the bottom of conf/httpd.conf. This is done so that thehttpd-vhosts.confhttpd-ssl.conf and httpd-dedfault.conf are included in the mainhttpd.conf configuration file.
Yet another cool new feature in Apache 2.2.0 is the ability to see all modules both statically compiled and shared with the -M option to apachectl.
  # Edit /usr/local/apache/conf/httpd.conf

  # Move the LoadModule Statement for mod_security 
  # to the top of all module
  # statements. This is needed to use SecChrootDir

  # Add the following line to load mod_jk
   LoadModule jk_module   modules/mod_jk.so

  # The default User and Group is set to daemon, 
  # create and apache user and group and then 
  # configure apache to run as such.
  User apache
  Group apache

  # List all modules to verify that mod_jk, 
  # mod_security, mod_php, and mod_ssl 
  # are correctly installed and loaded.
   /usr/local/apache/bin/apachectl -M 
      
  # Virtual hosts 
  
  Include conf/extra/httpd-vhosts.conf \
  -> Include conf/extra/httpd-vhosts.conf 
     
  # Various default settings
  Include conf/extra/httpd-default.conf \
  -> Include conf/extra/httpd-default.conf 

  # Secure (SSL/TLS) connections
   Include conf/extra/httpd-ssl.conf \
  -> Include conf/extra/httpd-ssl.conf 
Now it’s time to descend into the extra directory to configure virtual hosts. Open httpd-vhosts.confin your favorite editor. Next, configure the document root to be /srv/www/vhost1. Also, add theAddType directive for phpPHP files don’t have to have the .php file extension. In fact, it’s probably a good idea if they are .html files. By using the .php file extention you are advertizing more information about your setup than you need to.
`mod_security` makes `chrooting` Apache easy!
Here is the full vhost configuration stanza. It is annotated with inline comments: please take the time to read through it.
  # Enable mod_security engine
  SecFilterEngine On

  # Chroot Apache the easy way just make sure 
  # your web content is under the chrooted directory
  
  # Note: The log directives must also be valid 
  # directories releative to the chroot dir.
  
  # Note: THIS CANNOT GO INSIDE VHOST STANZA
  # as it applies to the entire apache configuration
  SecChrootDir /chroot/apache
       
  # Delete the 2nd Vhost stanza as you will only be 
  # using one for now
  
    ServerAdmin webmaster@mydomain.com
    DocumentRoot /srv/www/vhost1
    ServerName vhost.mydomain.com
    ServerAlias www.mydomain.com
    ErrorLog logs/vhost.mydomain.com-error_log
    CustomLog logs/vhost.mydomain.com-access_log \ 
                        common

    # The PHP engine will interpret all 
    # .php and .html files for php code
    AddType application/x-httpd-php .php .phtml \ 
                         .html
    
    AddType application/x-httpd-php-source .phps

    # Add a local Directory directive to override 
    # the global Deny From all in conf/httpd.conf
    
      Options FollowSymLinks
      AllowOverride None
      Order deny,allow
      Allow from all
    

    # Restrict Access to sensitive files
    
      Deny from all
    

   
    
    # Configure MOD_JK
    JkWorkersFile \
             "/usr/local/apache/conf/workers.properties"
    JkLogFile \
               "/usr/local/apache2/logs/mod_jk_www.log"
    JkLogLevel info
    JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
    JkOptions +ForwardKeySize +ForwardURICompat \ 
                                    -ForwardDirectories
    JkRequestLogFormat "%w %V %T"
                
    # Any URL that begins with /java/ will be 
    # forwarded to the java webapp in tomcat
    JkMount /java/* ajp13

    # Enable and configure MOD_SECURITY
                
    # See the mod_security documentation 
    # link in resources [3]
                
        
    # POST Scanning is disabled by default
    SecFilterScanPOST On
                
    # Make sure only content with standard 
    # encoding types is accepted
    SecFilterSelective HTTP_Content-Type \
    
    "!(^$|^application/x-www-form-urlencoded$|^multipart/form-data;)"

    
    # Default Action is to reject request, log, and
    # then return HTTP Response 404 which is 
    # File Not Found. 
    # Another option would be 403 which is access
    # denied.
    SecFilterDefaultAction "deny,log,status:404"
                
    # Enable URLEncoding validation. This can 
    # prevent Cross-Site Scripting attacks 
    SecFilterCheckURLEncoding On

    # Catch and Prevent PHP Fatal Errors from 
    # being displayed to the USER
    SecFilterSelective OUTPUT "Fatal error:" \
                    deny,status:500
    
    # Obviously you have to code up this custom 
    # Error Page
    ErrorDocument 500 /php-fatal-error.html 
                
    # This can be useful to avoid stack overflow 
    # attacks default is 0 255 ie All bytes allowed
    SecFilterForceByteRange 32 126

    
Here is the mod_jk configuration file apache/conf/workers.properties (referenced above):
  worker.list=ajp13
  workers.tomcat_home= \
        /usr/local/java/apache-tomcat-5.5.12
  
  workers.java_home=/usr/local/java/jdk1.5.0_06
  worker.ajp13.type=ajp13
  worker.ajp13.host=localhost
  worker.ajp13.port=8009
Apache can be used to configure other web consoles such as the Tomcat Manager application
The configuration stanza below is a variation on an article:

  ServerAdmin webmaster@zero-analog.com
  DocumentRoot /srv/www/hercules.zero-analog.com
  ServerName hercules.zero-analog.com
  ErrorLog logs/hercules.zero-analog-error_log
  CustomLog logs/hercules.zero-analog-access_log \
                                             common

  
      Options FollowSymLinks
      AllowOverride None
      Order deny,allow
  

  
      Deny from all
  

  # This whole stanza is really to forward http 
  # requests to https:// tomcat manager
  # so appended /html to the rewrite target. 
  # since the full path is manager/html 

  
   
       
         RewriteEngine on
         RewriteCond %{HTTPS} !^on$ [NC]
         RewriteRule . \
          https://%{HTTP_HOST}%{REQUEST_URI}/html \
                                [L]
        
   
  



# This is the ssl-vhost under extra/httpd-ssl.conf 


  # General setup for the virtual host
  DocumentRoot "/srv/www/outpost.zero-analog.com"
  ServerName hercules.zero-analog.com:443
  ServerAdmin webmaster@zero-analog.com

  ErrorLog /usr/local/apache2/logs/error_log
  TransferLog /usr/local/apache2/logs/access_log

  
    Options FollowSymLinks
    AllowOverride None
    Order deny,allow
  
  


  RewriteEngine on
  RewriteRule "^/manager$" \
    "https://outpost.zero-analog.com/manager/html" \
                                               [R,L]


   JkWorkersFile \
       "/usr/local/apache2/conf/workers.properties"
   JkLogFile \
       "/usr/local/apache2/logs/mod_jk_hercules.log"
   JkLogLevel info
   JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
   JkOptions +ForwardKeySize +ForwardURICompat \
                             -ForwardDirectories
   JkRequestLogFormat "%w %V %T"
   JkMount /manager/* ajp13


   #   Enable/Disable SSL for this virtual host.
   SSLEngine on

         
   # List the ciphers that the client is permitted 
   # to negotiate. See the mod_ssl documentation
   # for a complete list.
   SSLCipherSuite  ALL:!ADH:!EXPORT56:RC4+RSA: \ 
         +HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL

   # Server Certificate: Point SSLCertificateFile
   # at a PEM encoded certificate.
    
   SSLCertificateFile \ 
                /usr/local/apache/conf/server.crt

   # Server Private Key:
   SSLCertificateKeyFile \ 
                /usr/local/apache/conf/server.key

   SSLOptions +FakeBasicAuth \
              +ExportCertData \
              +StrictRequire
   
   
           SSLOptions +StdEnvVars
   
   
   
           SSLOptions +StdEnvVars
   

   BrowserMatch ".*MSIE.*" \
           nokeepalive ssl-unclean-shutdown \
            downgrade-1.0 force-response-1.0
 

   # Per-Server Logging:
   # The home of a custom SSL log file. 
   # Use this when you want a compact non-error 
   # SSL logfile on a virtual host basis.
   
   # *** Note there are \ characters in this 
   # string. These are not my artificial line-
   # breaks, please include them ***
   
   CustomLog /usr/local/apache2/logs/ssl_request_log 
             %t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"


Configuring PHP

I have already copied the php.ini to /usr/local/php/php.ini so that it will be read by the PHPengine at startup. By default it’s fairly secure, but there are one or two things you can do to improve security.
Disable PHP display_errors for security
  # Edit /usr/local/php/php.ini with your 
  # favorite editor

  # Since you're are going through the trouble of 
  # hiding PHP files you might as well disable 
  # this as well
   expose_php = On -> expose_php = Off 
        
  # You really don't want users, or worse yet 
  # an attacker to see error messages
   display_errors = On -> \
      display_erros = Off 

  # But you do want them logged \
   log_errors = Off -> log_errors = On 
  
  # Log to a file
  ;error_log = filename -> \
       error_log = /var/log/php-err 
Another option to consider is the Hardened-PHP project (see resources section). This is the brain child of three German developers, who continously perform code audits of popular PHP applications. They also release a patch for the standard PHP code, which fixes bugs and security holes in fringe configuration cases, where the main project developers have not had the time or the desire to find a fix.

Configuring Tomcat

The main configuration files from Tomcat are under $CATALINA_HOME/conf. The following files are of interest:
  • tomcat-users.xml
  • server.xml
  • web.xml
As you might have guessed, the tomcat-users.xml file contains user access information. It is important to create a custom user with a hard-to-guess password for the manager application.
  # Edit tomcat-users.xml with your favorite 
  # editor and append the following line.

   
Another important tenet of security is preventing information leakage. That’s why you enable PHP pages to masquerade as html files. It’s also why you want to disable directory listings in Tomcat. This is achieved by editing the tomcat/conf/web.xml file.
  # Open web.xml in your favorite editor and 
  # look for the following lines:
  
  
    listings
    false
   

  # The default value is true, which enables 
  # directory listings, simply change this to false
  # to prevent tomcat directory listings.
You can also hide JSP files by using a servlet-mapping directive in the webapps web.xmlconfiguration file. The following lines will map all html files to the JSP servlet, which is internal to Tomcat.
Note: The listing above goes in the main tomcat/conf/web.xml, while this listing should go in theweb.xml of each application. You can put it in the main web.xml. However, there may be cases where this is undesirable.
  
    jsp
      *.html
  
I want to restrict access to apache-tomcat to control the flow through Apache. iptables is already blocking port 8080 by default, but following the onion principle I’m going to bound Tomcat to loop-back device. This will prevent direct traffic to Tomcat in case of any unforeseen circumstances such as theiptables rules being flushed.
 # Open sever.xml in your favorite editor 
 # and look for the following lines:
        
 
 

 # And change to this:

  
  

Configuring MySQL

The default MySQL installation is not very secure. This is the case when it is installed manually and also when you use your distribution’s precompiled binaries. The default root password is blank, which means anyone can login is as the DBA. This is understandable, as, obviously, a DBA has to login to set the password. However, it’s too easy to forget that anyone can login as the MySQL root user and anonymous users are also enabled by default.
# Set the root password
mysqladmin -u root -h localhost password subGen1us 
  
# Once this is done, log in as the root user and 
# disable anonymous accounts
mysql -u root -p
  
# Drop the test database which comes installed 
# by default
mysql> drop database test;
        
# Disable anonymous accounts
mysql> use mysql;
       
mysql> delete from db where User=’’;
mysql> delete from user where User=’’;
        
# Change DBA NAME
mysql> update user set user="mydbadmin" \ 
          where user="root";

mysql> flush privileges;

# Make sure to login again to make sure 
# all the changes work

mysql -u mydbadmin -p
password: subGen1us

# Configure /etc/my.cnf for security Uncomment 
# the following line to disable TCP connections 
# to mysql.  As with tomcat this prevents remote 
# connections event in the even of the firewall
# even in the even of the firewall rules being 
# flushed.
  
skip-networking
        

Security mistakes in web applications

Now that you are done with configuration, it’s time to put your web developer hat on. You now have a very solid base upon which to build your web applications. This brings me to the Achilles heal: the web applications themselves.

What is Cross Site Scripting (XSS)?

Wikipedia [4] defines the term Cross Site Scripting as inaccurate as it really refers to an entire class of vulnerabilities. In general XSS vulnerabilities come down to an age old security problem: not verifying user input. The most common vector of attack is when data is passed to a processing program such as a PHP or JSP script, and then printed back out to the page without being URLEncoded.
The following (highly contrived) PHP code is vulnerable to XSS. If the database to this PHP script contains javascript, it will be executed.
Never trust user input, it is the root of all evil
        # Vulnerable Code
        
        
        # Secure Code
        
JSP’s or Java Servlets are no less vulnerable. First of all, it is important to understand that all JSP’s are compiled to servlets the first time a JSP is called. So, the two are basically the same thing, with different source code representations.
Here is the same vulnerability in the Java world. Note: JSP’s have access to the sameHttpServletRequest object as the servlets they are compiled to. So, in a JSP page, this would manifest itself as request.getParameter().
        
  # Vulnerable Code
  public class myServlet extends HttpServlet {
    public static void doGet 
              (HttpServletRequest req, 
               HttpServletResponse res) {
                        
     // Get User Input       
     String userInput = req.getParameter("input");

     // Print User Input to page
     PrintWriter out = response.getWriter();
     out.write("");
     out.write(userInput);
     out.write("");
                        
   }
  }

  # Secure Code
  import java.net.URLEncoder;
  public class myServlet extends HttpServlet {
    public static void doGet 
              (HttpServletRequest req, 
               HttpServletResponse res) {
                        
       // Get User Input       
       String userInput = req.getParameter("input");
       // URLEncode Input
       userInput = 
            URLEncoder.encode(userInput, "UTF-8"); 

       // Print User Input to page
       PrintWriter out = response.getWriter();
       out.write("");
       out.write(userInput);
       out.write("");
                        
   }
  }

What is SQL Injection?

SQL Injection is the ability to insert and execute arbitrary SQL code through a web-application. Like XSS attacks, it involves mishandling user input. In this case, properly escaping the input that is to become part of the SQL query. The PHP solution is to use the mysql_real_escape_string statement, and the java solution is to use PreparedStatements, with the user input as bind variables.
The following code snippets are from Wikipedia [5]:
  # Partial PHP
  $query_result = mysql_query
   ( "select * from users where name = \""
       .
      mysql_real_escape_string($user_name)
       .
      "\"" );

  # Partial Java, ? is the bind variable
  Connection con = (acquire Connection)
  
  PreparedStatement pstmt = 
    con.prepareStatement
       ("SELECT * FROM users WHERE name = ?");
  
  pstmt.setString(1, userInput);
  ResultSet rset = pstmt.executeQuery()
        

Conclusion

There is no magic bullet. “Conclusion” is a misleading heading: there is no conclusion when it comes to security. Security holes are constantly found and patched. Attackers change their methods, and security professionals respond; it is a process, rather than a result. When it's implemented correctly, this process can mitigate or prevent the damage done by attacks.
There is a silver lining: there is an entire community of security professionals sharing their experience, tips and tricks on the web. Sites like Securityfocus.com provide heaps of useful information, and the latest trends in security. It’s also the home of bugtraq, a mailing list of security holes that I highly recommend you subscribe to. Sites like freshmeat.net are the yellow pages of free software projects, listing new releases and updates. All of these sites have RSS feeds, a resource I would also recommend you take advantage of to stay abreast of the latest news.
Resources:

No hay comentarios: