笔记-PSOT请求报错:Invalid CSRF Token ‘null‘ was found on the request parameter ‘_csrf‘......

1. 背景

使用 postman 执行get请求正常,但执行 post 请求时报错:
Invalid CSRF Token 'null' was found on the request parameter '_csrf' or header 'X-XSRF-TOKEN'

2. 原因分析

2.1 相关知识点:

跨域问题:

  • 同一个ip、同一个网络协议、同一个端口,三者都满足就是同一个域,否则就有跨域问题

session劫持问题:

  • 客户端与服务端在基于http协议在交互的数据的时候,由于http协议本身是无状态协议,引进了cookie的 方式进行记录服务端和客户端的之间交互的状态和标记。cookie里面一般会放置服务端生成的session id(会话ID)用来识别客户端访问服务端过 程中的客户端的身份标记。

  • 跨域情况下, session id可能会被恶意第三方劫持,此时劫持这个session id的第三方会根据这个session id向服务器发起请求,此时服务器收到这个请求会 认为这是合法的请求,并返回根据请求完成相应的服务端更新。

什么是csrf:

  • CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack” 或者Session Riding,攻击方通过伪造用户请求访问受信任站点。

2.2 原因分析

Spring Security 4.0之后,引入了CSRF,默认是开启,CSRF默认支持的方法: GET|HEAD|TRACE|OPTIONS,不支持POST:

  • 如果这个http请求是get方式发起的请求,意味着它只是访问服务器 的资源,仅仅只是查询,没有更新服务器的资源,所以对于这类请求,spring security的防御策略是允许的;
  • 如果这个请求是通过post请求发起的, 那么spring security是默认拦截这类请求的。因为这类请求是带有更新服务器资源的危险操作,如果恶意第三方通过劫持session id来更新 服务器资源,那会造成服务器数据被非法的篡改。
  • 在默认的情况下,spring security是启用csrf 拦截功能的。这会造成:在跨域的情况下,post方式提交的请求都会被拦截无法被处理。

Spring Security为了正确的区别合法的post请求,采用了token的机制:

  • 在跨域的场景下,客户端访问服务端会首先发起get请求
    • 这个get请求在到达服务端的时候,服务端的Spring security会有一个过滤 器 CsrfFilter去检查这个请求,如果这个request请求的http header里面的X-CSRF-COOKIE的token值为空的时候,服务端就好自动生成一个 token值放进这个X-CSRF-COOKIE值里面。
  • 客户端在get请求的header里面获取到这个值,再发起post请求,并将这个token值带给服务端
    • 在post请求的header里面设置_csrf属性的token值,提交的方式可以是ajax,也可以是放在form里面设置hidden 属性的标签里面提交给服务端;
  • 服务端会根据post请求里面携带的token值进行校验,如果跟服务端发送给合法客户端的token值是一样的,那么这个post请求就可以受理和处理,如果不一样或者为空,就会被拦截。
    • 由于恶意第三方可以劫持session id,而很难获取token值,所以起到了 安全的防护作用。

3. 解决方案

3.1 给postman环境中设置token

原理:在postman执行post请求前,先执行一次get请求,获取到 X-XSRF-TOKEN,放到post的header中,再执行post请求。

step1: 在Postman 中创建 Environment变量

先在 Postman 中先创建一个环境(Environment),以后的请求都基于这个环境;

再在该环境(Environment)中创建变量(如csrf-token),表示 CSRF Token 的值

step2. 创建一个 GET 请求,用来从服务端获取 CSRF Token

基于刚才的环境(Environment)创建一个 GET 请求,用来从服务端获取 token 值。注意这个请求的 Authorization tab 里面要输入用户的认证信息,在 Scripts Tab里面输入以下代码,用来从服务端的 response cookie 中取出 token 值,然后再赋给上面创建的变量。

pm.environment.set("csrf-token", decodeURIComponent(pm.cookies.get("XSRF-TOKEN")));

step3.新建 POST(或PUT/DELETE)请求,在 header 中加入 Token 值,返回给服务端

基于刚才的环境(Environment)创建待测试的 POST,PUT,DELETE 请求,在请求头 header 中加入一个X-XSRF-TOKEN的键,它的值就是token 变量的值{{xsrf-token}}

发送 token 时,headers 中 key 为什么是X-XSRF-TOKEN?这也是 Spring Security 中定义的默认值。另外 token 值也可以通过一个名为 _csrf 的隐藏域发送(通过最上面的报错信息中也可以看出)。

step4.再发送 POST,PUT,DELETE 请求时,服务端正常响应

注意:如果执行 POST,PUT,DELETE 请求时,报 token 值无效或者为空的错误,那么请先执行一下 GET 请求再试。

参考文档:在集成 Spring-Security 的环境中,使用 Postman 测试 RESTful 接口如何发送 CRSF Token

3.2 关闭csrf

spring Security 3默认关闭csrf,Spring Security 4默认启动了csrf。
如果不采用csrf,可禁用security的csrf。

修改方式:加上 .csrf().disable()即可。

@Override
protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/", "/home").permitAll()
                .and()
                .formLogin()
                .loginPage("/login").permitAll()
                .and()
                .logout().logoutUrl("/logout")
                .logoutSuccessUrl("/hello")
                .permitAll();
        http.addFilterBefore(customizeFilterSecurityInterceptor, FilterSecurityInterceptor.class)
                .csrf().disable();
}

参考文档:spring security CSRF 问题 Invalid CSRF Token 'null' was found on ......_set securitycontextholder to empty securitycontext-优快云博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值