feat(security): strip XSSI prefix from XHR responses.
This commit is contained in:
parent
9099160038
commit
df1b1f6957
|
@ -6,11 +6,13 @@ import {Headers} from '../headers';
|
||||||
import {ResponseOptions} from '../base_response_options';
|
import {ResponseOptions} from '../base_response_options';
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from '@angular/core';
|
||||||
import {BrowserXhr} from './browser_xhr';
|
import {BrowserXhr} from './browser_xhr';
|
||||||
import {isPresent} from '../../src/facade/lang';
|
import {isPresent, isString} from '../../src/facade/lang';
|
||||||
import {Observable} from 'rxjs/Observable';
|
import {Observable} from 'rxjs/Observable';
|
||||||
import {Observer} from 'rxjs/Observer';
|
import {Observer} from 'rxjs/Observer';
|
||||||
import {isSuccess, getResponseURL} from '../http_utils';
|
import {isSuccess, getResponseURL} from '../http_utils';
|
||||||
|
|
||||||
|
const XSSI_PREFIX = ')]}\',\n';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates connections using `XMLHttpRequest`. Given a fully-qualified
|
* Creates connections using `XMLHttpRequest`. Given a fully-qualified
|
||||||
* request, an `XHRConnection` will immediately create an `XMLHttpRequest` object and send the
|
* request, an `XHRConnection` will immediately create an `XMLHttpRequest` object and send the
|
||||||
|
@ -32,13 +34,17 @@ export class XHRConnection implements Connection {
|
||||||
this.response = new Observable<Response>((responseObserver: Observer<Response>) => {
|
this.response = new Observable<Response>((responseObserver: Observer<Response>) => {
|
||||||
let _xhr: XMLHttpRequest = browserXHR.build();
|
let _xhr: XMLHttpRequest = browserXHR.build();
|
||||||
_xhr.open(RequestMethod[req.method].toUpperCase(), req.url);
|
_xhr.open(RequestMethod[req.method].toUpperCase(), req.url);
|
||||||
|
|
||||||
// load event handler
|
// load event handler
|
||||||
let onLoad = () => {
|
let onLoad = () => {
|
||||||
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
|
// responseText is the old-school way of retrieving response (supported by IE8 & 9)
|
||||||
// response/responseType properties were introduced in XHR Level2 spec (supported by
|
// response/responseType properties were introduced in XHR Level2 spec (supported by
|
||||||
// IE10)
|
// IE10)
|
||||||
let body = isPresent(_xhr.response) ? _xhr.response : _xhr.responseText;
|
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);
|
||||||
|
}
|
||||||
let headers = Headers.fromResponseHeaderString(_xhr.getAllResponseHeaders());
|
let headers = Headers.fromResponseHeaderString(_xhr.getAllResponseHeaders());
|
||||||
|
|
||||||
let url = getResponseURL(_xhr);
|
let url = getResponseURL(_xhr);
|
||||||
|
|
|
@ -273,6 +273,29 @@ export function main() {
|
||||||
existingXHRs[0].dispatchEvent('load');
|
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 prefix from errors', inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||||
|
var conn =
|
||||||
|
new XHRConnection(sampleRequest, new MockBrowserXHR(), new ResponseOptions());
|
||||||
|
conn.response.subscribe(null, (res: Response) => {
|
||||||
|
expect(res.text()).toBe('{json: "object"}');
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
existingXHRs[0].setStatusCode(404);
|
||||||
|
existingXHRs[0].setResponseText(')]}\',\n{json: "object"}');
|
||||||
|
existingXHRs[0].dispatchEvent('load');
|
||||||
|
}));
|
||||||
|
|
||||||
it('should parse response headers and add them to the response',
|
it('should parse response headers and add them to the response',
|
||||||
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
inject([AsyncTestCompleter], (async: AsyncTestCompleter) => {
|
||||||
var statusCode = 200;
|
var statusCode = 200;
|
||||||
|
|
Loading…
Reference in New Issue