我正在编写一个带有 Svelte 前端和 Spring Boot 3 后端(版本“3.0.6”)的应用程序。
我阅读了有关针对 BREACH 攻击的新保护措施,并应用了 Spring Security 的新配置。
在我的前端,在发送任何 POST 请求之前,我读取
XSRF-TOKEN
cookie 的值,并将该值复制到标头 X-XSRF-TOKEN
。
通过调试代码,我可以看到
CsrfFilter
能够从标头中提取令牌值。
不幸的是,接收两个相同字符串作为输入的方法
XorCsrfTokenRequestAttributeHandler::getTokenValue
返回null
。鉴于输入完全由我的客户端发送的内容定义,我想我必须先转换 XSRF-TOKEN
值,然后再将其复制到标头 X-XSRF-TOKEN
。
方法代码为:
// example call: actualToken = token = "b4b40051-9f64-4d8e-9092-cc84cc769ae0"
private static String getTokenValue(String actualToken, String token) {
byte[] actualBytes;
try {
actualBytes = Base64.getUrlDecoder().decode(actualToken);
}
catch (Exception ex) {
return null;
}
byte[] tokenBytes = Utf8.encode(token);
int tokenSize = tokenBytes.length;
if (actualBytes.length < tokenSize) {
// 24 < 36 so we arrive here
return null;
}
// extract token and random bytes
int randomBytesSize = actualBytes.length - tokenSize;
byte[] xoredCsrf = new byte[tokenSize];
byte[] randomBytes = new byte[randomBytesSize];
System.arraycopy(actualBytes, 0, randomBytes, 0, randomBytesSize);
System.arraycopy(actualBytes, randomBytesSize, xoredCsrf, 0, tokenSize);
byte[] csrfBytes = xorCsrf(randomBytes, xoredCsrf);
return Utf8.decode(csrfBytes);
}
当一切顺利时,该方法应该返回与“token”相同的值,并且调用
equalsConstantTime(csrfToken.getToken(), actualToken)
返回true
,其中actualToken
是上述方法的返回值。
那么,在将 cookie 的值
XSRF-TOKEN
复制到标头 X-XSRF-TOKEN
之前,我应该对它做什么?
我在这里找到了解决方案:
基本上,JavaScript 客户端根本不需要与 cookie 进行交互。相反,服务器可以定义端点
@GetMapping("/csrf")
public CsrfToken csrfToken(CsrfToken csrfToken) {
return csrfToken;
}
例如返回:
{
"parameterName":"_csrf",
"token":"pKpetTa2tv6yhmnko7ZvtaiP7CgX8cB5uBbR1G-ZR6NiKTpIkcltgALX0J-fslyGkJtbgpG_wRFxl_VUgCDm513_dMVUGQ15",
"headerName":"X-XSRF-TOKEN"
}
连同 cookie 中相应的原始令牌,浏览器将自动转发。
我无权添加评论。因此我被迫在这里发布我的问题。
我在 Spring 中使用 CookieCsrfTokenRepository 并返回带有令牌的 cookie。我使用 JS 从 cookie 中检索令牌并将其发送到 Ajax POST 请求的标头中,如下所示。 标头:{ 'X-XSRF-TOKEN': csrfToken }
我遇到了阿德里安提到的同样的问题。虽然我理解提供的解决方案,但我无法理解为什么 XorCsrfTokenRequestAttributeHandler 没有解码请求标头中的 X-XSRF-TOKEN 值。下面的文档说 XorCsrfTokenRequestAttributeHandler 是 Spring security 6.0 中的默认设置。我也尝试明确添加它,但它不起作用。
我使用了 CsrfTokenRequestAttributeHandler 并且它有效,但只有当我们想选择退出 BREACH 时才应使用 CsrfTokenRequestAttributeHandler。
我可以像 Adrien 所说的那样使用 /csrf 端点,但是 Spring security 将 XSRF-TOKEN cookie 返回到浏览器有什么意义呢?