前言

项目是java-sec-code:https://github.com/JoyChou93/java-sec-code

CSRF一般指跨站请求伪造(Cross-site request forgery),当某个接口没有设置CSRF验证,点击了别人恶意的链接,可能会造成对这个接口发送相应的数据,造成某个数据被更改。

看下具体实例。

GET类型的CSRF

利用十分简单,构造一个IMG标签,加载的时候即可发送一个恶意get请求

1
<img src=https://blog.mi-di.cn/csrf?xx=11 /> 

POST类型CSRF

构造一个表单自动提交,可以使用ajax触发事件去自动提交。

1
2
3
4
<form action=http://blog.mi-di.cn/csrf.php method=POST>
<input type="text" name="xx" value="11" />
</form>
<script> document.forms[0].submit(); </script>

打开该页面的时候,会自动提交该表单。

另类的CSRF

可以通过一些auth认证,比如ftp,路由器等。

1
<img src=http://admin:[email protected] /> 

接下来看下怎么防御。

从java代码出发

进入controller文件

/src/main/java/org/joychou/controller/CSRF.java

图片

打开http://localhost:8080/csrf/ 看下源码

图片

这个字段就是用来表单提交,POST请求验证的csrf_token,后端生成的,提交后会和后端校验。如果我们直接通过POSTMAN或者其他post请求,缺少了csrf的token是无法完成的。如图

图片

我们看下这个csrf的token是怎么生成的

我们跟进模板页面

/src/main/resources/templates/form.html

图片

我们发现Spring 3.2+和 Thymeleaf 2.1+可以通过这条语句自动生成一个csrf_token来验证

1
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />

可能和flask中的csrf生成的原理不同,这个csrf_token和session相捆绑,在同一个session下每次提交的csrf_token值是相同的,而flask的那个生成csrf是每次都变的。

参考:

https://github.com/JoyChou93/java-sec-code/wiki/CSRF

https://www.jianshu.com/p/7f33f9c7997b