Java解决CSRF问题
项目地址: https://github.com/morethink/web-security
CSRF是什么?
CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF。
CSRF可以做什么?
你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。
CSRF的原理
下图简单阐述了CSRF攻击的思

从上图可以看出,要完成一次CSRF攻击,受害者必须依次完成两个步骤:
- 登录受信任网站A,并在本地生成Cookie。
- 在不登出A的情况下,访问危险网站B。
看到这里,你也许会说:“如果我不满足以上两个条件中的一个,我就不会受到CSRF的攻击”。是的,确实如此,但你不能保证以下情况不会发生:
- 你不能保证你登录了一个网站后,不再打开一个tab页面并访问另外的网站。
- 你不能保证你关闭浏览器了后,你本地的Cookie立刻过期,你上次的会话已经结束。(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了......)
- 上图中所谓的攻击网站,可能是一个存在其他漏洞的可信任的经常被人访问的网站。
下面讲一讲java解决CSRF攻击的方式。
模拟CSRF攻击
登录A网站
用户名和密码都是admin。
http://localhost:8081/login.html:

你有权限删除1号帖子
http://localhost:8081/deletePost.html:

登录有CSRF攻击A网站的B网站
http://localhost:8082/deletePost.html:

明显看到B网站是8082端口,A网站是8081端口,但是B网站的删除2号帖子功能依然实现。
预防CSRF攻击
简单来说,CSRF 就是网站 A 对用户建立信任关系后,在网站 B 上利用这种信任关系,跨站点向网站 A 发起一些伪造的用户操作请求,以达到攻击的目的。
而之所以可以完成攻击是因为B向A发起攻击的时候会把A网站的cookie带给A网站,也就是说cookie已经不安全了。
通过Synchronizer Tokens
Synchronizer Tokens: 在表单里隐藏一个随机变化的 csrf_token csrf_token 提交到后台进行验证,如果验证通过则可以继续执行操作。这种情况有效的主要原因是网站 B 拿不到网站 A 表单里的 csrf_token
这种方式的使用条件是PHP和JSP等。因为cookie已经不安全了,因此把csrf_token值存储在session中,然后每次表单提交时都从session取出来放到form表单的隐藏域中,这样B网站不可以得到这个存储到session中的值。
下面是JSP的:
<input type="hidden" name="random_form" value=<%=random%>></input>
但是我现在的情况是html,不是JSP,并不能动态的从session中取出csrf_token值。只能采用加密的方式了。
Hash加密cookie中csrf_token值
这可能是最简单的解决方案了,因为攻击者不能获得第三方的Cookie(理论上),所以表单中的数据也就构造失败了。
我采用的hash加密方法是JS实现Java的HashCode方法,得到hash值,这个比较简单。也可以采用其他的hash算法。
前端向后台传递hash之后的csrf_token值和cookie中的csrf_token值,后台拿到cookie中的csrf_token值后得到hashCode值然后与前端传过来的值进行比较,一样则通过。
你有权限删除3号帖子
http://localhost:8081/deletePost.html

B网站的他已经没有权限了
我们通过UserFilter.java给攻击者返回的是403错误,表示服务器理解用户客户端的请求但拒绝处理。
http://localhost:8082/deletePost.html:

