• JavaWeb之会话技术&会话固定攻击


    什么是会话跟踪技术

    客户向某一个服务器发出第一个请求时,会话就开始了,直到客户关闭了浏览器,会话结束。在这个会话的多个请求中共享数据,这就是会话跟踪技术

    类似于你今天拿着银行卡去银行办理业务,今天没有办理完,你明天拿着银行卡(sessionID)过去,银行那边能继续给你办理没有完成的业务,不至于重新开始办理。

    起源&发展

    HTTP是一种不保存用户状态,即无状态(stateless)的协议。HTTP协议自身不对请求和响应之间的通信状态进行保存,也就是说在HTTP这个级别,协议对于发送过的请求或响应都不做持久化处理。(这是为了更快地处理大量事务,确保协议的可伸缩性)
    可随着Web的不断发展,因为这种无状态而导致业务处理变得棘手的情况也增多了。比如登录一家购物网站,然后跳转到该站的其他页面,也需要能继续保持登录状态。针对这个问题,为了保存用户的状态,因此引入了Cookie和Session技术。

    什么是Cookie

    Cookie就是一个键和一个值构成的,随着服务器端的响应发送给客户端浏览器。然后客户端浏览器会把Cookie保存起来,当下一次再访问服务器时把Cookie再发送给服务器

    特性:

    1.如果服务器端发送重复的Cookie那么会覆盖原有的Cookie
    2.Cookie保存在客户端,用户可以随意修改,并不安全,所以一般用来存放一些不敏感的数据
    3.不是每次请求都会带上所有Cookies,只有请求路径包含Cookie Path的Cookie才会被带上

    什么是Session

    HttpSession 是一个服务端的概念,服务端生成的 HttpSession 都会有一个对应的 sessionid,这个 sessionid 会通过 cookie 传递给前端,前端以后每次发送请求的时候,都会带上这个 sessionid 参数。服务端看到这个 sessionid 就会把这个前端请求和服务端的某一个 HttpSession 对象对应起来,形成“会话”的感觉。

    特性:

    1.Session 数据存在了服务端,用户不能进行修改

    会话过程在这里插入图片描述

    会话固定攻击

    1.URL重写
    因为Cookies存在风险,所以有些浏览器不支持Cookie。也有可能客户阻止了所有的Cookies。为了兼容这种情况的存在,有些服务支持重写URL来识别身份。
    例如:http://yyg.com;jsessionid=xxx。

    URL重写是一种位于服务器端的操作,URL重写不需要往返服务器。重写的URL不会被返回客户端,也不会出现在浏览器地址栏。比如/resource 重写到 /different-resource 时,客户端会请求 /resource ,而服务器会在内部提取 /different-resource 处的资源。客户端能够检索到已重写的URL处的资源,但是客户端发出请求并收到响应时,并不会知道已重写URL处存在的资源

    图示:
    在这里插入图片描述
    2什么是会话固定攻击
    黑客只需访问一次系统,将系统生成的sessionld提取并拼凑在URL上,然后将该URL发给一些取得信任的用户。只要用户在session有效期内通过此URL进行登录,该sessionld就会绑定到用户的身份,黑客便可以轻松享有同样的会话状态,完全不需要用户名和密码,这就是典型的会话固定攻击。

    举例(通过重写URL):
    1.攻击者自己可以正常访问淘宝网站,在访问的过程中,淘宝网站给攻击者分配了一个 sessionid;
    2.攻击者利用自己拿到的 sessionid 构造一个淘宝网站的链接,并把该链接发送给受害者;
    3.受害者使用该链接登录淘宝网站(该链接中含有 sessionid),登录成功后,一个合法的会话就成功建立;
    4.攻击者利用手里的 sessionid 冒充受害者。

    反射型xss攻击流程
    (图片来源于https://www.cnblogs.com/csnd/p/11807592.html)
    在这里插入图片描述
    反射型xss攻击主要用来窃取Cookie信息,需要欺骗用户点击链接。
    (还有存储型XSS:代码是存储在服务器中的)

    测试小案例
    (通过浏览器模拟实现会话攻击,跳过代码实现,我这里url重写有些问题实现不了)

    模拟一个钓鱼网站
    在这里插入图片描述
    后台登录代码

    package com.feisi.web;
    
    import com.feisi.Utils.BeanFactory;
    import com.feisi.pojo.Admin;
    import com.feisi.service.AdminService;
    
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.*;
    import java.io.IOException;
    
    @WebServlet("/LoginServlet")
    public class LoginServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //1.编码处理
            request.setCharacterEncoding("UTF-8");
            response.setContentType("text/html;charset=UTF-8");
    
            //获取验证码
            String verifycode = request.getParameter("verifycode");
            //得到session对象
            HttpSession session = request.getSession();
    
    
            //测试URL重写成功没有
            Object admin1 = session.getAttribute("admin");
            if (admin1!=null){
                System.out.println(admin1.toString());
            }
    
    
    
    
    
    
            //取消验证功能
    //        String checkcode = session.getAttribute("CHECKCODE_SERVER").toString();
            String error ="";
    
    //        if(!checkcode.equalsIgnoreCase(verifycode)){ //不相等
    //            error="验证码输入错误";
    //            request.setAttribute("error",error);
    //            request.getRequestDispatcher("/login.jsp").forward(request,response);
    //            return;
    //        }
    
            //2.获取请求参数
            String user = request.getParameter("user");
            String password = request.getParameter("password");
            //3.数据类型转换
    
            //4.调用Service的方法
            AdminService adminService = BeanFactory.createBean(AdminService.class);
            Admin admin =  adminService.login(user,password);
            if(admin != null){//登录成功
    
                //request.setAttribute("admin",admin);
    
                //5.把数据保存域中, admin保存到session域
                session.setAttribute("admin",admin);
    
                //判断用户是否勾选记住我
                String rem = request.getParameter("rem");
                if("rem".equals(rem)){ //勾选
                    //创建用户名cookie, 密码cookie (加密)
                    Cookie nameCookie = new Cookie("name",user);
                    Cookie pwdCookie = new Cookie("pwd",password);
                    //默认7天有效
                    nameCookie.setMaxAge(7*24*60*60);
                    pwdCookie.setMaxAge(7*24*60*60);
                    //path: 默认 /
    
                    //保存到客户端浏览器
                    response.addCookie(nameCookie);
                    response.addCookie(pwdCookie);
                }else{//没有勾选, 有就删除
                    //获取cookie
                    Cookie[] cookies = request.getCookies();
                    if(cookies != null && cookies.length > 0){
                        for (Cookie cookie : cookies) {
                            //判断使用有name的cookie 与pwd的Cookie
                            if(cookie.getName().equals("name") || cookie.getName().equals("pwd")){
                                //删除
                                cookie.setMaxAge(0);
                                response.addCookie(cookie);
                            }
                        }
                    }
                }
                //6.页面跳转  重定向
                response.sendRedirect(request.getContextPath()+"/index.jsp");
                //request.getRequestDispatcher("/index.jsp").forward(request,response);
            }else{//登录失败
                //5.把数据保存域中
                error = "用户名或者密码错误";
                request.setAttribute("error",error);
                //6.页面跳转 转发: 把数据存在request域
                request.getRequestDispatcher("/login.jsp").forward(request,response);
                // 往request域存数据, 存活时候很短, 只在一次请求内有效
            }
    
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
        }
    }
    
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109

    登录成功后,会将session域中的数据打印在控制台
    在这里插入图片描述

    前端窃取户的cookie,如何设置HttpOnly为true,则无法通过js来获取(我这里是打印在控制台)

        // 获取指定名称的cookie
          function getCookie(name){
              var strcookie = document.cookie;//获取cookie字符串
              var arrcookie = strcookie.split("; ");//分割
    		  console.log(strcookie);
              //遍历匹配
              for ( var i = 0; i < arrcookie.length; i++) {
                  var arr = arrcookie[i].split("=");
                  if (arr[0] == name){
                      return arr[1];
                  }
              }
              print();
              return "";
          }
    
          // 打印所有cookie
          function print() {
              var strcookie = document.cookie;//获取cookie字符串
              var arrcookie = strcookie.split(";");//分割
    
              //遍历匹配
              for ( var i = 0; i < arrcookie.length; i++) {
                  var arr = arrcookie[i].split("=");
                  console.log(arr[0] +":" + arr[1]);
              }
          }
    
    • 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

    然后我在另外一个浏览器中访问/LoginServlet,可以访问到session域中的内容,说明攻击成功(一个小测试)

    如何防御会话攻击

    通过Spring Security 可以防御,主要是从以下三个方面来完成:
    1.「首先」会利用 StrictHttpFirewall 防火墙,如果发现请求地址中带有 “;”,则该请求会被直接拒绝;

    2.「然后」就是响应的 Set-Cookie 字段中有 HttpOnly 属性,这种方式会避免通过 XSS 攻击来获取 Cookie 中的会话信息,进而达成会话固定攻击。

    3.「最后」则是让 sessionid 改变一下。既然问题是由于 sessionid 不变导致的,那我们就让 sessionid 变一下,利用Spring Security提供的防御会话固定攻击的策略即可实现。

    还不会,以后再更新

  • 相关阅读:
    Java——TCP UDP Socket编程
    pygame播放视频并实现音视频同步
    神经网络模型画图工具,神经网络模型图怎么画
    【知识点】JavaScript中require的一些理解
    成都优优聚是专业美团代运营吗?
    进阶Linux服务器命令
    SCM供应链具体有哪些优越性?智能供应链管理系统助力汽车服务企业数字化转型
    iceberg学习笔记(2)—— 与Hive集成
    中小企业平台安全建设如何落地
    时序数据库-5-[IoTDB]的数据迁移
  • 原文地址:https://blog.csdn.net/xiaogaotongxue__/article/details/127349794