Joven hacker sonriendo

Hackeamos su software

cero falsos positivos

Atacando Aplicaciones, APIs, Apps Móviles, Servidores Redes, Dispositivos IoT
SCI: Sistemas de Control Industrial
COS: Centro de Operaciones de Seguridad

Controlar el Acceso para Servlets

Nuestros ethical hackers explican cómo evitar vulnerabilidades de seguridad mediante la programación segura en Java al establecer el control de acceso para servlets de forma declarativa con anotaciones. Ésto resulta útil cuando se requiere un diseño personalizado para la pantalla de autenticación.

Necesidad

Establecer control de acceso para Servlets usando una forma declarativa con anotaciones en Java.

Contexto

A continuación se describen las circunstancias bajo las cuales la siguiente solución tiene sentido:

  1. Se está desarrollando una aplicación web en Java.

  2. Se dispone de un servidor de aplicaciones o contenedor de Servlets conforme con las especificaciones empresariales de Java que soporte la especificación 3.0 o superior.

  3. Se conoce como configurar roles de seguridad en el descriptor de despliegue web.xml.

  4. Se han configurado los roles de seguridad necesarios por la aplicación en el servidor de aplicaciones.

  5. Se desea emplear un mecanismo conveniente para la tecnología de Servlets.

  6. Se requiere un diseño personalizado para la pantalla de autenticación.

  7. Se conoce cómo trabajar con servlets.

Solución

  1. Inicialmente se configuran los usuarios que tendrán acceso a la aplicación. Este paso dependerá del contenedor de servlets que se esté usando y de la fuente de donde se extraigan los datos.

  2. A continuación se muestra la estructura de carpetas que debe contener la aplicación.

    estructura.bash
    1
    2
    3
    4
    5
    6
    7
    % ls -R *
    .:
    cerrar.jsp index.jsp login-failed.jsp login.jsp WEB-INF/ src/
    src/test:
    TestServlet.java
    WEB-INF:
    web.xml
    
  3. Se crea el archivo cerrar.jsp, página encargada de invalidar la sesión. Para esto llama el método invalidate del objeto de sesión session.

  4. La acción solo se lleva a cabo cuando se pasa como parámetro en la petición el valor invalidate en el parámetro action.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <html>
      <head>
        <title>Cierre de sesi&aocute;n</title>
      </head>
      <body>
       <%
         String action = request.getParameter("action");
         if("invalidate".equals(action)) {
           session.invalidate();
    
  5. Luego se obtiene una nueva sesión y se redirecciona a index.jsp

    1
    2
    3
    4
    5
    6
       request.getSession(true);
       response.sendRedirect("index.jsp");
       }
      %>
     </body>
    </html>
    
  6. Se crea el archivo index.jsp, el cual contendrá la página cuyo acceso debe ser restringido.

  7. Únicamente posee un link que hace una petición a cerrar.jsp con los parámetros para cerrar la sesión.

    1
    2
    3
    Esta página puede ser vista solo por usuarios autorizados.
    <br />
    <a href="cerrar.jsp?action=invalidate">Cerrar sesion</a>
    
  8. Se crea la página que contendrá el formulario de autenticación login.jsp.

    1
    2
    3
    4
    5
    <html>
      <head>
        <title>Login</title>
      </head>
      <body>
    
  9. En el formulario, la acción que corresponde a j_security_check no necesita ser programada, sino que el servidor responderá ante esta según se configure el descriptor de despliegue web.xml como se verá más adelante.

  10. Se usa el método response.encodeURL para que en caso de que las cookies estén deshabilitadas, se mantenga el ID de la sesión como parte de la URL.

    1
    <form method="POST" action='<%= response.encodeURL("j_security_check") %>' >
    
  11. El contenido del formulario incluye los campos j_username y j_password que son los interpretados por el servidor para determinar el acceso.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
       <table border="0" cellspacing="5">
         <tr><th align="right">Usuario:</th>
           <td align="left"><input type="text" name="j_username"></td>
         </tr>
         <tr><th align="right">Contrase&ntilde;a:</th>
           <td align="left"><input type="password" name="j_password"></td>
         </tr>
         <tr><td align="right"><input type="submit" value="Ingresar"></td>
           <td align="left"><input type="reset" value="Limpiar"></td>
         </tr>
        </table>
      </form>
     </body>
    </html>
    
  12. Se crea el archivo login-failed.jsp que será el mostrado cuando se haga un intento de autenticación erróneo. Esta página simplemente tiene un link de redirección hacia index.jsp.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    <html>
      <head>
        <title>P&aacute;gina de error</title>
      </head>
      <body>
        Nombre de usuario o contrase&ntilde;a no v&aacute;lido.
        <br />
        <a href='<%= response.encodeURL("login.jsp") %>'>Volver</a>
      </body>
    </html>
    
  13. Se debe especificar cuales son las páginas que componen el mecanismo de autenticación en el descriptor de despliegue WEBINF\web.xml

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    <?xml version="1.0" encoding="UTF-8"?>
      <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://java.sun.com/xml/ns/j2ee"
        xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
        http://java.sun.com/xml/ns/j2ee/web-app_3_0.xsd"
        id="tomcat-demo"
        version="3.0">
        <login-config>
          <auth-method>FORM</auth-method>
          <form-login-config>
            <form-login-page>/login.jsp</form-login-page>
            <form-error-page>/login-failed.jsp</form-error-page>
          </form-login-config>
        </login-config>
      </web-app>
    
  14. En <login-config> se especifica cual será la página de login a la que se redirigirá cuando no se cuente con los privilegios para acceder a un recurso así como la página de error a la que se redirigirá cuando se intente una autenticación errónea.

  15. Se crea el servlet TestServlet.java, configurando mediante anotaciones cuales serán los roles permitidos.

  16. Primero, se especifica que pertenece al paquete test y se importan las clases necesarias para trabajar con servlets HTTP.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    package test;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.HttpConstraint;
    import javax.servlet.annotation.ServletSecurity;
    import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
  17. Se especifica que el servlet se llamará TestServlet y que la URL que mapea a este será /TestServlet.

    1
    @WebServlet(name = "TestServlet", urlPatterns = {"/TestServlet"})
    
  18. La anotación @HttpConstraint al interior de la anotación @ServletSecurity especifica los roles que serán permitidos para acceder a este servlet.

  19. Se especifica NONE en el mecanismo de transporte porque no se harán configuraciones de seguridad adicionales tales como SSL. Se usa rolesAllowed para indicar que se permitirá el acceso a los roles rol1 y tomcat.

    1
    2
    3
    @ServletSecurity(
      @HttpConstraint(transportGuarantee = TransportGuarantee.NONE,
        rolesAllowed = {"rol1", "tomcat"}))
    
  20. Se termina de crear un servlet típico que solo muestra la palabra prueba como salida:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    public class TestServlet extends HttpServlet {
      public TestServlet() {
        super();
      }
      protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
          PrintWriter out = response.getWriter();
          out.println("Prueba");
        }
    }
    
  21. Opcionalmente, se podría usar la anotación @HttpMethodConstraint dentro de la anotación @ServletSecurity para especificar que métodos HTTP serían permitidos.




Haz un comentario

Estado de los servicios - Términos de Uso