Spring授权服务器response_mode=form_post触发无效CSRF令牌问题
我们在SecurityConfig中配置了两条过滤器链Bean:
- 优先级1:
oauth2ProtocolEndpointsSecurityFilterChain(授权服务器核心配置) - 优先级2:
userEndpointsSecurityFilterChain(对接外部OIDC身份提供商)
第二条链用于对接外部OIDC提供商,用户通过授权服务器登录时会被转发至外部提供商完成认证。此前功能正常,直到我们在自定义AuthorizationRequestResolver中将response_mode改为form_post(默认的query模式安全性较低),代码如下:
additionalParameters.put(RESPONSE_MODE, "form_post");
现在出现异常:外部OIDC提供商携带code值重定向回授权服务器时,触发访问拒绝。TRACE级别日志显示:
{"@timestamp":"2025-01-03T14:16:11.229589993+01:00","@version":"1","message":"Sending AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=10.131.0.2, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]] to authentication entry point since access is denied","logger_name":"org.springframework.security.web.access.ExceptionTranslationFilter","thread_name":"http-nio-8080-exec-4","level":"TRACE","level_value":5000,"stack_trace":"org.springframework.security.authorization.AuthorizationDeniedException: Access Denied\n\tat org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:99)\n\tat
进一步查看日志,发现问题根源是CSRF校验失败:
Invalid CSRF token found for https://nettskjema-authorization-dev.uio.no/login/oauth2/code/idporten
我们尝试完全禁用CSRF,将配置从: ```java .csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher))
替换为:
.csrf(csrf -> csrf.disable())
但无效CSRF令牌错误依然存在。
通过DevTools调试,获取到外部IdP发送的POST请求(简化为Curl命令):
curl 'https://nettskjema-authorization-dev.uio.no/login/oauth2/code/idporten' --compressed -X POST -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:133.0) Gecko/20100101 Firefox/133.0' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' -H 'Accept-Language: no,en;q=0.7,en-US;q=0.3' -H 'Accept-Encoding: gzip, deflate, br, zstd' -H 'Content-Type: application/x-www-form-urlencoded' -H 'Origin: https://login.test.idporten.no' -H 'DNT: 1' -H 'Sec-GPC: 1' -H 'Connection: keep-alive' -H 'Referer: https://login.test.idporten.no/' -H 'Upgrade-Insecure-Requests: 1' -H 'Sec-Fetch-Dest: document' -H 'Sec-Fetch-Mode: navigate' -H 'Sec-Fetch-Site: cross-site' -H 'Priority: u=0, i' --data-raw 'iss=https%3A%2F%2Ftest.idporten.no&code=******&state=*******'
值得注意的是,普通Spring应用(非Spring授权服务器)中使用response_mode=form_post一切正常,但在Spring授权服务器中注册的OIDC客户端却无法正常工作。
内容的提问来源于stack exchange,提问作者Erlend Garåsen

