什么是会话跟踪技术
客户向某一个服务器发出第一个请求时,会话就开始了,直到客户关闭了浏览器,会话结束。在这个会话的多个请求中共享数据,这就是会话跟踪技术
类似于你今天拿着银行卡去银行办理业务,今天没有办理完,你明天拿着银行卡(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 {
}
}
登录成功后,会将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]);
}
}
然后我在另外一个浏览器中访问/LoginServlet,可以访问到session域中的内容,说明攻击成功(一个小测试)
如何防御会话攻击
通过Spring Security 可以防御,主要是从以下三个方面来完成:
1.「首先」会利用 StrictHttpFirewall 防火墙,如果发现请求地址中带有 “;”,则该请求会被直接拒绝;
2.「然后」就是响应的 Set-Cookie 字段中有 HttpOnly 属性,这种方式会避免通过 XSS 攻击来获取 Cookie 中的会话信息,进而达成会话固定攻击。
3.「最后」则是让 sessionid 改变一下。既然问题是由于 sessionid 不变导致的,那我们就让 sessionid 变一下,利用Spring Security提供的防御会话固定攻击的策略即可实现。
还不会,以后再更新