sunny123456

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  1796 随笔 :: 22 文章 :: 24 评论 :: 226万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

Servlet - 使用 changeSessionId() 改变SessionId 防止会话固定攻击

会话固定攻击,黑客获取/设置(通过任何方式)另一个人的会话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
原文链接:https://blog.csdn.net/allway2/article/details/126679312
posted on   sunny123456  阅读(302)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示