spring.security禁止 curl post请求

wqlqzqxt  于 2021-09-30  发布在  Java
关注(0)|答案(1)|浏览(456)

我使用ssm框架开发了一个演示网站,并使用spring.security进行身份验证。我能够使用post请求登录到站点,并使用get请求获取数据。但是,我无法使用post请求添加数据。它总是被禁止的。如果csrf被禁用,则正常。我尝试过以下方法,但没有一种有效。
在标题中添加“x-csrf-token:csrf值”。
在标题中添加“\u csrf:csrf值”。
将_csrf添加到post请求正文。
那么,在启用csrf的情况下,如何使post请求工作?此外,我不确定是否需要使用不同的帖子重新生成csrf令牌。奇怪的是,登录post请求是有效的。
应用程序属性

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();
     }
 }

curl 脚本


# !/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
rqmkfv5c

rqmkfv5c1#

是否需要使用不同的POST重新生成csrf令牌
不,没有必要。
奇怪的是,登录post请求是有效的
登录后,spring.security将重新生成令牌。
那么,在启用csrf的情况下,如何使post请求工作?
关键部分是如何获取登录后生成的新csrf令牌。一种可能的解决方案是将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();
    }
}

然后,可以通过以下方式从cookie中获取csrf令牌: awk '/XSRF-TOKEN/{print $7}' cookie 并使用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

相关问题