Version: Next
CSRF跨站请求伪造攻击防御
CSRF攻击
通常的CSRF攻击方式如下:
- 你登录了网站A,攻击者向你的网站A账户发送留言、或者伪造嵌入页面,带有危险操作链接。
- 当你在登录状态下点击了攻击者的连接,因此该链接对你网站A的账户进行了操作。
- 这个操作是你在网站A中主动发出的,并且也是针对网站A的HTTP链接请求,同源策略无法限制该请求。
如果你不小心点击的连接,是针对网站的数据操作,如:转出货币,你的钱就被转走了。因为点击"链接"的请求是HTTP的GET请求,所以正规的开发人员的做法是不要使用GET方法进行数据操作,只使用GET方法进行数据查询。
后端防御
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringAntMatchers("/authentication");
.and()
...
}
}
- 使用CookieCsrfTokenRepository生成CSRF Token放入cookie,并设置cookie的HttpOnly=false,允许读取该cookie。这样非浏览器等无法自动维护cookie的客户端可以读取cookie中的CSRF Token,以供后续资源请求中使用。
- 使用ignoringAntMatchers开放一些不需要进行CSRF防护的访问路径,比如:登录授权。
至此,我们生成了CSRF token保存在了cookies中,浏览器向服务端发送的HTTP请求,都要将CSRF token带上,服务端校验通过才能正确的响应。这个校验的过程并不需要我们自己写代码实现,Spring Security会自动处理。但是我们需要关注前端代码,如何正确的携带CSRF token。
前端携带CSRF Token
以Thymeleaf为例
- 其他模板引擎或前端框架,需要自己写代码从Cookie中拿这个CSRF Token
- 在Header中携带CSRF token
var headers = {};
headers['X-XSRF-TOKEN'] = "${_csrf.token}";
$.ajax({
headers: headers,
});
- 直接作为参数提交。
$.ajax({
data: {
"_csrf": "${_csrf.token}"
}
});
- 表单的隐藏字段
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}">