From 729dc3b764993d422bda4d0a38418637d0d1daeb Mon Sep 17 00:00:00 2001 From: Martin Probst Date: Wed, 8 Jun 2016 20:50:58 -0700 Subject: [PATCH] fix(security): support XSSI prefixes with and without commas. Some implementations use an XSSI prefix with a trailing comma, some without. This changes Angular to support both. --- modules/@angular/http/src/backends/xhr_backend.ts | 6 ++---- .../@angular/http/test/backends/xhr_backend_spec.ts | 13 ++++++++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/modules/@angular/http/src/backends/xhr_backend.ts b/modules/@angular/http/src/backends/xhr_backend.ts index b261c89188..f4c6dc4ce1 100644 --- a/modules/@angular/http/src/backends/xhr_backend.ts +++ b/modules/@angular/http/src/backends/xhr_backend.ts @@ -13,7 +13,7 @@ import {Observable} from 'rxjs/Observable'; import {Observer} from 'rxjs/Observer'; import {isSuccess, getResponseURL} from '../http_utils'; -const XSSI_PREFIX = ')]}\',\n'; +const XSSI_PREFIX = /^\)\]\}',?\n/; /** * Creates connections using `XMLHttpRequest`. Given a fully-qualified @@ -46,9 +46,7 @@ export class XHRConnection implements Connection { // IE10) let body = isPresent(_xhr.response) ? _xhr.response : _xhr.responseText; // Implicitly strip a potential XSSI prefix. - if (isString(body) && body.startsWith(XSSI_PREFIX)) { - body = body.substring(XSSI_PREFIX.length); - } + if (isString(body)) body = body.replace(XSSI_PREFIX, ''); let headers = Headers.fromResponseHeaderString(_xhr.getAllResponseHeaders()); let url = getResponseURL(_xhr); diff --git a/modules/@angular/http/test/backends/xhr_backend_spec.ts b/modules/@angular/http/test/backends/xhr_backend_spec.ts index 016221f76d..71c6dbbe10 100644 --- a/modules/@angular/http/test/backends/xhr_backend_spec.ts +++ b/modules/@angular/http/test/backends/xhr_backend_spec.ts @@ -472,6 +472,17 @@ export function main() { existingXHRs[0].dispatchEvent('load'); })); + it('should strip XSSI prefixes', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { + var conn = new XHRConnection(sampleRequest, new MockBrowserXHR(), new ResponseOptions()); + conn.response.subscribe((res: Response) => { + expect(res.text()).toBe('{json: "object"}'); + async.done(); + }); + existingXHRs[0].setStatusCode(200); + existingXHRs[0].setResponseText(')]}\'\n{json: "object"}'); + existingXHRs[0].dispatchEvent('load'); + })); + it('should strip XSSI prefixes', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => { var conn = new XHRConnection(sampleRequest, new MockBrowserXHR(), new ResponseOptions()); conn.response.subscribe((res: Response) => { @@ -491,7 +502,7 @@ export function main() { async.done(); }); existingXHRs[0].setStatusCode(404); - existingXHRs[0].setResponseText(')]}\',\n{json: "object"}'); + existingXHRs[0].setResponseText(')]}\'\n{json: "object"}'); existingXHRs[0].dispatchEvent('load'); }));