ng2从cookie中获取csrf令牌,并将其作为标头发布 [英] ng2 get csrf token from cookie post it as header
问题描述
在花了整整2天的时间在网上搜索并阅读了文档和面对相同问题的大量公开问题后,我仍然不了解Angular 2如何处理(x来源)cookie以及如何访问它们.
After spending 2 full days searching the web and reading docs and tons of open questions of people facing the same problem, i still don't grasp how Angular 2 handles the (x-origin) cookies and how to access them.
问题: 后端发送2个带有x-csrf-token&里面的JSESSIONID.我的工作是将csrf令牌保留在内存(ng2)中,并将其(仅)作为 header (不是cookie)发送回去,并将每条帖子发送到后端.
The problem: Back-end sends 2 cookies with x-csrf-token & JSESSIONID inside of it. My job is to keep the csrf token in memory (ng2) and send it (only) back as header (not cookie) with every post to the back-end.
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Access-Control-Allow-Origin: http://localhost:4200
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: Access-Control-Allow-Origin,Access-Control-Allow-Credentials
Set-Cookie: x-csrf-token=8555257a-396f-43ac-8587-c6d489e76026; Path=/app
Set-Cookie: JSESSIONID=73E38392C60370E38FBAF80143ECE212; Path=/app/; HttpOnly
Expires: Thu, 12 Apr 2018 07:49:02 GMT
Cache-Control: max-age=31536000
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 12 Apr 2017 07:49:02 GMT
我的部分解决方案: 我创建了一个自定义RequesstOptions类,该类扩展了BaseRequestOptions.添加了一些额外的标题,并将'withCredentials'设置为true.
My partial solution: I created a custom RequesstOptions class that extends the BaseRequestOptions. Added some extra headers, and set the 'withCredentials' as true.
export class MyRequestOptions extends BaseRequestOptions {
headers: Headers = new Headers({
'Accept': 'application/json',
'Content-Type': 'application/json',
});
withCredentials = true;
}
在我的HttpService中,我这样做并得到如下信息:
In my HttpService i do the post and get like so:
@Injectable()
export class HttpService {
constructor(
protected _http: Http,
protected requestOptions: RequestOptions
) { }
get(url): Observable<any> {
return this._http.get(url, this.requestOptions).map( res => res.json() );
}
post(url: string, object: any): Observable<any> {
return this._http.post(url, object, this.requestOptions).map( res => res.json() );
}
}
在我的app.module中,我像这样做魔术:
and in my app.module i do the magic like so:
providers: [
{ provide: RequestOptions, useClass: DocumentumDefaultRequestOptions },
{ provide: XSRFStrategy, useFactory: xsrfFactory }
],
我的xsrfFactory
my xsrfFactory
export function xsrfFactory() {
return new CookieXSRFStrategy('x-csrf-token', 'x-csrf-token');
}
我的部分结果: 在这一点上,angular随每个请求(不加区别地进行GET和POST)发送一个带有jsessionid和x-csrf-token的cookie,如下所示:
My partial result: At this point angular sends a cookie with every request (GET and POST without discrimination) with the jsessionid and x-csrf-token like so:
POST /app/business-objects/business-objects-type HTTP/1.1
Host: localhost:8040
Connection: keep-alive
Content-Length: 26
Pragma: no-cache
Cache-Control: no-cache
Authorization: Basic ZG1hZG1pbjphZG1pbg==
Origin: http://localhost:4200
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Content-Type: application/json
Accept: application/json
Referer: http://localhost:4200/page
Cookie: JSESSIONID=B874C9A170EFC12BEB0EDD4266896F2A; x-csrf-token=0717876e-f402-4a1c-a31a-2d60e48509d3
我的十亿美元问题:
- 如何以及在哪里访问x-csrf令牌,以及如何将其添加到我的请求中?
-
CookieXSRFStrategy('x-csrf-token', 'x-csrf-token');
的确切功能.我不喜欢黑匣子的感觉,也不了解文档解释它的方式.我可以访问它来获取数据吗?
- How and where do i access the x-csrf-token, and how do i add it to my requests?
- What does
CookieXSRFStrategy('x-csrf-token', 'x-csrf-token');
exactly do. I don't like the blackbox feeling / understand the way the docs explained it. Can i access it for data ?
在发送HTTP请求之前,CookieXSRFStrategy查找一个名为XSRF-TOKEN的cookie,并使用该cookie的值设置一个名为X-XSRF-TOKEN的标头.
Before sending an HTTP request, the CookieXSRFStrategy looks for a cookie called XSRF-TOKEN and sets a header named X-XSRF-TOKEN with the value of that cookie.
-
在我的情况下,它没有设置标题...但是为什么呢?
It doesn't set the header in my case ... but why ?
现在,我将使用sessionid和csrf令牌将cookie发送到后端,但是发送它是什么呢? CookieXSRFStrategy或'withCredentials'标志.
Right now i'm sending the cookie to the backend with the sessionid and the csrf token but what is sending it? The CookieXSRFStrategy or 'withCredentials' flag.
请不要使用像"document.cookie"之类的衬里回答.如果没有元数据,数据将毫无用处
推荐答案
更新为5.0或更高版本
为支持HttpClient
而弃用了Http
服务,也已弃用了CookieXSRFStrategy
类,现在,此任务委派给了HttpClientXsrfModule
类.如果要自定义标头和cookie名称,则只需导入该模块,如下所示:Update for angular 5.0+
Http
service beign deprecated in favor ofHttpClient
, theCookieXSRFStrategy
class has been deprecated too, now this mission is delegated to theHttpClientXsrfModule
class. If you want to customize the header and cookie names, you just need to import this module like so :@NgModule({ imports: [ HttpClientModule, HttpClientXsrfModule.withConfig({ cookieName: 'My-Xsrf-Cookie', headerName: 'My-Xsrf-Header', }), ] }) export class MyModule{}
供将来的读者使用:
Ajax响应cookie
如果您选中 XHR规范<,/a>,您将注意到禁止访问与"Set-Cookie"匹配的标头:
For future readers:
Ajax response cookies
You cannot access any cookie from any Ajax response, if you check the XHR spec, you will notice that any access to a header matching "Set-Cookie" is forbidden :
禁止的响应标头名称是标头名称,它是以下内容之一的不区分大小写的匹配项:
A forbidden response-header name is a header name that is a byte-case-insensitive match for one of:
-
Set-Cookie
-
Set-Cookie2
Set-Cookie
Set-Cookie2
但是我的cookie不是
httpOnly
对您有好处,但
httpOnly
仅声明无法通过document.cookie
访问cookie(请参阅进一步).But my cookie isn't
httpOnly
Good for you, but
httpOnly
only states that your cookie cannot be accessed viadocument.cookie
(see further).您唯一可以使用javascript访问的cookie是
document.cookie
,但document.cookie
指的是与文档一起发送的cookie (运行脚本的页面),并且不会随时被修改. MDN明确指出它引用了当前文档:The only cookies you will be able to access with javascript is
document.cookie
butdocument.cookie
refers to the cookie that has been sent with the document (the page your script is running on) and won't get modified at any time. MDN states clearly it refers to the current document:Document.cookie
获取并设置与当前文档关联的cookie.有关常规库,请参见此简单的cookie框架.
Document.cookie
Get and set the cookies associated with the current document. For a general library see this simple cookie framework.
来源: MDN
由Ajax响应设置的任何cookie不属于当前文档.
从Cookie到标题令牌的保护是一种实现方法去.请注意,您将发送的令牌在整个会话期间是相同的,并且不会根据狂野的Ajax发送cookie的请求而更改.
The cookie to header token protection is the way to go. Note that the token you will send is the same during the whole session, and it is not suposed to change according to wild Ajax requests sending cookies.
使用JavaScript进行大部分操作的Web应用程序可能会使用基于同源策略的反CSRF技术:
Web applications that use JavaScript for the majority of their operations may use an anti-CSRF technique that relies on same-origin policy:
-
登录后,Web应用程序将设置一个cookie,其中包含一个随机令牌,该令牌在整个用户会话中都保持不变
On login, the web application sets a cookie containing a random token that remains the same for the whole user session
Set-Cookie: Csrf-token=i8XNjC4b8KVok4uw5RftR38Wgp2BFwql; expires=Thu, 23-Jul-2015 10:25:33 GMT; Max-Age=31449600; Path=/
-
-
在客户端运行的JavaScript读取其值,并将其复制到随每个事务请求发送的自定义HTTP标头中
JavaScript operating on the client side reads its value and copies it into a custom HTTP header sent with each transactional request
X-Csrf-Token: i8XNjC4b8KVok4uw5RftR38Wgp2BFwql
-
服务器验证令牌的存在和完整性
The server validates presence and integrity of the token
此技术的安全性是基于这样的假设,即只有在相同起源内运行的JavaScript才能读取cookie的值.从恶意文件或电子邮件运行的JavaScript将无法读取它并将其复制到自定义标头中.即使csrf令牌cookie随恶意请求自动发送,服务器仍将期待有效的X-Csrf-Token标头.
Security of this technique is based on the assumption that only JavaScript running within the same origin will be able to read the cookie's value. JavaScript running from a rogue file or email will not be able to read it and copy into the custom header. Even though the csrf-token cookie will be automatically sent with the rogue request, the server will be still expecting a valid X-Csrf-Token header.
来源:维基百科:CSRF
对于Angular 2+,此任务由
CookieXSRFStrategy
类完成.With Angular 2+ this mission is fulfilled by the
CookieXSRFStrategy
class.如何以及在哪里访问x-csrf令牌,以及如何将其添加到我的请求中?
How and where do i access the x-csrf-token, and how do i add it to my requests?
使用
CookieXSRFStrategy
似乎是将其添加到您的请求中的方法.不幸的是,对于如何",答案可能是你做不到"(请参阅进一步).Using
CookieXSRFStrategy
seems to be the way to go to add it to your request. For the "how", unfortunately, the answer might be "you can't" (see further).CookieXSRFStrategy('x-csrf-token','x-csrf-token');是什么?完全可以.我不喜欢黑匣子的感觉,也不了解文档解释它的方式.
What does CookieXSRFStrategy('x-csrf-token', 'x-csrf-token'); exactly do. I don't like the blackbox feeling / understand the way the docs explained it.
CookieXSRFStrategy
/** * `XSRFConfiguration` sets up Cross Site Request Forgery (XSRF) protection for the application * using a cookie. See https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF) * for more information on XSRF. * * Applications can configure custom cookie and header names by binding an instance of this class * with different `cookieName` and `headerName` values. See the main HTTP documentation for more * details. * * @experimental */ export class CookieXSRFStrategy implements XSRFStrategy { constructor( private _cookieName: string = 'XSRF-TOKEN', private _headerName: string = 'X-XSRF-TOKEN') {} configureRequest(req: Request): void { const xsrfToken = getDOM().getCookie(this._cookieName); if (xsrfToken) { req.headers.set(this._headerName, xsrfToken); } } }
基本上,它从
document.cookie
中读取cookie,并相应地修改Request
标头.Basically, it reads the cookie from
document.cookie
and modify theRequest
headers accordingly.现在我正在将cookie连同sessionid和csrf令牌一起发送到后端,但是发送它的原因是什么? CookieXSRFStrategy或"withCredentials"标志.
Right now i'm sending the cookie to the backend with the sessionid and the csrf token but what is sending it? The CookieXSRFStrategy or 'withCredentials' flag.
这是
withCredentials
标志,该标志指示XHR应该发送所有已发送的cookie(甚至包括以前由Ajax响应设置的cookie,但作为cookie,而不是标头,并且有无法更改此行为)That's
withCredentials
flag, this flag indicates that the XHR should send all the cookies that have been sent (even those previously set by Ajax response, but as cookies, not headers, and there is no way to change this behavior)在我的情况下,它没有设置标题...但是为什么?
It doesn't set the header in my case ... but why ?
您正在谈论的cookie不会与文档(
index.html
)一起发送,而是从另一个ajax请求发送.事实是您无法访问由ajax响应设置的cookie(The cookie you are talking about is not sent with the document (
index.html
) but from another ajax request. The fact is you cannot access cookies set by ajax response (see this answer), because that would be a security issue: a simple ajax get onwww.stackoverflow.com
from a random web page would get the stack overflow cookie, and an attacker could steal it easily (if anAccess-Control-Allow-Origin: *
header is present on stackoverflow response).另一方面,
document.cookie
API仅可以访问在文档加载后设置的cookie,而不能访问其他任何On the other hand, the
document.cookie
API can only access to the cookies that are set when the document has been loaded, not any other.因此,您应该重新考虑服务器端的客户端/服务器通信流程,因为唯一可以复制到标头的cookie是与脚本在其上运行的文档一起发送的cookie. (index.html).
So you should rethink the flow of your client/server communication on the server-side, because the only cookie that you will be able to copy to the headers is the one that has been sent with the document your script is running on (index.html).
它不是httpOnly cookie,因此即使它是X起源,也应该可以通过js访问
it isn't a httpOnly cookie so it should be accessible with js even if it is X origin
httpOnly
使cookie无法用于document.cookie
API,但是,正如我告诉您的那样,document.cookie
指的是与文档一起发送的 cookie,而不是那些通过Ajax响应发送.您可以在响应中使用Set-Cookie
标头进行数千个ajax调用,document.cookie
仍将是相同的字符串,而无需进行任何修改.httpOnly
makes the cookie unavailable to thedocument.cookie
API, but as I told you,document.cookie
refers to the cookie that has been sent with the document, not those sent via Ajax responses. You can make thousands of ajax call with aSet-Cookie
Header in the response,document.cookie
will still be the same string, without any modification.服务器应仅发送一个包含令牌和文档的
x-csrf-token
cookie,并且对于使用CookieXSRFStrategy
的每个请求,您都应使用该令牌对整个会话有效.为什么 ?因为这就是它的工作原理.The server should only send one
x-csrf-token
cookie containing the token with the document, and you should use that token that will be valid for the whole session for every request usingCookieXSRFStrategy
. Why ? because that is how it works.这篇关于ng2从cookie中获取csrf令牌,并将其作为标头发布的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!