首页 文章

ng2从cookie获取csrf令牌将其作为 Headers 发布

提问于
浏览
7

在花了整整两天的时间搜索网络并阅读文档和大量面临同样问题的人的开放性问题之后,我仍然不了解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 回答

  • 17

    更新角度5.0

    Http 服务beign不赞成使用 HttpClientCookieXSRFStrategy 类也已弃用,现在此任务被委托给 HttpClientXsrfModule 类 . 如果要自定义 Headers 和cookie名称,只需要像这样导入此模块:

    @NgModule({
      imports: [
        HttpClientModule,
        HttpClientXsrfModule.withConfig({
          cookieName: 'My-Xsrf-Cookie',
          headerName: 'My-Xsrf-Header',
        }),
      ]
    })
    export class MyModule{}
    

    对于未来的读者:

    Ajax响应cookie

    您无法从任何Ajax响应中访问任何cookie,如果您选中the XHR spec,您会注意到禁止访问与"Set-Cookie"匹配的标头:

    禁止响应标头名称是 Headers 名称,它是以下之一的字节大小写不匹配:Set-Cookie Set-Cookie2

    但我的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明确指出它涉及当前的文件:

    Document.cookie获取并设置与当前文档关联的cookie . 对于通用库,请参阅此简单的cookie框架 .

    资料来源: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 .

    在大多数操作中使用JavaScript的Web应用程序可能会使用依赖于同源策略的反CSRF技术:在登录时,Web应用程序会设置一个包含随机令牌的cookie,该令牌对于整个用户会话Set保持不变-Cookie:Csrf-token = i8XNjC4b8KVok4uw5RftR38Wgp2BFwql; expires =星期四,23-Jul-2015 10:25:33 GMT;最大年龄= 31449600;路径= /
    在客户端运行的JavaScript读取其值并将其复制到随每个事务请求发送的自定义HTTP头中X-Csrf-Token:i8XNjC4b8KVok4uw5RftR38Wgp2BFwql
    服务器验证令牌的存在性和完整性此技术的安全性基于以下假设:只有在同一来源中运行的JavaScript才能读取cookie的值 . 从流氓文件或电子邮件运行的JavaScript将无法读取它并复制到自定义标头中 . 即使csrf-token cookie将与恶意请求一起自动发送,服务器仍然期望有效的X-Csrf-Token标头 .

    资料来源:Wikipedia : CSRF

    通过Angular 2,这个任务由 CookieXSRFStrategy 课程完成 .

    原始答案

    我如何以及在何处访问x-csrf-token,以及如何将其添加到我的请求中?

    使用 CookieXSRFStrategy 似乎是将其添加到您的请求的方式 . 对于"how",不幸的是,答案可能是"you can't"(见进一步说明) .

    什么CookieXSRFStrategy('x-csrf-token','x-csrf-token');确切地说 . 我不喜欢黑盒子感觉/理解文档解释它的方式 .

    CookieXSRFStrategy

    / **
    *XSRFConfiguration为应用程序设置跨站点请求伪造(XSRF)保护
    *使用cookie . 请参阅https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)
    *有关XSRF的更多信息 .

    *应用程序可以通过绑定此类的实例来配置自定义cookie和标头名称
    *使用不同的cookieNameheaderName值 . 有关更多信息,请参阅主要HTTP文档

    • 细节 .
    • @experimental
    • /
      导出类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 标头 .

    现在我正在使用sessionid和csrf令牌将cookie发送到后端,但发送的是什么? CookieXSRFStrategy或'withCredentials'标志 .

    那是 withCredentials 标志,这个标志表示XHR应该发送所有已发送的cookie(即使是之前由Ajax响应设置的那些,但是 as cookies, not headers ,并且没有办法改变这种行为)

    它没有在我的情况下设置 Headers ...但为什么?

    您正在讨论的cookie不会随文档( index.html )一起发送,而是与另一个ajax请求一起发送 . 事实是你无法访问由ajax响应(see this answer)设置的cookie,因为这将是一个安全问题:来自随机网页的简单ajax get www.stackoverflow.com 将获得堆栈溢出cookie,攻击者可以轻松窃取它(如果stackoverflow响应中存在 Access-Control-Allow-Origin: * 标头) .

    另一方面, document.cookie API只能访问加载文档时设置的cookie,而不能访问任何其他cookie .

    因此,您应该重新考虑服务器端的客户端/服务器通信流,因为您将能够复制到标头的唯一cookie是与脚本运行的文档一起发送的cookie(索引) . HTML) .

    它不是一个httpOnly cookie,所以它应该可以用js访问,即使它是X原点

    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 .

  • 0

    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 命名,那么你也可以这样做:

    imports: [
      HttpClientModule,
      HttpClientXsrfModule.withConfig({
        cookieName: 'My-Xsrf-Cookie',
        headerName: 'My-Xsrf-Header',
      }),
    ]
    

    如果您使用的是Spring安全性,它支持角度命名约定,因此您可以配置此服务器端:

    @Configuration
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                .and()
                .authorizeRequests()
                ....
    

相关问题