攻击者不能删除4号帖子。
前端代码:
deletePost.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>deletePost</title>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript">
function deletePost() {
var url = '/post/' + document.getElementById("postId").value;
var csrf_token = document.cookie.replace(/(?:(?:^|.*;\s*)csrf_token\s*\=\s*([^;]*).*$)|^.*$/, "$1");
console.log('csrf_token=' + csrf_token);
$.ajax({
type: "post",//请求方式
url: url, //发送请求地址
timeout: 30000,//超时时间:30秒
data: {
"_method": "delete",
"csrf_token": hash(csrf_token) // 对csrf_token进行hash加密
},
dataType: "json",//设置返回数据的格式
success: function (result) {
if (result.message == "success") {
// window.location.href = "index.html";
$("#result").text("删除成功");
} else {
$("#result").text("删除失败");
}
},
error: function () { //请求出错的处理
$("#result").text("请求出错");
}
});
}
// javascript的String到int(32位)的hash算法
function hash(str) {
var hash = 0;
if (str.length == 0) return hash;
for (i = 0; i < str.length; i++) {
char = str.charCodeAt(i);
hash = ((hash << 5) - hash) + char;
hash = hash & hash; // Convert to 32bit integer
}
return hash;
}
</script>
</head>
<body>
<h3>删除帖子</h3>
帖子编号 : <input type="text" id="postId"/>
<button onclick="deletePost();">deletePost</button>
<br/>
<br/>
<br/>
<div>
<p id="result"></p>
</div>
</body>
</html>
后台代码:
UserInterceptor.java
package cn.morethink.interceptor;
import cn.morethink.util.JsonUtil;
import cn.morethink.util.Result;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
/**
* @author 李文浩
* @date 2018/1/4
*/
public class UserInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String method = request.getMethod();
System.out.println(method);
if (method.equalsIgnoreCase("POST") || method.equalsIgnoreCase("DELETE")
|| method.equalsIgnoreCase("PUT")) {
String csrf_token = request.getParameter("csrf_token");
System.out.println(csrf_token + "1222222222222222222222222222222222222222222222");
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 0 && csrf_token != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("csrf_token")) {
if (Integer.valueOf(csrf_token) == cookie.getValue().hashCode()) {
return true;
}
}
}
}
}
Result result = new Result("403", "你还想攻击我??????????", "");
PrintWriter out = response.getWriter();
out.write(JsonUtil.toJson(result));
out.close();
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
注意:
- cookie必须要设置PATH才可以生效,否则在下一次请求的时候无法带给服务器。
- Spring Boot 出现启动找不到主类的问题时可以mvn clean一下。
- Filter设置response.sendError(403)在Spring Boot没有效果。
参考文档:
Java解决CSRF问题的更多相关文章
- java 解决Hash(散列)冲突的四种方法--开放定址法(线性探测,二次探测,伪随机探测)、链地址法、再哈希、建立公共溢出区
java 解决Hash(散列)冲突的四种方法--开放定址法(线性探测,二次探测,伪随机探测).链地址法.再哈希.建立公共溢出区 标签: hashmaphashmap冲突解决冲突的方法冲突 2016-0 ...
- JAVA | Java 解决跨域问题
JAVA | Java 解决跨域问题 Table of Contents 引言 什么是跨域(CORS) 什么情况会跨域 解决方案 前端解决方案 后端解决方案 具体方式 一.使用Filter方式进行设置 ...
- Java解决大文件读取的内存问题以及文件流的比较
Java解决大文件读取的内存问题以及文件流的比较 传统方式 读取文件的方式一般是是从内存中读取,官方提供了几种方式,如BufferedReader, 以及InputStream 系列的,也有封装好的如 ...
- java 解决中文乱码
//1.代码解决 public class LuanMa { public static String getNewString(String luanma){ String result = &qu ...
- 约瑟夫环的java解决
总共3中解决方法,1.数学推导,2.使用ArrayList递归解决,3.使用首位相连的LinkedList解决 import java.util.ArrayList; /** * 约瑟夫环问题 * 需 ...
- java 解决JFrame不能设置背景色的问题 分类: Java Game 2014-08-15 09:48 119人阅读 评论(0) 收藏
这段时间比较多,于是写一写JAVA的一些IT技术文章.如有JAVA高手请加QQ:314783246,互相讨论. 在Java的GUI设计中,Frame和JFrame两者之间有很大差别,上次刚学时编一个窗 ...
- Java解决TopK问题(使用集合和直接实现)
在处理大量数据的时候,有时候往往需要找出Top前几的数据,这时候如果直接对数据进行排序,在处理海量数据的时候往往就是不可行的了,而且在排序最好的时间复杂度为nlogn,当n远大于需要获取到的数据的时候 ...
- 关于eclipse新建web项目,提示:"The superclass "javax.servlet.http.HttpServlet" was not found on the Java"解决办法
新建jsp页面老提示: Multiple annotations found at this line: - The superclass "javax.servlet.http.HttpS ...
- 解决No 'Access-Control-Allow-Origin' header is present on the requested resource.跨域问题(后台(java)解决方法)
附:前端常见跨域解决方案(全) 跨域错误 解决方法 在后台写一个过滤器来改写请求头 附上一个前端不知所以然的后台java代码: public class CorsFilter implements F ...
随机推荐
- 线上系统/tmp 目录不断增长分析与总结
1.问题描述 系统配置为单核4G, web 工程配置堆2G, /tmp目录 二进制文件不断增加,平均一天增加20G, 手动清理/tmp目录,重启系统,问题依旧. 2.分析 /tmp 目录存放系统运行 ...
- weui 中的tabbar导航
最近做微信的服务号项目,用的weui作为主要的ui,但是对于用惯了ele ui的开发者来说,文档貌似有点不友好.真是很让人头疼! 所以结合着自己做的项目,随便写一点东西. 比如说,tabbar导航的切 ...
- win10/win7下不通过winmanager整合NERDTree和Tagbar的gVim8.0配置
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利. 注:图片来自作者公众号--"iKM_2018",亦即& ...
- 数据挖掘之聚类算法Apriori总结
项目中有时候需要用到对数据进行关联分析,比如分析一个小商店中顾客购买习惯. package com.data.algorithm; import com.google.common.base.Spli ...
- 基于Windows环境下cmd/编译器无法输入中文,显示中文乱码解决方案
基于Windows环境下cmd/编译器无法输入中文,显示中文乱码解决方案 两个月前做C++课设的时候,电脑编译器编译结果出现了中文乱码,寻求了百度和大神们,都没有解决这个问题,百度上一堆解释是对编译器 ...
- 51 Nod 1057 N的阶乘【Java大数乱搞】
1057 N的阶乘 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 输入N求N的阶乘的准确值. Input 输入N(1 <= N <= 10000) Ou ...
- HDU1312-Red and Black-DFS
Red and Black Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tot ...
- Win10没有以太网图标如何找回?以太网适配器不见了怎么恢复?
Win10以太网适配器不见了怎么恢复?以太网其实就是Win7系统中常说的"本地连接"假若用户发现网络适配器中的以太网适配器图标不见了,可以在设备管理器中添加一些这类适配器,具体过程 ...
- SpringMVC框架学习笔记(5)——数据处理
1.提交数据的处理 a)提交的域名称和参数名称一致 http://localhost:8080/foward/hello.do?name=zhangsan 处理方法 @RequestMapping(v ...
- 一步一步从原理跟我学邮件收取及发送 4.不同平台下的socket
既然是面向程序员的文章那当然不能只说说原理,一定要有实际动手的操作. 其实作为我个人的经历来说,对于网络编程,这是最重要的一章! 作为一位混迹业内近20年的快退休的程序员,我学习过很多的开发语言 ...