改正一些错误,初学的时候有很多地方理解有偏差;感谢各位给出的指正!!!(xd来自置顶评论) 这次更改也是读后的修正,但是理解上可能还会有问题,求帮助哈!!!
目录
1. 什么是CSRF?
用户访问网站中错误点击了非法网站,攻击者盗取用户Cookie信息伪造请求访问其他网站,达到自己的目的。
CSRF又称为跨站请求攻击,第三方诱导用户点击含攻击信息的网站或其他资源。利用用户在目标网站的凭证通过目标网站后台的认证过滤,进而实现后续的攻击。
第一处问题:CSRF不是盗取信息,只是冒充用户的提交操作
- CSRF的特点:一般是跨域的,通过第三方网站进行模拟请求;但也会有存在目标网站本域的功能,如图片,链接等。
- 解决措施:
- 1. 同源检测:禁止外域请求;
- 2. CSRF Token
- 3. 双重Cookie
2. 解决方案
2.1 同源检测
利用HTTP协议中的,异步请求携带的Origin/Refer Header;通过这两个请求头可以确定请求源。
2.2 CSRF Token
CSRF攻击之所以能够成功,是因为服务器误把攻击者发送的请求当成了用户自己的请求。那么我们可以要求所有的用户请求都携带一个CSRF攻击者无法获取到的Token )
步骤:
1. Token通过加密算法由服务端生成返回给用户,但是这个Token不存放到Cookie中,而是放到Seesion中;前端通过JS渲染Dom树添加这个Token,在之后的请求中可以进行携带;如果Html是动态数据,那么需要手动添加Token(这里:token是由后端生成返回前端然后渲染的,本体还在Session中,我这这么理解的)
2. 客户端请求携带Token
3. 服务端Session获取Token进行核对
(代码可以看源地址 前端安全系列(二):如何防止CSRF攻击? - 美团技术团队)
HttpServletRequest req = (HttpServletRequest)request; HttpSession s = req.getSession(); // 从 session 中得到 csrftoken 属性 String sToken = (String)s.getAttribute(“csrftoken”); if(sToken == null){ // 产生新的 token 放入 session 中 sToken = generateToken(); s.setAttribute(“csrftoken”,sToken); chain.doFilter(request, response); } else{ // 从 HTTP 头中取得 csrftoken String xhrToken = req.getHeader(“csrftoken”); // 从请求参数中取得 csrftoken String pToken = req.getParameter(“csrftoken”); if(sToken != null && xhrToken != null && sToken.equals(xhrToken)){ chain.doFilter(request, response); }else if(sToken != null && pToken != null && sToken.equals(pToken)){ chain.doFilter(request, response); }else{ request.getRequestDispatcher(“error.jsp”).forward(request,response); } }
分布式环境下的Token: 分布式中一般服务器以集群进行搭建,传统的Session集中在单一服务器上,那么使用集群的时候会有Session不共享的问题(即使数据同步带来的开销不可避免);因此在分布式环境下同一个用户发送的多次HTTP请求可能会先后落到不同的服务器上,导致Session失效 -> 存放到Redis中 -> 公共存储空间
问题:之前学习项目的时候为什么将用户Id作为token?放到Redis中?
1.Redis的情况上面说了,是一个公共存储空间
2.UserId做Token?
(网站中有这样一段话)由于使用Session存储,读取和验证CSRF Token会引起比较大的复杂度和性能问题,目前很多网站采用Encrypted Token Pattern方式。这种方法的Token是一个计算出来的结果,而非随机生成的字符串。这样在校验时无需再去读取存储的Token,只用再次计算一次即可。(在实现的时候通过相同的算法进行解密)
这种Token的值通常是使用UserID、时间戳和随机数,通过加密的方法生成。这样既可以保证分布式服务的Token一致,又能保证Token不容易被破解。
在token解密成功之后,服务器可以访问解析值,Token中包含的UserID和时间戳将会被拿来被验证有效性,将UserID与当前登录的UserID进行比较,并将时间戳与当前时间进行比较。
下面是自己学习过的一个写法,感觉类似,如有错误,欢迎指点!!!
// 没有token直接放行 if (token == null) { doFilter(httpServletRequest, httpServletResponse, filterChain); return; } // 解析token Claims claims = null; try { claims = JwtUtil.parseJWT(token); // JwtUtil一个工具类,就是用同一算法进行解密 } catch (Exception e) { e.printStackTrace(); // 如果解析失败,超时会抛出异常,过滤器中的异常不能统一处理 ResponseResult result = ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN); WebUtils.renderString(httpServletResponse, JSON.toJSONString(result)); } // 从redis中根据token获取数据, getSubObject()表示内容主体 LoginUserDetails user = null; user = redisCache.getCacheObject("login:" + claims.getSubject());
总结
看这段话:
验证码和密码其实也可以起到CSRF Token的作用哦,而且更安全。
为什么很多银行等网站会要求已经登录的用户在转账时再次输入密码,现在是不是有一定道理了?
是不是可以理解为:token的作用就是身份认证?防止机器人?(hhh
上述总结有几点:
1. 什么是token?
2.为什么用token?他对比session的优势? -》 传统看token放到session中,根本不是一个阶级 -》 放到redis中,提效率,减压力
3. token对比cookie的优势? 防止csrf攻击,令牌加密 + 时间戳;这里看攻击者不是无法篡改,而是拿不到;即使拿到请求中的,修改后对比不成功
4. 为什么将UserId作为token,然后解析比对的是什么?
Cookie的原理:
Cookie存放在客户端,可以存放一些用户信息保证状态性。在配合session的时候,服务端生成session,并将对应的sessionID返回到客户端存放到Cookie, 在下一次请求中通过Cookie进行携带。
通过这个特性,攻击者可以盗取Cookie中的信息 (冒充不是盗取)
下面的不是重点,但是还是保留算新知识了嘛,可以忽略
但是token一般存放到local storage, 然后前端通过某些方法获取token进行发送;local Storage中的数据相比于Cookie安全性更高;并且token字符串是经过加密的,当被篡改后在服务端进行解密发送数据错误可以得到反馈
Cookie和LocalStorage的区别?
Coolie:
1.只能存储文本 2.单条存储有大小限制4KB左右
3. 数量限制 , 一般浏览器,限制大概在50条左右
4.需要解决跨域问题
5. 时效限制
localStorage
1. 主要解决Cookie存储空间不足,大小一般为5M;一般仅支持高级浏览器
2. 在隐私模式下localStorage不可被获取, 不能被爬虫获取
3. 相比于sessionStorage,LocalStorage是永久性存储
4. 调用localStorage时每次调用接口的时候放在HTTP请求头的Authorization字段里
2.3 双重Cookie
从网站下扒下俩的,有些不懂的还在修改:1.子域 2.客户端token 3. XSS
另一种防御措施是使用双重提交Cookie。利用CSRF攻击不能获取到用户Cookie的特点,我们可以要求Ajax和表单请求携带一个Cookie中的值。(攻击者冒充一个身份,但是请求中的另一个Cookie只有自己才能后加)
双重Cookie采用以下流程:
- 在用户访问网站页面时,向请求域名注入一个Cookie,内容为随机字符串(例如
csrfcookie=v8g9e4ksfhw
)。- 在前端向后端发起请求时,取出Cookie,并添加到URL的参数中(接上例
POST https://www.a.com/comment?csrfcookie=v8g9e4ksfhw
)。- 后端接口验证Cookie中的字段与URL参数中的字段是否一致,不一致则拒绝。
总结
用双重Cookie防御CSRF的优点:
- 无需使用Session,适用面更广,易于实施。
- Token储存于客户端中,不会给服务器带来压力。
- 相对于Token,实施成本更低,可以在前后端统一拦截校验,而不需要一个个接口和页面添加。
缺点:
- Cookie中增加了额外的字段。
- 如果有其他漏洞(例如XSS),攻击者可以注入Cookie,那么该防御方式失效。
- 难以做到子域名的隔离。
- 为了确保Cookie传输安全,采用这种防御方式的最好确保用整站HTTPS的方式,如果还没切HTTPS的使用这种方式也会有风险。