在会话固定攻击,黑客获取/设置(通过任何方式)另一个人的会话ID。然后,黑客可以冒充他人并获取敏感信息。
Java Servlet 3.1 引入了以下 HttpServletRequest 方法:
String changeSessionId()
此方法将当前会话 id 更改为新的,从而提供针对会话固定攻击的保护。
Servlet 3.1 还引入了HttpSessionIdListener用于接收 HttpSession id 更改通知。
对于 3.1 之前的版本,我们可以使用以下步骤:
HttpSession session = .....
.....
session.invalidate();
session=request.getSession(true);
//now set data from old session here
例子
在以下示例中,我们将学习如何使用 Servlet 3.1 API 对抗会话固定。
登录 servlet
@WebServlet(name = "userLoginServlet", urlPatterns = {"/login"})
public class LogInServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
HttpSession session = req.getSession();
String userKey = "loggedInUser";
User user = (User) session.getAttribute(userKey);
if (user == null) {
user = loadUserForRequest(req);
session.setAttribute(userKey, user);
}
prepareLogginInfoHtml(user, resp);
req.changeSessionId();
}
private void prepareLogginInfoHtml(User user, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/html");
PrintWriter w = resp.getWriter();
w.write("User logged in " + user.getName());
w.write("<br/><a href='/balance'>Show Balance</a>");
}
private User loadUserForRequest(HttpServletRequest req) {
//returning a dummy user
return new User("1", "Mike", "12312",
BigDecimal.valueOf(200000));
}
}
public class User {
private String id;
private String name;
private String accountNumber;
BigDecimal currentBalance;
.............
}
用于登录后处理的另一个 servlet
@WebServlet(name = "userBalanceServlet", urlPatterns = {"/balance"})
public class BalanceServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
HttpSession session = req.getSession();
User user = (User) session.getAttribute("loggedInUser");
if (user == null) {
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/login");
dispatcher.forward(req, resp);
} else {
prepareBalanceInfoHtml(user, resp);
req.changeSessionId();
}
}
private void prepareBalanceInfoHtml(User user, HttpServletResponse resp) throws IOException {
resp.setContentType("text/html");
PrintWriter w = resp.getWriter();
w.write("User logged in " + user.getName());
w.write("<br/>Balance: " + user.getCurrentBalance());
}
}
实现 AppSessionIdListener
@WebListener
public class AppSessionIdListener implements HttpSessionIdListener {
@Override
public void sessionIdChanged(HttpSessionEvent event, String oldSessionId) {
System.out.println("oldSessionId: " + oldSessionId);
System.out.println("newSessionId: " + event.getSession().getId());
}
}
要尝试示例,请运行嵌入式 Jetty(在以下示例项目的 pom.xml 中配置):
mvn jetty:run
在本教程中,我们使用 Jetty 插件而不是 tomcat7-maven-plugin,因为 tomcat 插件不支持 Servlet 3.1(它支持最高 3.0 的版本)。
输出

点击“显示余额”链接:

服务器输出
正如我们的 HttpSessionIdListener 打印的那样:
.....
oldSessionId: node0md9ox8wtj0e91lr5kpuzw7dql0
newSessionId: node01jl2v0v5bvfwgxvhr7ao2f52z1
....
oldSessionId: node0nyhkl2ej1ret1716bwjwyl9a92
newSessionId: node0mqnz9mrwfg8a1it5hxc7rdg3v3
....
Chrome 检查 - 网络选项卡

示例项目
使用的依赖项和技术:
- javax.servlet-api 3.1.0 Java Servlet API
- jetty-maven-plugin 9.4.1.v20170120:Jetty maven 插件。
- JDK 1.8
- Maven 3.3.9
本文介绍了如何利用Java Servlet 3.1 API来防范会话固定攻击。通过调用HttpServletRequest的changeSessionId()方法,可以在用户成功登录后改变会话ID,从而保护用户会话的安全。同时,通过实现HttpSessionIdListener,可以监听会话ID的变化。示例展示了登录和余额查询两个Servlet的实现,并给出了使用Jetty运行示例的说明。

1万+

被折叠的 条评论
为什么被折叠?



