4

我有一个非常基本的登录 JSP,它将变量传递给 servlet,并从 MySQL DB 检查用户名和密码是否可用。这是否足够安全以在网站上使用,还是需要更多安全性?如果是这样,如何使它更安全?

这是小服务程序:

import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.*;
import java.sql.*;

/**
 * Servlet implementation class loginServlet
*/
@WebServlet("/loginServlet")
public class loginServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

/**
 * @seeHttpServlet#HttpServlet()
 */
public loginServlet() {
    super();
    // TODOAuto-generated constructor stub
}

/**
 * @seeHttpServlet#doGet(HttpServletRequest request, HttpServletResponse
 * response)
 */
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODOAuto-generated method stub
}

/**
 * @seeHttpServlet#doPost(HttpServletRequest request, HttpServletResponse
 * response)
 */
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    HttpSession session = request.getSession();
    String email = request.getParameter("email");
    String pwd = request.getParameter("pass");
    try {
        Class.forName("com.mysql.jdbc.Driver");
        Connection con =
                DriverManager.getConnection("jdbc:mysql://localhost:3306/logindb",
                "root", "password");
        Statement st = con.createStatement();
        ResultSet rs;
        rs = st.executeQuery("select fname, lname, email from userAccount where Email='"
                + email + "' and password='" + pwd + "'");
        if (rs.next()) {
            session.setAttribute("email", email);
            session.setAttribute("Fullname", rs.getString(1) + " " + rs.getString(2));
            response.sendRedirect("success.jsp");
        } else {

            response.sendRedirect("fail.jsp");
        }
    } catch (Exception ssd) {
        System.out.println(ssd.getMessage());
    }
}
}
4

5 回答 5

4

此代码存在几个安全问题和编程问题:

  • 除非应用程序是通过 HTTPS 提供的,否则密码会以明文形式通过网络传递
  • 密码不应明文存储在数据库中。它们应该使用随机盐进行加盐,然后使用像 bcrypt 这样的慢速加密算法进行散列。要检查密码,您应该对来自用户的输入进行加盐和散列,并将结果与​​存储在数据库中的加盐和散列密码进行比较
  • 您的代码不使用准备好的语句,从而使自己容易受到 SQL 注入攻击
  • 您的代码不使用准备好的状态,这将使其失败,例如,一旦电子邮件或密码中有单引号。
  • 你不应该抓住异常。仅捕获您可以处理并且应该发生的异常。对于意外异常,显示一个通用错误页面就可以了。对于预期的异常,您应该处理它们。您的 catch 块在服务器控制台中记录一些内容,并为用户留下一个空白页面。
于 2013-11-14T09:58:58.267 回答
2

这是否足够安全以在网站上使用,还是需要更多安全性?如果是这样,如何使它更安全?

,这还不够安全。您需要使用form-based authenticationstore password as hash限制直接资源调用。为此,我更喜欢Spring Security. 您将从中获得以下好处Spring Security

  1. 基本的 Spring Security 配置
  2. OpenID 集成
  3. 访问控制列表 (ACL)
  4. 基于 JDBC 的配置
  5. 记住我的服务
  6. 基于 LDAP 的身份验证
  7. 单点登录服务
  8. JSF 和 GWT 集成
  9. 还有很多
于 2013-11-14T09:59:19.443 回答
1

由于以下原因,上述内容不安全,

  1. SQL 注入:如果你看到下面的代码,你直接将用户输入附加到 SQL 查询中。因此,假设用户将电子邮件提供为“';drop table userAccount;”。这会丢掉桌子。

    rs = st.executeQuery("select fname, lname, email from userAccount where Email='"+ email + "' and password='"+ pwd + "'");

  2. 永远不要向用户显示堆栈跟踪:如果上面的代码在 try 块内抛出任何异常,您将捕获它并在控制台中打印。但是没有响应被发送。在这种情况下,您也可以将用户重定向到 fail.jsp。

  3. 使用验证码或任何令牌机制来避免自动提交。

于 2013-11-14T09:56:44.603 回答
0

看起来您的密码没有在数据库中散列。因此,在将密码存储在数据库调用之前,例如 sha256 ( https://stackoverflow.com/a/5531479/514463 ),然后当您在上述 servlet 中查找密码时再次执行此操作。

st.executeQuery("select fname, lname, email from userAccount where Email='"+ email + "' and password='"+ sha256(pwd) + "'"); 

此外-您没有在 sql 中使用绑定变量,因此您的代码对 sql 注入开放,这意味着有人可以像 somehtlin 一样作为密码传入

  "password; delete from users;"

并且在执行您的 sql 后,用户表可以全部删除。始终使用准备好的语句

 dbConnection.prepareStatement("select fname, lname, email from userAccount where Email=? and password=?" );

传入您的用户名和 sha256(密码)

于 2013-11-14T09:59:50.773 回答
0

您绝对不应该存储创建密码,因此如果您被黑客入侵,黑客将无法获得密码。您应该使用不可逆算法(推荐SHA-1)和salt来消化它们。 是对彩虹表的保护。

于 2013-11-14T10:03:07.553 回答