【问题标题】:spring.security forbid curl post requestspring.security 禁止 curl 发布请求
【发布时间】:2021-09-04 08:59:24
【问题描述】:

我使用 SSM 框架开发了一个演示网站,并使用 spring.security 进行身份验证。我可以使用 post 请求登录网站并使用 get 请求获取数据。但是,我无法使用发布请求添加数据。它总是被禁止的。如果 CSRF 被禁用,就可以了。我尝试了以下方法,它们都不起作用。

  1. 将“X-CSRF-TOKEN:CSRF 值”添加到标题中。
  2. 将“_csrf:CSRF 值”添加到标题中。
  3. 将 _csrf 添加到发布请求正文。

那么如何在启用 CSRF 的情况下使发布请求工作?另外,我不确定是否需要使用不同的帖子重新生成 CSRF 令牌。奇怪的是,登录帖子请求有效。

  • application.properties

     spring.datasource.url=jdbc:mysql://localhost:3306/ssm?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
     spring.datasource.username=root
     spring.datasource.password=123456
    
     mybatis.mapper-locations=classpath:mybatis/*.xml
    
     spring.security.user.name=root
     spring.security.user.password=123456
    
     debug=true
    
  • 安全配置

     @Configuration
     public class SecurityConfig extends WebSecurityConfigurerAdapter {
     @Override
     protected void configure(HttpSecurity http) throws Exception {
         http.authorizeRequests()
                 .anyRequest().authenticated()
                 .and()
                 .formLogin().permitAll();
         }
     }
    
  • 用户控制器

     @RestController
     @RequestMapping("/rest/users")
     public class UserController {
         @Autowired
         private UserMapper userMapper;
    
         @PostMapping
         public void add(@RequestBody User user){
             userMapper.add(user);
         }
    
         @GetMapping
         public List<User> getAll(){
             return userMapper.findAll();
         }
     }
    
  • 卷曲脚本

      #!/usr/bin/env bash
    
      host=192.168.44.109:8080
      remote=http://${host}
      login=${remote}/login
      users=${remote}/rest/users/
    
      csrf=$( \
        curl --url ${login} -L -c cookie.txt 2>&1 \
        |grep _csrf \
        |sed 's/^.*value="\(.*\)".*$/\1/' \
      )
      echo "before login, csrf=${csrf}"
    
      curl --url ${login} -L -b cookie.txt -c cookie.txt -i \
          -d "username=root&password=123456&_csrf=${csrf}"
    
      curl --url ${users} -L -b cookie.txt -v \
          -H "Content-Type: application/json" \
          -H "X-CSRF-Token: ${csrf}" \
          -H "x-csrf-token: ${csrf}" \
          -H "_csrf: ${csrf}" \
          -d "{\"name\": \"name2\"}"
    
      rm -f cookie.txt
    
  • 脚本输出

     before login, csrf=6d7b2d7b-f9aa-4463-ad9b-468082df4d74
     HTTP/1.1 302 
     Set-Cookie: JSESSIONID=D728694163DEEC78DDBC8869DC54C870; Path=/; HttpOnly
     X-Content-Type-Options: nosniff
     X-XSS-Protection: 1; mode=block
     Cache-Control: no-cache, no-store, max-age=0, must-revalidate
     Pragma: no-cache
     Expires: 0
     X-Frame-Options: DENY
     Location: http://192.168.44.109:8080/
     Content-Length: 0
     Date: Sun, 20 Jun 2021 11:05:52 GMT
    
     HTTP/1.1 200 
     Vary: Origin
     Vary: Access-Control-Request-Method
     Vary: Access-Control-Request-Headers
     X-Content-Type-Options: nosniff
     X-XSS-Protection: 1; mode=block
     Cache-Control: no-cache, no-store, max-age=0, must-revalidate
     Pragma: no-cache
     Expires: 0
     X-Frame-Options: DENY
     Content-Type: application/hal+json
     Transfer-Encoding: chunked
     Date: Sun, 20 Jun 2021 11:05:52 GMT
    
     {
       "_links" : {
         "profile" : {
           "href" : "http://192.168.44.109:8080/profile"
         }
       }
     }*   Trying 192.168.44.109...
     * TCP_NODELAY set
     * Connected to 192.168.44.109 (192.168.44.109) port 8080 (#0)
     > POST /rest/users/ HTTP/1.1
     > Host: 192.168.44.109:8080
     > User-Agent: curl/7.64.1
     > Accept: */*
     > Cookie: JSESSIONID=D728694163DEEC78DDBC8869DC54C870
     > Content-Type: application/json
     > X-CSRF-Token: 6d7b2d7b-f9aa-4463-ad9b-468082df4d74
     > x-csrf-token: 6d7b2d7b-f9aa-4463-ad9b-468082df4d74
     > _csrf: 6d7b2d7b-f9aa-4463-ad9b-468082df4d74
     > Content-Length: 17
     > 
     * upload completely sent off: 17 out of 17 bytes
     < HTTP/1.1 403 
     < X-Content-Type-Options: nosniff
     < X-XSS-Protection: 1; mode=block
     < Cache-Control: no-cache, no-store, max-age=0, must-revalidate
     < Pragma: no-cache
     < Expires: 0
     < X-Frame-Options: DENY
     < Content-Type: application/json
     < Transfer-Encoding: chunked
     < Date: Sun, 20 Jun 2021 11:05:52 GMT
     < 
     * Connection #0 to host 192.168.44.109 left intact
     {"timestamp":"2021-06-20T11:05:52.540+00:00","status":403,"error":"Forbidden","message":"","path":"/rest/users/"}* Closing connection 0
    

【问题讨论】:

    标签: curl spring-security csrf csrf-token


    【解决方案1】:

    是否需要用不同的帖子重新生成 CSRF 令牌

    不,没有必要。

    奇怪的是,登录帖子请求有效

    登录后由spring.security重新生成token。

    那么如何在启用 CSRF 的情况下使发布请求工作?

    关键是如何获取登录后生成的新CSRF token。一种可能的解决方案是将 CSRF 令牌保存在 cookie 中。并且 SecurityConfig 应该改为:

    @Configuration
    public class SecurityConfig extends WebSecurityConfigurerAdapter {    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .and()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .formLogin().permitAll();
        }
    }
    

    然后,可以通过awk '/XSRF-TOKEN/{print $7}' cookie从cookie中获取csrf令牌,并使用X-XSRF-TOKEN请求头发送到服务器。完整的脚本改为:

    #!/usr/bin/env bash
    
     host=192.168.44.109:8080
     remote=http://${host}
     login=${remote}/login
     users=${remote}/rest/users/
    
     csrf(){
         awk '/XSRF-TOKEN/{print $7}' cookie
     }
    
     curl ${login} -c cookie 1> /dev/null 2>/dev/null
    
     echo "before login, csrf=$(csrf)"
     curl ${login} -d "username=root&password=123456&_csrf=$(csrf)" -b cookie -c cookie -L -i
     echo "after login, csrf=$(csrf)"
    
     name=$(date '+%Y%m%d-%H:%M:%S')
     curl ${users} -H "X-XSRF-TOKEN: $(csrf)" -H 'Content-Type: application/json' -d "{\"name\": \"${name}\"}" -b cookie -L -v
    
     rm -f cookie
    

    【讨论】:

      猜你喜欢
      • 2015-12-06
      • 2022-11-29
      • 2015-02-16
      • 2016-04-15
      • 1970-01-01
      • 2019-08-06
      • 1970-01-01
      • 2020-07-06
      • 2017-11-21
      相关资源
      最近更新 更多