Аутентификация имени пользователя, пароля с использованием фильтров в Java (связь с базой данных)
Ниже приведен фрагмент кода Java с использованием фильтров, каждый раз показывающий страницу с ошибкой, если имя пользователя и пароль также верны. Пожалуйста, помогите мне, у меня мало знаний об этой концепции.
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);
Ответы
Ответ 1
Строка sql = "select * from reg, где username = '" + user + "' и pass = '" + pwd + "'";
Это очень плохая практика. Этот подход требует, чтобы как имя пользователя, так и пароль передавались по простой ванили через запросы. Более того, у вас есть отверстие для инъекций SQL.
Используйте сеансы, в JSP/Servlet там есть HttpSession
для. Также действительно не нужно ударять БД снова и снова по каждому запросу с помощью Filter
. Это неоправданно дорого. Просто поставьте User
в сеансе, используя Servlet
, и используйте Filter
, чтобы проверить его присутствие при каждом запросе.
Начните с /login.jsp
:
<form action="login" method="post">
<input type="text" name="username">
<input type="password" name="password">
<input type="submit"> ${error}
</form>
Затем создайте LoginServlet
, который отображается на url-pattern
в /login
и имеет doPost()
реализован следующим образом:
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.
}
Затем создайте LoginFilter
, который отображается на url-pattern
в /secured/*
(вы можете выбрать свой собственный, например, /protected/*
, /restricted/*
, /users/*
и т.д., но это должно быть как минимум все защищенные страницы, вам также нужно поместить JSP в соответствующую папку в WebContent) и имеет doFilter()
реализован следующим образом:
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.
}
Это должно быть так. Надеюсь это поможет.
Чтобы понять, как выглядит UserDAO
, вы можете найти эту статью. В нем также описывается, как использовать PreparedStatement
, чтобы сохранить ваш webapp от атак SQL-инъекций.
См. также:
Ответ 2
Используйте подготовленный оператор, ваш код является открытым приглашением для SQL injection.
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();
}
Теперь для вашего вопроса, пожалуйста, проверьте:
- что имена таблиц и столбцов являются правильными (у вас нет столбца "login" и "имя пользователя"?)
- что значения действительно правильны (например, попробуйте запрос в sqldevelopper)
- что он работает с паролем ascii-7 и именем пользователя (это может быть проблема с кодировкой)
- что столбец пароля содержит реальный пароль, а не хэш его
Ответ 3
Так много чего не так с этим...: -/
- Большая - SQL Injection. Не записывайте другую строку SQL в свой код, пока вы его не поймете. И это не преувеличение для эффекта; код, написанный без понимания этого, может привести к произвольному доступу злоумышленника к вашей базе данных.
- Вы не должны иметь возможность выдавать такой запрос, потому что вы никогда не должны хранить пароли в виде открытого текста. Вместо этого вы должны рассчитать и сохранить какой-то (предпочтительно соленый) хэш пароля, а затем передать хэш-пароль и сравнить его. См., Например, Как лучше всего хранить логин и пароль пользователя и Солить свой пароль здесь, на SO. Это особенно плохо с учетом вашей уязвимости в SQL-инъекции.
-
select * from reg
не требуется, поскольку вы просто хотите знать, существует ли строка. Если вы использовали select 1
, вместо этого база данных не должна была бы проверять содержимое строки и могла бы служить результатом запроса только из индекса. Если бы вы ожидали, что будет много строк, select 1 where exists ...
будет быстрее, так как это позволит БД коротко запрограммировать запрос после нахождения хотя бы одной строки.
- Вы не закрываете оператор и результат в блоках
finally
. Это означает, что они не гарантируются, что они всегда будут удалены (например, если вы выбрали SQLException
), что приведет к утечке ресурсов и соединений.
Ответ 4
Прежде всего, вам действительно нужно использовать параметризованные запросы для этого. Если пользователь вводит '";DROP TABLE reg;
в качестве имени пользователя, у вас будут большие проблемы.
Кроме того, вы уверены, что имя пользователя и пароль верны? Как насчет капитализации?