使用Java中的过滤器验证用户名,密码(与数据库联系)

时间:2009-12-22 10:05:28

标签: jsp authentication servlets login servlet-filters

以下是使用过滤器的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);

4 个答案:

答案 0 :(得分:30)

  

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

这是一种非常糟糕的做法。这种方法要求用户名和密码都通过请求传递普通香草。而且,你有一个SQL注入攻击漏洞。

利用会话,在JSP / Servlet中你有HttpSession。实际上也没有必要在使用Filter的每个请求上反复点击数据库。这是不必要的昂贵。只需使用UserServlet置于会话中,然后使用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的{​​{1}},并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/*,{{ 1}}等等,但这必须至少涵盖所有安全页面,你还需要将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的外观,您可能会发现this article很有用。它还介绍了如何使用PreparedStatement保存您的Web应用程序免受SQL注入攻击。

另见:

答案 1 :(得分:3)

使用预先准备好的声明,您的代码是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();
        }

现在提出您的问题,请检查:

  • 表名和列名是正确的(你没有'登录'和'用户名'列吗?)
  • 值非常正确(例如在sqldevelopper中尝试查询)
  • 它使用ascii-7密码和用户名(可能是编码问题)
  • 密码列包含真实密码而不是哈希值

答案 2 :(得分:2)

这么多错了......: - /

  1. 最重要的一个 - SQL Injection。在理解之前,不要在代码中编写另一行SQL。这并不夸张效果;在不了解这一点的情况下编写的代码可能会让攻击者任意访问您的数据库。
  2. 您不应该发出这样的查询,因为您绝不应该以明文形式存储密码。相反,您应该计算并存储密码的某种(最好是盐渍的)哈希值,然后对提交的密码进行哈希处理并进行比较。例如,请参阅此处的How to best store user login and passwordSalting your password。鉴于您的SQL注入漏洞,这特别不好。
  3. select * from reg是不必要的,因为您只想知道是否存在行。如果您使用select 1,则数据库不必检查行的内容,只能从索引中提供查询结果。如果您希望有很多行,select 1 where exists ...会更快,因为这样可以让DB在查找至少一行后对查询进行短路。
  4. 您没有关闭finally块中的语句和结果集。这意味着不保证始终处置它们(例如,如果有SQLException抛出)导致资源和连接泄漏。

答案 3 :(得分:1)

首先,你真的应该为此使用参数化查询。如果用户输入'";DROP TABLE reg;作为用户名,您将遇到大麻烦。

另外,您确定用户名和密码是否正确?资本化怎么样?