Autenticando el nombre de usuario, contraseña usando filtros en Java (contactando con la base de datos)

La siguiente es la parte del código de Java utilizando filtros que muestran la página de error en todo momento si el nombre de usuario y la contraseña también son correctos. Por favor, ayúdenme, no tengo mucho conocimiento sobre este concepto.

String sql="select * from reg where username='"+user+"' and pass='"+pwd+"'"; rs=st.executeQuery(sql); if(rs.next()) { chain.doFilter(request,response); } else sc.getRequestDispatcher("/error.html").forward(request,response); 

String sql = “select * from reg where username = ‘” + user + “‘ y pass = ‘” + pwd + “‘”;

Esta es una práctica extremadamente mala. Este enfoque requiere que tanto el nombre de usuario como la contraseña se transmitan a través de las solicitudes simples. Además, tienes un agujero de ataque de inyección SQL.

Haga uso de las sesiones, en JSP / Servlet para el que tiene HttpSession . En realidad, tampoco es necesario pulsar DB una y otra vez en cada solicitud utilizando un Filter . Eso es innecesariamente caro. Simplemente ponga al User en sesión usando un Servlet y use el Filter para verificar su presencia en cada solicitud.

Comience con un /login.jsp :

 
${error}

Luego, cree un LoginServlet que esté mapeado en url-pattern of /login y tenga doPost() implementado de la siguiente manera:

 String username = request.getParameter("username"); String password = request.getParameter("password"); User user = userDAO.find(username, password); if (user != null) { request.getSession().setAttribute("user", user); // Put user in session. response.sendRedirect("/secured/home.jsp"); // Go to some start page. } else { request.setAttribute("error", "Unknown login, try again"); // Set error msg for ${error} request.getRequestDispatcher("/login.jsp").forward(request, response); // Go back to login page. } 

Luego, crea un LoginFilter que está mapeado en url-pattern de /secured/* (puedes elegir el tuyo propio, por ejemplo /protected/* , /restricted/* , /users/* , etc., pero al menos debe cubrir todos páginas seguras, también debe colocar las JSP en la carpeta apropiada en WebContent) y tiene doFilter() implementado de la siguiente manera:

 HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; HttpSession session = request.getSession(false); String loginURI = request.getContextPath() + "/login.jsp"; boolean loggedIn = session != null && session.getAttribute("user") != null; boolean loginRequest = request.getRequestURI().equals(loginURI); if (loggedIn || loginRequest) { chain.doFilter(request, response); // User is logged in, just continue request. } else { response.sendRedirect(loginURI); // Not logged in, show login page. } 

Eso debería ser. Espero que esto ayude.

Para tener una idea de cómo se UserDAO un UserDAO , puede encontrar este artículo útil. También cubre cómo usar PreparedStatement para guardar su aplicación web de ataques de inyección SQL.

Ver también:

  • ¿Cómo redirigir a la página de inicio de sesión cuando expira la sesión en la aplicación web Java?
  • Filtro de autenticación y servlet para iniciar sesión
  • ¿Cómo manejar la autenticación / autorización con usuarios en una base de datos?

Use una statement preparada, su código es una invitación abierta para una inyección SQL .

 Connection con = getMyConnection(); try { //no string concatenation, we use ? instead: PreparedStatement ps = con.prepareStatement("select * from reg where username=? and pass=?"); try { //actual value for parameters are set here: ps.setString(1, user); ps.setString(2, pwd); ResultSet rs = ps.executeQuery(); if(rs.next()) { chain.doFilter(request,response); } else { sc.getRequestDispatcher("/error.html").forward(request,response); } } finally { ps.close(); } } finally { con.close(); } 

Ahora para su pregunta, por favor verifique:

  • que los nombres de tabla y columna son los correctos (¿no tienes una columna de “inicio de sesión” y una columna de “nombre de usuario”?)
  • que los valores son realmente correctos (prueba la consulta en sqldevelopper, por ejemplo)
  • que funciona con una contraseña y un nombre de usuario de ascii-7 (podría ser un problema de encoding)
  • que la columna de contraseña contiene la contraseña real y no un hash de ella

Tantas cosas mal con esto …: – /

  1. El más grande: Inyección SQL . No escriba otra línea de SQL en su código hasta que lo comprenda. Y eso no es una exageración para el efecto; El código escrito sin entender esto probablemente le otorgue a un atacante acceso arbitrario a su base de datos.
  2. No debería poder emitir una consulta como esta porque nunca debe almacenar contraseñas en texto sin formato. En su lugar, debe calcular y almacenar algún tipo de hash (preferiblemente salado) de la contraseña, y luego hash la contraseña enviada y compararla. Consulte, por ejemplo, Cómo almacenar mejor el inicio de sesión y la contraseña del usuario y Saltear su contraseña aquí en SO. Esto es especialmente malo dada su vulnerabilidad de inyección SQL.
  3. select * from reg es innecesario dado que solo quiere saber si existe una fila. Si utilizó select 1 en su lugar, la base de datos no tendría que inspeccionar el contenido de la fila y podría servir los resultados de la consulta solo del índice. Si esperaba que hubiera muchas filas, select 1 where exists ... sería más rápido ya que esto le permitiría al DB cortocircuitar la consulta después de encontrar al menos una fila.
  4. No estás cerrando la statement y el conjunto de resultados en los bloques finally . Esto significa que no está garantizado que siempre se desechen (por ejemplo, si hay una SQLException arrojada) que conduce a pérdidas de recursos y conexiones.

Antes que nada, debería usar consultas parametrizadas para esto. Si el usuario ingresa '";DROP TABLE reg; como nombre de usuario estará en un gran problema.

Además, ¿estás seguro de que el nombre de usuario y la contraseña son correctos? ¿Qué hay de capitalización?