Fetch, set-cookies and csrf (Cross-Site Request Forgery)
Fetch, set-cookies and csrf (Cross-Site Request Forgery)
我在我的应用程序中使用了Isomorphic fetch,并且在处理CSRF时遇到了一些问题。
实际上,我有一个后端,在set-cookies属性中向我发送了一个CSRF-TOKEN:
我在某个地方读到过,直接在我的代码中访问这种cookie是不可能的,或者是一种不好的做法。
因此,我尝试使用fetch请求的credentials属性来做些什么:
const headers = new Headers({ 'Content-Type': 'x-www-form-urlencoded' }); return this.fetcher(url, { method: 'POST', headers, credentials: 'include', body: JSON.stringify({ email: 'mail@mail.fr', password: 'password' }) });
这样,我可以将我的CSRF cookie发送回服务器以满足我的需求(这是一个不同的请求,因为它不是同一个请求):
我的问题
我的问题是,我的后端需要接收一个x-csrf-token头,所以我不能将其设置为我的POST请求。
我需要什么
我该如何将set-cookies: CSRF-TOKEN的值放入下一个请求的x-csrf-token头中?
Fetch, set-cookies和CSRF问题的出现原因和解决方法
当使用Fetch API进行网络请求时,有时会遇到一些问题,这些问题涉及到设置cookies和CSRF(Cross-Site Request Forgery)令牌。这些问题可能会导致请求无法成功发送或者被服务器拒绝。
原因:
1. Cookies的问题:在使用Fetch API发送请求时,默认情况下不会包含任何cookies。这是因为Fetch API的设计初衷是通过现代的Web标准来处理网络请求,而不是通过传统的cookies机制。因此,如果服务器要求在请求中携带cookies,可能会导致请求失败。
2. CSRF令牌的问题:CSRF是一种跨站请求伪造攻击,它利用了Web应用程序中的漏洞,使攻击者能够以受害者的身份执行非法操作。为了防止CSRF攻击,Web应用程序通常会在每个请求中包含一个CSRF令牌。然而,使用Fetch API时,默认情况下不会自动发送CSRF令牌,这可能导致请求被服务器拒绝。
解决方法:
1. 设置cookies:要在Fetch请求中携带cookies,可以使用Fetch API提供的credentials属性来进行配置。credentials属性有三个可能的值:omit、same-origin和include。默认值是omit,表示不包含任何cookies。如果要发送请求时包含cookies,可以将credentials属性设置为include。
fetch(url, { credentials: 'include', // 其他请求参数 })
2. 设置CSRF令牌:要在Fetch请求中包含CSRF令牌,可以通过设置请求头来实现。在请求头中添加X-CSRFToken字段,并将其值设置为CSRF令牌的值。具体的设置方法取决于服务器的要求,以Django为例,可以在Fetch请求的headers中添加X-CSRFToken字段,并将其值设置为获取CSRF令牌的方法。
fetch(url, { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json; charset=UTF-8', 'X-CSRFToken': get_token }, // 其他请求参数 })
通过以上的解决方法,可以解决使用Fetch API时遇到的cookies和CSRF问题,确保请求能够成功发送并得到正确的响应。
在这种情况下,您应该从CSRF-TOKEN cookie中读取数据。否则,它将被标记为HttpOnly,例如JSESSIONID。后者意味着您无法从网页中访问它,只能自动发送回服务器。通常从cookie中读取CSRF令牌是没有问题的。请参考这个很好的讨论:为什么通常将CSRF预防令牌放在cookie中?
您可以使用以下代码读取cookie(不包括HttpOnly):
function getCookie(name) { if (!document.cookie) { return null; } const xsrfCookies = document.cookie.split(';') .map(c => c.trim()) .filter(c => c.startsWith(name + '=')); if (xsrfCookies.length === 0) { return null; } return decodeURIComponent(xsrfCookies[0].split('=')[1]); }
因此,fetch调用可能如下所示:
const csrfToken = getCookie('CSRF-TOKEN'); const headers = new Headers({ 'Content-Type': 'x-www-form-urlencoded', 'X-CSRF-TOKEN': csrfToken }); return this.fetcher(url, { method: 'POST', headers, credentials: 'include', body: JSON.stringify({ email: 'test.com', password: 'password' }) });
请修复打字错误:X-XSRF-TOKEN应该是X-CSRF-TOKEN,标头名称取决于服务器端,实际上可以是X-CSRF-TOKEN或X-XSRF-TOKEN,或者有一些自定义名称。