Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 3192dcc

Browse filesBrowse files
arshsmith1pkozlowski-opensource
authored andcommitted
fix(http): prevent transfer cache key collisions
`makeCacheKey` joined the request fields with `|` before hashing. The url and the serialized body can contain `|` themselves, so a shifted field boundary (url `/items/a` + body `b|c` vs url `/items/a|b` + body `c`) produced the same joined string and the same key, letting two distinct requests share a transfer cache slot. Join with `\0` instead, which cannot occur in a valid url or in encoded params, so the field boundaries cannot be forged by field content.
1 parent 00699f3 commit 3192dcc
Copy full SHA for 3192dcc

2 files changed

+15-3Lines changed: 15 additions & 3 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

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

Copy file name to clipboardExpand all lines: packages/common/http/src/transfer_cache.ts
+4-1Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,10 @@ function makeCacheKey(
421421
serializedBody = '';
422422
}
423423

424-
const key = [method, responseType, mappedRequestUrl, serializedBody, encodedParams].join('|');
424+
// Joining with `|` lets a shifted field boundary (url `/a` + body `b|c` vs url `/a|b` + body `c`)
425+
// collapse to the same string and thus the same hash. `\0` cannot occur in a valid url or in
426+
// encoded params, so the field boundaries can't be forged by field content.
427+
const key = [method, responseType, mappedRequestUrl, serializedBody, encodedParams].join('\0');
425428
const hash = generateHash(key);
426429

427430
return makeStateKey(hash);
Collapse file

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

Copy file name to clipboardExpand all lines: packages/common/http/test/transfer_cache_spec.ts
+11-2Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -419,15 +419,15 @@ describe('TransferCache', () => {
419419

420420
const transferState = TestBed.inject(TransferState);
421421
expect(JSON.parse(transferState.toJson()) as Record<string, unknown>).toEqual({
422-
'2da5dfaf112523258ec9c26a0abe9a093b59ed7dbe5f43e4b5ee25a407ac9cf0': {
422+
'd501aa2d57b63a95df74e3b0558782b71b077974e968ed303cd30b27e4b70702': {
423423
[BODY]: 'foo',
424424
[HEADERS]: {},
425425
[STATUS]: 200,
426426
[STATUS_TEXT]: 'OK',
427427
[REQ_URL]: '/test-1',
428428
[RESPONSE_TYPE]: 'json',
429429
},
430-
'869485290d9385f3c0a9ba571918c335bbca9e03373bf8260d02f2b7dd335849': {
430+
'ceddc6689dc1f2fc3a0b8c364b6e00a79b99a149f27e84da87cec03d44c150c8': {
431431
[BODY]: 'buzz',
432432
[HEADERS]: {},
433433
[STATUS]: 200,
@@ -764,6 +764,15 @@ describe('TransferCache', () => {
764764
makeRequestAndExpectOne('/test-1', null, {method: 'POST', transferCache: true, body: 'bar'});
765765
});
766766

767+
it('should differentiate POST requests with an ambiguous url/body boundary', () => {
768+
// `/items/a` with body `b|c` and `/items/a|b` with body `c` are different requests, but a
769+
// cache key that concatenates the fields with `|` maps both to the same string. The second
770+
// request must be treated as a cache miss and hit the network.
771+
makeRequestAndExpectOne('/items/a', null, {method: 'POST', transferCache: true, body: 'b|c'});
772+
makeRequestAndExpectNone('/items/a', 'POST', {transferCache: true, body: 'b|c'});
773+
makeRequestAndExpectOne('/items/a|b', null, {method: 'POST', transferCache: true, body: 'c'});
774+
});
775+
767776
it('should cache POST with the differing body in object form', () => {
768777
makeRequestAndExpectOne('/test-1', null, {
769778
method: 'POST',

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.