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 (N.d.E. como es mi obligación…).

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.

Comments

  1. Gracias por comentar el post. Es justo decir que los post de bastionado de apache los estamos realizando José Luis Chica y yo. Que conste en acta.

  2. El caso es bastionar cosas ;D
    Muy chulo el post

  3. Gracias por el artículo, ha sido muy intenresante tener otros puntos de vista sobre la puesta el «bastionado» de este tipo de sistemas.

  4. Interesante documento. Gracias por compartirlo.

  5. Muy buen articulo, pero tengo una duda el tag allowTrace=”false” con exactitud donde se debe agregar, gracias