-
Notifications
You must be signed in to change notification settings - Fork 27.4k
feat(http): JSONP requests now require trusted resource URLs #15143
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -379,8 +379,8 @@ function $HttpProvider() { | |
**/ | ||
var interceptorFactories = this.interceptors = []; | ||
|
||
this.$get = ['$browser', '$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector', | ||
function($browser, $httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) { | ||
this.$get = ['$browser', '$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector', '$sce', | ||
function($browser, $httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector, $sce) { | ||
|
||
var defaultCache = $cacheFactory('$http'); | ||
|
||
|
@@ -881,6 +881,12 @@ function $HttpProvider() { | |
</file> | ||
<file name="script.js"> | ||
angular.module('httpExample', []) | ||
.config(['$sceDelegateProvider', function($sceDelegateProvider) { | ||
$sceDelegateProvider.resourceUrlWhitelist([ | ||
'self', | ||
'https://angularjs.org/**' | ||
]); | ||
}]) | ||
.controller('FetchController', ['$scope', '$http', '$templateCache', | ||
function($scope, $http, $templateCache) { | ||
$scope.method = 'GET'; | ||
|
@@ -948,7 +954,7 @@ function $HttpProvider() { | |
throw minErr('$http')('badreq', 'Http request configuration must be an object. Received: {0}', requestConfig); | ||
} | ||
|
||
if (!isString(requestConfig.url)) { | ||
if (!isString($sce.valueOf(requestConfig.url))) { | ||
throw minErr('$http')('badreq', 'Http request configuration url must be a string. Received: {0}', requestConfig.url); | ||
} | ||
|
||
|
@@ -1249,12 +1255,14 @@ function $HttpProvider() { | |
cache, | ||
cachedResp, | ||
reqHeaders = config.headers, | ||
url = buildUrl(config.url, config.paramSerializer(config.params)); | ||
needsTrustedUrl = (lowercase(config.method) === 'jsonp'), | ||
url = needsTrustedUrl ? $sce.getTrustedResourceUrl(config.url) : config.url; | ||
|
||
url = buildUrl(url, config.paramSerializer(config.params)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it is simpler if all changes inside function buildUrl(url, serializedParams) {
if (serializedParams.length > 0) {
+ url = $sce.valueOf(url);
url += ((url.indexOf('?') === -1) ? '?' : '&') + serializedParams;
}
return url;
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree |
||
|
||
$http.pendingRequests.push(config); | ||
promise.then(removePendingReq, removePendingReq); | ||
|
||
|
||
if ((config.cache || defaults.cache) && config.cache !== false && | ||
(config.method === 'GET' || config.method === 'JSONP')) { | ||
cache = isObject(config.cache) ? config.cache | ||
|
@@ -1293,7 +1301,7 @@ function $HttpProvider() { | |
reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue; | ||
} | ||
|
||
$httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout, | ||
$httpBackend(config.method, needsTrustedUrl ? $sce.trustAsResourceUrl(url) : url, reqData, done, reqHeaders, config.timeout, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Slight nit, this is the first time AngularJS calls a trustAs function in the core library. That's not wrong, but it's a weird pattern: how about a parameter that will disable the check below instead? (selfish reason for that: I maintain a custom $sce that uses the Closure's implementation of safe types and disables trustAs calls, and this is going to need ad-hoc patching. That's doable, so if you'd rather keep it this way it's fine) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we are going with not securing the params then I can do a tidy refactor on this PR that removes the need for this |
||
config.withCredentials, config.responseType, | ||
createApplyHandlers(config.eventHandlers), | ||
createApplyHandlers(config.uploadEventHandlers)); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -49,17 +49,19 @@ function $xhrFactoryProvider() { | |
* $httpBackend} which can be trained with responses. | ||
*/ | ||
function $HttpBackendProvider() { | ||
this.$get = ['$browser', '$jsonpCallbacks', '$document', '$xhrFactory', function($browser, $jsonpCallbacks, $document, $xhrFactory) { | ||
return createHttpBackend($browser, $xhrFactory, $browser.defer, $jsonpCallbacks, $document[0]); | ||
this.$get = ['$sce', '$browser', '$jsonpCallbacks', '$document', '$xhrFactory', function($sce, $browser, $jsonpCallbacks, $document, $xhrFactory) { | ||
return createHttpBackend($sce, $browser, $xhrFactory, $browser.defer, $jsonpCallbacks, $document[0]); | ||
}]; | ||
} | ||
|
||
function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) { | ||
function createHttpBackend($sce, $browser, createXhr, $browserDefer, callbacks, rawDocument) { | ||
// TODO(vojta): fix the signature | ||
return function(method, url, post, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers) { | ||
url = url || $browser.url(); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why this change? Why are we implicitly allowing JSONP requests to the current URL? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I originally moved the trust check inside the second There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Couldn't we leave this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Anyway, I am hoping that we can accept that the param changes are not a security issue, in which case we can refactor the whole thing out and move the checks out from the |
||
if (lowercase(method) === 'jsonp') { | ||
// This is a pretty sensitive operation where we're allowing a script to have full access to | ||
// our DOM and JS space. So we require that the URL satisfies SCE.RESOURCE_URL. | ||
url = $sce.getTrustedResourceUrl(url) || $browser.url(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So, we are basically only allowing JSONP requests to whitelisted URLs (no support for trusting a URL "on-the-fly"). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right - documentation .... |
||
var callbackPath = callbacks.createCallback(url); | ||
var jsonpDone = jsonpReq(url, callbackPath, function(status, text) { | ||
// jsonpReq only ever sets status to 200 (OK), 404 (ERROR) or -1 (WAITING) | ||
|
@@ -69,6 +71,7 @@ function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDoc | |
}); | ||
} else { | ||
|
||
url = url || $browser.url(); | ||
var xhr = createXhr(method, url); | ||
|
||
xhr.open(method, url, true); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needsTrustedUrl is a little misleading, since you have a $sce.trustAsUrl function for another context :/ needsTrustedResourceUrl ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right thanks!