@@ -34,7 +34,7 @@ function $HttpParamSerializerProvider() {
3434 * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D` (stringified and encoded representation of an object)
3535 *
3636 * Note that serializer will sort the request parameters alphabetically.
37- * * /
37+ */
3838
3939 this . $get = function ( ) {
4040 return function ngParamSerializer ( params ) {
@@ -101,7 +101,7 @@ function $HttpParamSerializerJQLikeProvider() {
101101 * });
102102 * ```
103103 *
104- * * /
104+ */
105105 this . $get = function ( ) {
106106 return function jQueryLikeParamSerializer ( params ) {
107107 if ( ! params ) return '' ;
@@ -258,7 +258,7 @@ function isSuccess(status) {
258258 *
259259 * @description
260260 * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
261- * * /
261+ */
262262function $HttpProvider ( ) {
263263 /**
264264 * @ngdoc property
@@ -312,7 +312,7 @@ function $HttpProvider() {
312312 * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
313313 * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
314314 *
315- ** /
315+ */
316316 var defaults = this . defaults = {
317317 // transform incoming response data
318318 transformResponse : [ defaultHttpResponseTransform ] ,
@@ -359,7 +359,7 @@ function $HttpProvider() {
359359 *
360360 * @returns {boolean|Object } If a value is specified, returns the $httpProvider for chaining.
361361 * otherwise, returns the current configured value.
362- ** /
362+ */
363363 this . useApplyAsync = function ( value ) {
364364 if ( isDefined ( value ) ) {
365365 useApplyAsync = ! ! value ;
@@ -380,9 +380,51 @@ function $HttpProvider() {
380380 * array, on request, but reverse order, on response.
381381 *
382382 * {@link ng.$http#interceptors Interceptors detailed info}
383- ** /
383+ */
384384 var interceptorFactories = this . interceptors = [ ] ;
385385
386+ /**
387+ * @ngdoc property
388+ * @name $httpProvider#xsrfWhitelistedOrigins
389+ * @description
390+ *
391+ * Array containing URLs whose origins are trusted to receive the XSRF token. See the
392+ * {@link ng.$http#security-considerations Security Considerations} sections for more details on
393+ * XSRF.
394+ *
395+ * **Note:** An "origin" consists of the [URI scheme](https://en.wikipedia.org/wiki/URI_scheme),
396+ * the [hostname](https://en.wikipedia.org/wiki/Hostname) and the
397+ * [port number](https://en.wikipedia.org/wiki/Port_(computer_networking). For `http:` and
398+ * `https:`, the port number can be omitted if using th default ports (80 and 443 respectively).
399+ * Examples: `http://example.com`, `https://api.example.com:9876`
400+ *
401+ * <div class="alert alert-warning">
402+ * It is not possible to whitelist specific URLs/paths. The `path`, `query` and `fragment` parts
403+ * of a URL will be ignored. For example, `https://foo.com/path/bar?query=baz#fragment` will be
404+ * treated as `https://foo.com`, meaning that **all** requests to URLs starting with
405+ * `https://foo.com/` will include the XSRF token.
406+ * </div>
407+ *
408+ * @example
409+ *
410+ * ```js
411+ * // App served from `https://example.com/`.
412+ * angular.
413+ * module('xsrfWhitelistedOriginsExample', []).
414+ * config(['$httpProvider', function($httpProvider) {
415+ * $httpProvider.xsrfWhitelistedOrigins.push('https://api.example.com');
416+ * }]).
417+ * run(['$http', function($http) {
418+ * // The XSRF token will be sent.
419+ * $http.get('https://api.example.com/preferences').then(...);
420+ *
421+ * // The XSRF token will NOT be sent.
422+ * $http.get('https://stats.example.com/activity').then(...);
423+ * }]);
424+ * ```
425+ */
426+ var xsrfWhitelistedOrigins = this . xsrfWhitelistedOrigins = [ ] ;
427+
386428 this . $get = [ '$browser' , '$httpBackend' , '$$cookieReader' , '$cacheFactory' , '$rootScope' , '$q' , '$injector' , '$sce' ,
387429 function ( $browser , $httpBackend , $$cookieReader , $cacheFactory , $rootScope , $q , $injector , $sce ) {
388430
@@ -406,6 +448,11 @@ function $HttpProvider() {
406448 ? $injector . get ( interceptorFactory ) : $injector . invoke ( interceptorFactory ) ) ;
407449 } ) ;
408450
451+ /**
452+ * A function to check request URLs against a list of allowed origins.
453+ */
454+ var urlIsAllowedOrigin = urlIsAllowedOriginFactory ( xsrfWhitelistedOrigins ) ;
455+
409456 /**
410457 * @ngdoc service
411458 * @kind function
@@ -762,25 +809,42 @@ function $HttpProvider() {
762809 * which the attacker can trick an authenticated user into unknowingly executing actions on your
763810 * website. AngularJS provides a mechanism to counter XSRF. When performing XHR requests, the
764811 * $http service reads a token from a cookie (by default, `XSRF-TOKEN`) and sets it as an HTTP
765- * header (`X-XSRF-TOKEN`). Since only JavaScript that runs on your domain could read the
766- * cookie, your server can be assured that the XHR came from JavaScript running on your domain.
767- * The header will not be set for cross- domain requests .
812+ * header (by default `X-XSRF-TOKEN`). Since only JavaScript that runs on your domain could read
813+ * the cookie, your server can be assured that the XHR came from JavaScript running on your
814+ * domain.
768815 *
769816 * To take advantage of this, your server needs to set a token in a JavaScript readable session
770817 * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
771- * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
772- * that only JavaScript running on your domain could have sent the request. The token must be
773- * unique for each user and must be verifiable by the server (to prevent the JavaScript from
818+ * server can verify that the cookie matches the `X-XSRF-TOKEN` HTTP header, and therefore be
819+ * sure that only JavaScript running on your domain could have sent the request. The token must
820+ * be unique for each user and must be verifiable by the server (to prevent the JavaScript from
774821 * making up its own tokens). We recommend that the token is a digest of your site's
775822 * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography))
776823 * for added security.
777824 *
778- * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
779- * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
780- * or the per-request config object.
825+ * The header will — by default — **not** be set for cross-domain requests. This
826+ * prevents unauthorized servers (e.g. malicious or compromised 3rd-party APIs) from gaining
827+ * access to your users' XSRF tokens and exposing them to Cross Site Request Forgery. If you
828+ * want to, you can whitelist additional origins to also receive the XSRF token, by adding them
829+ * to {@link ng.$httpProvider#xsrfWhitelistedOrigins xsrfWhitelistedOrigins}. This might be
830+ * useful, for example, if your application, served from `example.com`, needs to access your API
831+ * at `api.example.com`.
832+ * See {@link ng.$httpProvider#xsrfWhitelistedOrigins $httpProvider.xsrfWhitelistedOrigins} for
833+ * more details.
834+ *
835+ * <div class="alert alert-danger">
836+ * **Warning**<br />
837+ * Only whitelist origins that you have control over and make sure you understand the
838+ * implications of doing so.
839+ * </div>
840+ *
841+ * The name of the cookie and the header can be specified using the `xsrfCookieName` and
842+ * `xsrfHeaderName` properties of either `$httpProvider.defaults` at config-time,
843+ * `$http.defaults` at run-time, or the per-request config object.
781844 *
782845 * In order to prevent collisions in environments where multiple AngularJS apps share the
783- * same domain or subdomain, we recommend that each application uses unique cookie name.
846+ * same domain or subdomain, we recommend that each application uses a unique cookie name.
847+ *
784848 *
785849 * @param {object } config Object describing the request to be made and how it should be
786850 * processed. The object has following properties:
@@ -1340,7 +1404,7 @@ function $HttpProvider() {
13401404 // if we won't have the response in cache, set the xsrf headers and
13411405 // send the request to the backend
13421406 if ( isUndefined ( cachedResp ) ) {
1343- var xsrfValue = urlIsSameOrigin ( config . url )
1407+ var xsrfValue = urlIsAllowedOrigin ( config . url )
13441408 ? $$cookieReader ( ) [ config . xsrfCookieName || defaults . xsrfCookieName ]
13451409 : undefined ;
13461410 if ( xsrfValue ) {
0 commit comments