文章目录
  1. 1. 什么是CSRF
    1. 1.1. 解决办法
    2. 1.2. Spring Security中启用CSRF保护
      1. 1.2.1. 配置CSRF保护
      2. 1.2.2. 包含CSRF Token

Spring Security可以保护应用免收Cross Site Request Forgery (CSRF)的攻击。

什么是CSRF

假设你的银行网站提供如下的表单进行转账

1
2
3
4
5
6
POST /transfer HTTP/1.1
Host: bank.example.com
Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly
Content-Type: application/x-www-form-urlencoded
amount=100.00&routingNumber=1234&account=9876

现在假设你登陆了银行的网站,然后没有登出,访问了一个恶意网站,恶意网站有这么一个表单

1
2
3
4
5
6
7
8
9
10
11
12
13
<form action="https://bank.example.com/transfer" method="post">
<input type="hidden"
name="amount"
value="100.00"/>
<input type="hidden"
name="routingNumber"
value="evilsRoutingNumber"/>
<input type="hidden"
name="account"
value="evilsAccountNumber"/>
<input type="submit"
value="Win Money!"/>
</form>

并且你点了这个表单,尽管恶意网站不知道你的用户名密码,看不到的cookies,但是最终请求还是被发出,钱就被转走了。并且这还能通过Javascript脚本来实现,就是说恶意网站根本就不需要你点击这个按钮,只要访问了他们的网站就能实现。

解决办法

解决的方法就是使用Synchronizer Token Pattern。这个方案确保每个请求,除了session的cookies值,还需要发送一个预先生成的随机值作为请求参数。

1
2
3
4
5
6
POST /transfer HTTP/1.1
Host: bank.example.com
Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly
Content-Type: application/x-www-form-urlencoded
amount=100.00&routingNumber=1234&account=9876&_csrf=<secure-random>

Spring Security中启用CSRF保护

配置CSRF保护

Spring Security 4.0,CSRF保护是默认启用的,如果要关闭

1
2
3
4
<http>
<!-- ... -->
<csrf disabled="true"/>
</http>
1
2
3
4
5
6
7
8
9
10
@EnableWebSecurity
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable();
}
}

包含CSRF Token

启用CSRF保护后,需要在请求中包含CSRF Token。下面是一个JSP的例子

1
2
3
4
5
6
7
8
9
<c:url var="logoutUrl" value="/logout"/>
<form action="${logoutUrl}"
method="post">
<input type="submit"
value="Log out" />
<input type="hidden"
name="${_csrf.parameterName}"
value="${_csrf.token}"/>
</form>

AJAX的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<html>
<head>
<meta name="_csrf" content="${_csrf.token}"/>
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" content="${_csrf.headerName}"/>
<!-- ... -->
</head>
<!-- ... -->
$(function () {
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
$(document).ajaxSend(function(e, xhr, options) {
xhr.setRequestHeader(header, token);
});
});

如果使用JSP标签,或者Thymeleaf 2.1+,CSRF会自动通过RequestDataValueProcessor的子类CsrfRequestDataValueProcessor自动加入到form表单中。 前提是需要启用@EnableWebMvcSecurity来生成CsrfRequestDataValueProcessor的实例

NOTE: 从Spring Security 4.0开始,@EnableWebMvcSecurity注解被废弃,使用@EnableWebSecurity注解即可。

文章目录
  1. 1. 什么是CSRF
    1. 1.1. 解决办法
    2. 1.2. Spring Security中启用CSRF保护
      1. 1.2.1. 配置CSRF保护
      2. 1.2.2. 包含CSRF Token
Fork me on GitHub