在花了整整两天的时间搜索网络并阅读文档和大量面临同样问题的人的开放性问题之后,我仍然不了解Angular 2如何处理(x-origin)cookie以及如何访问它们 .
The problem: 后端发送2个带有x-csrf-token和JSESSIONID的cookie . 我的工作是将csrf令牌保留在内存(ng2)中并将其(仅)发送回 header (不是cookie),每个帖子都发送到后端 .
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
My partial solution: 我创建了一个扩展BaseRequestOptions的自定义RequesstOptions类 . 添加了一些额外的标头,并将'withCredentials'设置为true .
export class MyRequestOptions extends BaseRequestOptions {
headers: Headers = new Headers({
'Accept': 'application/json',
'Content-Type': 'application/json',
});
withCredentials = true;
}
在我的HttpService中我做了帖子并得到如下:
@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中我做了这样的魔术:
providers: [
{ provide: RequestOptions, useClass: DocumentumDefaultRequestOptions },
{ provide: XSRFStrategy, useFactory: xsrfFactory }
],
我的xsrfFactory
export function xsrfFactory() {
return new CookieXSRFStrategy('x-csrf-token', 'x-csrf-token');
}
My partial result: 此时,角度会发送一个cookie,其中包含jsessionid和x-csrf-token等每个请求(GET和POST无歧视):
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
My billion dollar questions:
-
我如何以及在何处访问x-csrf-token,以及如何将其添加到我的请求中?
-
CookieXSRFStrategy('x-csrf-token', 'x-csrf-token');
究竟做了什么 . 我不喜欢黑盒子感觉/理解文档解释它的方式 . 我可以访问数据吗?
在发送HTTP请求之前,CookieXSRFStrategy会查找名为XSRF-TOKEN的cookie,并使用该cookie的值设置名为X-XSRF-TOKEN的标头 .
-
它没有在我的情况下设置 Headers ...但为什么?
-
现在我正在使用sessionid和csrf令牌将cookie发送到后端,但发送的是什么? CookieXSRFStrategy或'withCredentials'标志 .
请不要回答像"document.cookie"这样的一个班轮 . 没有元数据,数据就毫无用处
2 回答
更新角度5.0
Http
服务beign不赞成使用HttpClient
,CookieXSRFStrategy
类也已弃用,现在此任务被委托给HttpClientXsrfModule
类 . 如果要自定义 Headers 和cookie名称,只需要像这样导入此模块:对于未来的读者:
Ajax响应cookie
您无法从任何Ajax响应中访问任何cookie,如果您选中the XHR spec,您会注意到禁止访问与"Set-Cookie"匹配的标头:
但我的cookie不是httpOnly
对你有好处,但是
httpOnly
只表明你的cookie无法通过document.cookie
访问(见进一步说明) .document.cookie API
您将能够使用javascript访问的唯一cookie是
document.cookie
,但document.cookie
指的是 the cookie that has been sent with the document (您的脚本正在运行的页面)和 won't get modified at any time . MDN明确指出它涉及当前的文件:资料来源:MDN
由Ajax响应设置的任何cookie都不属于当前文档 .
如何实现我的csrf保护呢?
cookie to header token protection是要走的路 . 请注意 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 .
资料来源:Wikipedia : CSRF
通过Angular 2,这个任务由
CookieXSRFStrategy
课程完成 .原始答案
使用
CookieXSRFStrategy
似乎是将其添加到您的请求的方式 . 对于"how",不幸的是,答案可能是"you can't"(见进一步说明) .CookieXSRFStrategy
*应用程序可以通过绑定此类的实例来配置自定义cookie和标头名称
*使用不同的
cookieName
和headerName
值 . 有关更多信息,请参阅主要HTTP文档导出类CookieXSRFStrategy实现XSRFStrategy {
构造函数(
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);
}
}
}
Source
基本上,它从
document.cookie
读取cookie并相应地修改Request
标头 .那是
withCredentials
标志,这个标志表示XHR应该发送所有已发送的cookie(即使是之前由Ajax响应设置的那些,但是 as cookies, not headers ,并且没有办法改变这种行为)您正在讨论的cookie不会随文档(
index.html
)一起发送,而是与另一个ajax请求一起发送 . 事实是你无法访问由ajax响应(see this answer)设置的cookie,因为这将是一个安全问题:来自随机网页的简单ajax getwww.stackoverflow.com
将获得堆栈溢出cookie,攻击者可以轻松窃取它(如果stackoverflow响应中存在Access-Control-Allow-Origin: *
标头) .另一方面,
document.cookie
API只能访问加载文档时设置的cookie,而不能访问任何其他cookie .因此,您应该重新考虑服务器端的客户端/服务器通信流,因为您将能够复制到标头的唯一cookie是与脚本运行的文档一起发送的cookie(索引) . HTML) .
httpOnly
使得cookie对document.cookie
API不可用, but 正如我告诉你的那样,document.cookie
指的是 cookie that has been sent with the document, not those sent via Ajax responses . 您可以在响应中使用Set-Cookie
标头进行数千个ajax调用,document.cookie
仍然是相同的字符串,不做任何修改 ._0003亿美元的解决方案
服务器应该只发送一个包含该文档的令牌的
x-csrf-token
cookie,并且您应该使用对于使用CookieXSRFStrategy
的每个请求对整个会话有效的令牌 . 为什么?因为that is how it works .Angular has built in support for XSRF 见这里:https://angular.io/guide/http#security-xsrf-protection
"When performing HTTP requests, an interceptor reads a token from a cookie, by default XSRF-TOKEN, and sets it as an HTTP header, X-XSRF-TOKEN"
因此,如果您的服务器设置名为XSRF-TOKEN的cookie,那么 it will work automatically! 无需在客户端执行任何操作 . 如果你想为你的cookie / Headers 命名,那么你也可以这样做:
如果您使用的是Spring安全性,它支持角度命名约定,因此您可以配置此服务器端: