pre { background:#eeeeee; border:1px solid #A6B0BF; font-size:120%; line-height:100%; overflow:auto; padding:10px; color:#000000 } pre:hover { border:1px solid #efefef; } code { font-size:120%; text-align:left; margin:0;padding:0; color: #000000;} .clear { clear:both; overflow:hidden; }

Bienvenido al blog

Bienvenidos al blog de seguridad en sistemas

martes, 17 de abril de 2012

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. 

PD: entrada publicada para el blog de securityartwork.
PD2: veo que se sale el texto de algunas casillas, siento las molestias :(


Continuar...

jueves, 12 de abril de 2012

Bastionado de Apache Tomcat (I)

A raíz de la entrada de Guillermo Mir sobre el bastionado de Apache (parte I y parte II) y una entrada en el blog SecurityByDefault sobre cómo trabajar con SSL en Tomcat me he decidido a escribir una entrada sobre el bastionado de Tomcat que debía desde hace mucho tiempo a Manolo, quien no se olvidaba de recordármelo.

En primer lugar indicar que la entrada se centrará en un correcto bastionado de Tomcat sobre un entorno Linux, puesto que sinceramente Tomcat en Windows no ofrece las mismas opciones, por muy Java que sea, que en un entorno Linux. Como documentar una guía de bastionado de Tomcat ocuparía muchas páginas, esta y la siguiente entrada tratará los principales puntos a tener en cuenta durante un bastionado adecuado. Para más información os remito a la documentación de Tomcat.

Durante la instalación se deben tener en cuenta los siguientes puntos:
  • En primer lugar se debe emplear un usuario administrador de tomcat al que llamaremos “tomcatadm” y un grupo tomcat al que llamaremos “tomcat”. Los ficheros de configuración tendrán permisos de lectura para el grupo “tomcat” y permisos de lectura más escritura para el usuario “tomcatadm”.
  • A su vez se debe diferenciar entre el Home y el Base de Catalina. El base CATALINA_HOME debe tener únicamente el motor de Tomcat mientras que CATALINA_BASE debe tener la parte dinámica constituida por: webapps, logs, temporales y ficheros de configuración, de forma que para actualizar el motor solo sea necesario cambiar el enlace dinámico donde apunta CATALINA_HOME.
  • La ejecución del servicio Tomcat se debe realizar a través del demonio programado en C JSVC, el cual permite que Tomcat escuche en puertos inferiores al 1024 para posteriormente cambiar a rol de usuario sin privilegios, sin ser necesario el uso de redirecciones a nivel de red o proxys frontales.
Durante el bastionado inicial se deben tener en cuenta los siguientes puntos:
  • Solo habilitar los conectores estrictamente necesarios. Si vamos a usar Tomcat en alta disponibilidad mediante clusters o vamos a usar un proxy frontal se deberá usar el conector AJP. Si se va a emplear un único Tomcat donde los usuarios se conecten directamente desde su navegador Web a Tomcat se deberá emplear un conector HTTP/HTTPS. Lo que no tiene sentido en un entorno de producción es que se empleé los dos conectores a la vez.
  • Ajustar las variables proporcionadas por Tomcat para dada una infraestructura y unos recursos, evitar dentro de los límites posibles, una denegaciones de servicio de los recursos del servidor. Recomendando los siguientes valores para cada conector configurado en el fichero server.xml:
    maxPostSize=”2097152”
    maxSavePostSize=”4096”
    maxHttpHeaderSize="8192"
    maxParameterCount="15"
    keepAliveTimeout="300000"
    maxThreads="150"
    maxPostSize="2097152"
    maxSavePostSize="4096"
    compression="on"
    compressableMimeType="text/html,text/xml,text/plain,application/xml"
  • Se deben ocultar las cabeceras HTTP server y xpoweredBy que proporciona por defecto el servidor como respuesta ante una solicitud. Para ello es necesario añadir las siguientes dos variables al fichero “server.xml”:
    server="Nombre Inventado"
    xpoweredBy="false"
  • Importante, muy importante, realizar el tratamiento adecuado de las excepciones. Si un desarrollador no trata correctamente las excepciones de su aplicación, nuestro servidor Tomcat no debe permitir que estas se visualicen en el cliente Web. Para tratar las excepciones hay que añadir al final del fichero web.xml, antes de cerrar el tag web-app la siguiente entrada:
    <web-app ... >
    ...
       <error-page>
           <exception-type>java.lang.Throwable</exception-type>
           <location>/error.html</location>
       </error-page>
    </web-app>
    Donde será necesario crear un fichero error.html en el directorio base de cada aplicación, de forma que, ante una excepción de Tomcat se mostrará dicha página en lugar de la traza de la excepción.

    De la misma forma que se tratan las excepciones, se puede gestionar los códigos de error HTTP, tanto del servidor (5XX) como del cliente (4XX). Para ello será necesario añadir al final del fichero web.xml, antes de cerrar el tag web-app, una entrada por cada error a gestionar, donde XXX es el código de error de respuesta (401, 403, 404, 414, 500, etc):
    <web-app ... >
    ...
        <error-page>
            <error-code>XXX</error-code>
            <location>/error.html</location>
        </error-page>
    </web-app>
    De esta forma cuando se origine un error de tipo “XXX” se redireccionará a la página error.html indicada y no a la de por defecto de Tomcat que muestra, entre otras cosas, la información de la versión. Si se quiere evitar que se muestre el mensaje por defecto de error para cualquier código de error es necesario modificar el código de Tomcat: desempaquetar, modificar un par de líneas y empaquetar, pero esto ya queda fuera del contexto de esta entrada.
  • Se debe desactivar el puerto de apagado del servicio. Esto es algo curioso y no acabo de entender el motivo por el cual este activado por defecto en distribuciones como Debian, donde se habilita el conector Shutdown en el puerto 8005 con contraseña por defecto SHUTDOWN, de forma que un usuario local del sistema puede detener el servicio Tomcat:
    $ netstat -putan | grep LISTEN | grep java
    tcp6     0    0 127.0.0.1:8005      :::*        LISTEN      7437/java
    tcp6     0    0 :::8080             :::*        LISTEN      7437/java
    $ telnet localhost 8005
    Trying 127.0.0.1...
    Connected to localhost.
    Escape character is '^]'.
    SHUTDOWN
    Connection closed by foreign host.
    $ netstat -putan | grep LISTEN | grep java
    $
    Por ello se debe desactivar el conector en el fichero server.xml indicando que el puerto es “-1” y adicionalmente cambiando la contraseña:
    <Server port="-1" shutdown="QUiENnnQu1er3J4v4Cuand0TIENeCee">
    Por defecto se debe restringir el despliegue de aplicaciones de forma automatizada. Para ello se debe configurar adecuadamente el fichero server.xml impidiendo que se desplieguen aplicaciones automáticamente cuando se deposita la aplicación en el directorio de aplicaciones (webapps), indicándolo con el tag autoDeploy="false". A su vez se debe impedir que las aplicaciones depositadas en el directorio de aplicaciones (webapps) se desplieguen al reiniciar el servicio mediante el tag deployOnStartup="false”.

    Si ya se quiere ser muy tiquismiquis se puede indicar que solo las aplicaciones documentadas en el fichero server.xml se puedan desplegar. Para ello se debe definir la variable deployXML=”false” y emplear los tag Context path que identificaran las aplicaciones que se desean desplegar, tal y como se muestra a continuación:
    <Server ...>
     <Service name="Catalina">
        <Engine name="Catalina" ...>
          <Host ... autoDeploy="false" deployOnStartup="false" deployXML="false"
              ...
               <Context path="/aplicacion"/>
              ...
          </Host>
        </Engine>
      </Service>
    </Server>
  • Desactivar el método HTTP Trace añadiendo el siguiente tag al fichero server.xml:
    allowTrace=”false”
Con estas recomendaciones damos por finalizada la primera entrada de bastionado en Apache Tomcat. En la siguiente entrada trataremos el uso de Security Manager y la correcta configuración del protocolo SSL sobre un Apache Tomcat. Esperamos que os resulte útil.

PD: entrada publicada para SecurityArtWork.

Continuar...