SpringSecurity启用csrf防攻击(解决post提交失败) 作者:马育民 • 2020-07-31 20:41 • 阅读:11376 # 概述 使用spring security后,get请求可以正常访问资源,但提交post请求时,会报错,这是因为security默认开启防csrf攻击 # csrf攻击 CSRF(Cross-site request forgery)跨站请求伪造,也被称为One Click Attack或者Session Riding,通常缩写为CSRF或XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本(XSS),但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装成受信任用户的请求来利用受信任的网站。与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。 CSRF是一种依赖web浏览器的、被混淆过的代理人攻击(deputy attack)。 # spring security springSecurity在2.0之后就会 **默认开启防csrf攻击** `GET`,`HEAD`,`TRACE`,`OPTIONS`请求放行,其他请求(如`post`、`delete`、`put`),都需要带上 csrf token,不带tocken,服务器会认为该请求非法,请求就会被拒绝 ### CsrfFilter `CsrfFilter`处理CSRF校验,详见: https://www.malaoshi.top/show_1EF5zQbtQP3U.html # 如何能够正常发post请求 - 禁用csrf - 前台页面获取csrf token,然后发post请求时,将token一并发出 - HttpSessionCsrfTokenRepository,适用 jsp、Thymeleaf - CookieCsrfTokenRepository ,适用前后台分离式开发 # 禁用csrf ``` @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable();//关闭打开的csrf保护 } } ``` # HttpSessionCsrfTokenRepository 在默认情况下,Spring Security加载的是一个`HttpSessionCsrfTokenRepository` `HttpSessionCsrfTokenRepository` 将 CsrfToken 值存储在 HttpSession 中,并指定前端把CsrfToken 值放在名为`_csrf`的请求参数或名为`X-CSRF-TOKEN`的请求头字段里(可以调用相应的设置方法来重新设定)。校验时,通过对比HttpSession内存储的CsrfToken值与前端携带的CsrfToken值是否一致,便能断定本次请求是否为CSRF攻击。 ### jsp获取token ``` ``` ### 应用场景 这种方式适合 jsp、Thymeleaf等,可以从session中取出token 在前后台分离式开发 **会出现问题**,因为html、js无法从session中取出token # CookieCsrfTokenRepository Spring Security还提供了另一种方式,即`CookieCsrfTokenRepository` `CookieCsrfTokenRepository` 是一种更加灵活可行的方案,它将 `CsrfToken` 值存储在用户的`cookie`内。 减少了服务器HttpSession存储的内存消耗,并且当用cookie存储CsrfToken值时,前端可以用JavaScript读取(需要设置该cookie的httpOnly属性为false),而不需要服务器注入参数,在使用方式上更加灵活。 存储在cookie中是不可以被CSRF利用的,cookie 只有在同域的情况下才能被读取,所以杜绝了第三方站点跨域获取 CsrfToken 值的可能。CSRF攻击本身是不知道cookie内容的,只是利用了当请求自动携带cookie时可以通过身份验证的漏洞。 **注意:** 服务器对 `CsrfToken` 值的校验 **不是取自 cookie**,而是需要前端 **手动将CsrfToken值作为参数携带在请求里** ### 启用cookie方式 关键代码: ``` http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) ``` 完整代码: ``` @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) //使用cookie .and() .authorizeRequests()//url权限配置 // .antMatchers("/index.html").permitAll() // 匹配这些路径可以所有人访问 .antMatchers("/user/**").hasRole("admin") .anyRequest().authenticated() .and() //login部分 .formLogin() .loginPage("/login.html")//指定登录页面。所有url前面必须写/,否则报错 'xxx' is not a valid forward URL .loginProcessingUrl("/login")//security提供的处理登录url,默认是/login // .successForwardUrl("/index.html")//登录成功后跳转的页面,需要额外处理才能使用,否则页面会提示错误 .defaultSuccessUrl("/index.html")//登录成功后重定向的页面 .failureUrl("/login_fails.html")//登录失败跳转的页面 // .failureForwardUrl("/login_fails.html")//登录失败不会转发 .permitAll()//让login部分的url可以任意访问 // // //logout部分 .and() .logout() .logoutSuccessUrl("/login.html")//退出成功访问的页面 .invalidateHttpSession(true)//清空session .permitAll();//让logout部分的url可以任意访问 } } ``` 访问 http://localhost:8080/ ,在cookie中可以看到 xsrf-token: [](https://www.malaoshi.top/upload/pic/security/QQ20200731-205300.png) ### 修改登录页面 由于登录要发送post请求,所以必须带上token,否则会被过滤器拦截,无法正常提交 从cookie中获取token,并放入表单隐藏域中,一并发出 ``` 用户名: 密码: ``` 在表单中添加隐藏域``,提交表单时连带token一起提交 感谢: https://www.cnblogs.com/dalianpai/p/12393133.html 原文出处:https://www.malaoshi.top/show_1EF5zSj6yS7R.html