Bastionado de Apache Tomcat (II)

Tras la primera parte que vimos el otro día, en esta entrada vamos a ver el uso de Security Manager y la correcta configuración del protocolo SSL sobre un Apache Tomcat.

Respecto al primero, vamos a configurar Security Manager para que restrinja el uso de ciertos métodos y clases que puedan implicar un riesgo para el servidor de aplicaciones. Estas restricciones se definen en el fichero catalina.policy. Para activar Security Manager será necesario añadir las siguientes dos entradas en el arranque de Tomcat:

-Djava.security.manager 
-Djava.security.policy=$CATALINA_BASE/conf/catalina.policy  

Nota: si se usa el script por defecto de arranque en vez de JSVC se debe añadir el tag -security, que realmente hace lo mismo: añadir las dos entradas anteriores.

Un ejemplo práctico de Security Manager sería una aplicación con un fallo de seguridad donde un posible atacante ha conseguido subir una Web Shell para intentar ejecutar órdenes en el servidor mediante el método Runtime.getRuntime().exec(). Al intentar ejecutar dicho método Security Manager impedirá su ejecución devolviendo la siguiente excepción:

java.security.AccessControlException: access denied

Donde sí se ha tratado adecuadamente la excepción, tal como se documento en la anterior entrada, únicamente se mostrara la página error.html cuando se intente ejecutar órdenes en el servidor mediante la Web Shell del atacante. Otro punto importante a tener en cuenta es la correcta configuración del registro de sucesos. Para ello se recomienda seguir los siguientes consejos:

  • Aplicar una configuración adecuada para registrar la mayor información posible de los clientes que han realizado una solicitud a una aplicación del servidor Tomcat, añadiendo para ello la siguiente válvula al campo Host del fichero server.xml:
    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
      prefix="localhost_access." suffix=".log"
      resolveHosts="false"
      pattern="%t %h %H %m %s "%r" cookie:%{SESSIONID}c User- Agent:%{User-Agent}i " />
    
  • Crear registros específicos para cada aplicación. Para realizar esta tarea es necesario especificar un fichero de logging.properties por cada aplicación desplegada en el directorio .../aplicacion/WEB-INF/clases/ donde aplicacion es el directorio de la aplicación. Dicho fichero tendrá la siguiente configuración:
    handlers = org.apache.juli.FileHandler, java.util.logging.ConsoleHandler
    org.apache.juli.FileHandler.level = FINEST
    org.apache.juli.FileHandler.directory = ${catalina.base}/logs
    org.apache.juli.FileHandler.prefix = aplicacion.
    org.apache.juli.FileHandler.suffix = .log
    org.apache.juli.FileHandler.rotatable = true
    java.util.logging.ConsoleHandler.level = FINEST
    java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
    
  • Emplear LOG4J para aquellas aplicaciones donde las librerías de registros por defectos de Tomcat no cumplan todos nuestros requisitos.

Para finalizar trataremos de configurar adecuadamente los conectores que empleen protocolos cifrados (conectores SSL) definidos en nuestro servidor de aplicaciones Tomcat siguiendo para ello los siguientes puntos:

  • Forzar a los conectores que no cifran las comunicaciones a usar SSL mediante los siguientes pasos, llamado también redirección a conector SSL:

    1. En los conectores definidos en el fichero server.xml que no se empleen protocolo SSL se debe aplicar una redireccionan hacia un conector que emplee el puerto SSL:

    <Connector port="80" protocol="HTTP/1.1"
                    redirectPort="443"
    ...
    />
    <Connector port="443" protocol="HTTP/1.1"
                    scheme="https"
    ...
    />
    
  • 2. Indicar que los métodos GET, POST y HEAD sean confidenciales añadiendo la siguiente entrada al fichero web.xml:

    <web-app xmlns="http://java.sun.com/xml/ns/javaee" …>
    ...
        <security-constraint>
                <web-resource-collection>
                        <web-resource-name>Servidor Aplicaciones</web-resource-name>
                        <url-pattern>/*</url-pattern>
                        <http-method>GET</http-method>
                        <http-method>POST</http-method>
                        <http-method>HEAD</http-method>
               </web-resource-collection>
                <user-data-constraint>
                        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
                </user-data-constraint>
        </security-constraint>
    </web-app>
    
  • Impedir el uso de algoritmos y protocolos débiles. Para ello en la configuración de los conectores cifrados, definidos en el fichero server.xml, se deberá indicar que se desea usar TLS mediante la variable sslProtocol="TLS". Hay que tener en cuenta que el valor “TLS” en las últimas versiones de Tomcat identifica a la versión 1.1, y por tanto, acepta tanto TLS como SSL v3 pero no SSL versión 2, tal y como se especifica en la documentación del protocolo TLS v1.1.

    Será necesario definir que ciphers suite de los soportados por Java (ver enlace) se deben emplear. Estos presentan la siguiente forma:

    Proto_AlgClaveAsimetrica_WITH_AlgClaveSimetrica_tamClaveSim_AlgCompendio
    
  • Para esta restricción se pueden aplicar listas negras: aceptamos todos los algoritmos menos unos cuantos, como se recomienda en la entrada de SecurityByDefault, o se pueden aplicar listas blancas: solo permito los estrictamente indicados. Para gustos colores, pero en mi opinión prefiero aplicar listas blancas, es decir, indicar solo los que puedo usar.

    En mi opinión, sin ser ni mucho menos un experto en algoritmos de cifrado, recomendaría usar TLS, algoritmos de curva elíptica o RSA como clave asimétrica, AES de 128 bits mínimo para clave simétrica y SHA como algoritmo de compendio:

    TLS_RSA_WITH_AES_128_CBC_SHA
    TLS_RSA_WITH_AES_256_CBC_SHA
    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
    TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
    TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
    TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
    TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
    

    Por ello se definirán los cipher suite indicados con anterioridad en cada conector SSL creado en el fichero server.xml mediante la variable ciphers separados por comas:

    <Connector port="443" protocol="HTTP/1.1"
    scheme="https"
    ...
    ciphers="TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,
    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
    TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
    TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA"
    ...
     />
    

    Hay que tener en cuenta que para que pueda emplear algoritmos de curvas elípticas y algoritmos simétricos de más de 128 bits será necesario sustituir las librerías por defecto del Java JDK local_policy.jar y US_export_policy.jar por las suministradas en el paquete Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files. Esto es debido a que por defecto el JDK está restringido a las leyes de EEUU donde no se permite más de 128 bits ni algoritmos de curva elíptica. Una vez sustituidas las librerías y reiniciado Tomcat ya se permitirá emplear dichos algoritmos, tal como se muestra a continuación:

    $ openssl s_client -host localhost -port  443 -tls1 -cipher AES256-SHA
    …
    New, TLSv1/SSLv3, Cipher is AES256-SHA
    Server public key is 1024 bit
    Secure Renegotiation IS supported
    Compression: NONE
    Expansion: NONE
    SSL-Session:
        Protocol  : TLSv1
        Cipher    : AES256-SHA
    ...
    

Con este par de pasos ya se dispondrá de un servidor Tomcat con una configuración de seguridad más o menos correcta ya que se han omitido una serie de configuraciones adicionales que se deberían aplicar para mejorar la seguridad del entorno, aspecto que queda fuera del contexto de esta entrada.