Sitelet https://github.com/angular/angular/commit/de7b2a62e7eded747c2a520c177cd41f60a96dcd
Skip to content

Commit de7b2a6

Browse files
Yenya030alxhub
authored andcommitted
fix(http): exclude withCredentials requests from transfer cache
Update the transfer cache check to safely exclude all requests sent with the `withCredentials` flag. By default, the HTTP transfer cache avoids caching user-specific responses to prevent sensitive data exposure or incorrect caching. While requests with explicit headers like `Cookie` or `Authorization` are excluded by default, requests can also be sent with credentials via the `withCredentials` flag without having those headers explicitly declared on the request object. To keep user-specific responses from being cached, exclude `withCredentials` requests unconditionally, even when the `includeRequestsWithAuthHeaders` option is set to true.
1 parent 4233188 commit de7b2a6

3 files changed

Lines changed: 26 additions & 3 deletions

File tree

‎adev/src/content/guide/ssr.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ To configure this, update your `angular.json` file as follows:
362362
You can customize how Angular caches HTTP responses during server‑side rendering (SSR) and reuses them during hydration by configuring `HttpTransferCacheOptions`.
363363
This configuration is provided globally using `withHttpTransferCacheOptions` inside `provideClientHydration()`.
364364

365-
By default, `HttpClient` caches all `HEAD` and `GET` requests which don't contain `Authorization`, `Proxy-Authorization`, or `Cookie` headers. You can override those settings by using `withHttpTransferCacheOptions` to the hydration configuration.
365+
By default, `HttpClient` caches all `HEAD` and `GET` requests which don't contain `Authorization`, `Proxy-Authorization`, or `Cookie` headers and are not sent with `withCredentials`. You can override those settings by using `withHttpTransferCacheOptions` to the hydration configuration.
366366

367367
```ts
368368
import { bootstrapApplication } from '@angular/platform-browser';
@@ -417,7 +417,7 @@ Use this only when `POST` requests are **idempotent** and safe to reuse between
417417
### `includeRequestsWithAuthHeaders`
418418

419419
Determines whether requests containing `Authorization`, `Proxy‑Authorization`, or `Cookie` headers are eligible for caching.
420-
By default, these are excluded to prevent caching user‑specific responses.
420+
By default, these are excluded to prevent caching user‑specific responses. Requests sent with `withCredentials` are also excluded by default.
421421

422422
```ts
423423
withHttpTransferCacheOptions({

‎packages/common/http/src/transfer_cache.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import {HttpParams} from './params';
4242
* (for example using GraphQL).
4343
* @param includeRequestsWithAuthHeaders Enables caching of requests containing `Authorization`,
4444
* `Proxy-Authorization`, or `Cookie` headers. By default, these requests are excluded from
45-
* caching.
45+
* caching. Requests sent using `withCredentials` are also excluded by default.
4646
*
4747
* @see [Configuring the caching options](guide/ssr#configuring-the-caching-options)
4848
*
@@ -135,6 +135,8 @@ export function transferCacheInterceptorFn(
135135
if (
136136
!isCacheActive ||
137137
requestOptions === false ||
138+
// Do not cache requests sent with credentials.
139+
req.withCredentials ||
138140
// POST requests are allowed either globally or at request level
139141
(requestMethod === 'POST' && !globalOptions.includePostRequests && !requestOptions) ||
140142
(requestMethod !== 'POST' && !ALLOWED_METHODS.includes(requestMethod)) ||

‎packages/common/http/test/transfer_cache_spec.ts‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ interface RequestParams {
4040
observe?: 'body' | 'response';
4141
transferCache?: {includeHeaders: string[]} | boolean;
4242
headers?: {[key: string]: string};
43+
withCredentials?: boolean;
4344
body?: RequestBody;
4445
}
4546

@@ -397,6 +398,16 @@ describe('TransferCache', () => {
397398
makeRequestAndExpectOne('/test-auth', 'foo');
398399
});
399400

401+
it('should not cache requests with credentials', async () => {
402+
makeRequestAndExpectOne('/test-auth', 'foo', {
403+
withCredentials: true,
404+
});
405+
406+
makeRequestAndExpectOne('/test-auth', 'foo', {
407+
withCredentials: true,
408+
});
409+
});
410+
400411
it('should cache POST with the differing body in string form', () => {
401412
makeRequestAndExpectOne('/test-1', null, {method: 'POST', transferCache: true, body: 'foo'});
402413
makeRequestAndExpectNone('/test-1', 'POST', {transferCache: true, body: 'foo'});
@@ -549,6 +560,16 @@ describe('TransferCache', () => {
549560
makeRequestAndExpectNone('/test-auth');
550561
});
551562

563+
it(`should not cache requests with credentials when 'includeRequestsWithAuthHeaders' is 'true'`, async () => {
564+
makeRequestAndExpectOne('/test-auth', 'foo', {
565+
withCredentials: true,
566+
});
567+
568+
makeRequestAndExpectOne('/test-auth', 'foo', {
569+
withCredentials: true,
570+
});
571+
});
572+
552573
it('should cache a POST request', () => {
553574
makeRequestAndExpectOne('/include?foo=1', 'post-body', {method: 'POST'});
554575

0 commit comments

Comments
 (0)