Skip to content

Commit 784e60b

Browse files
committed
Security: Always include the no-store and private directives in the Cache-Control header when setting headers that prevent caching.
The intention of these headers is to prevent any form of caching, whether that's in the browser or in an intermediate cache such as a proxy server. These directives instruct an intermediate cache to not store the response in their cache for any user – not just for logged-in users. This does not affect the caching behaviour of assets within a page such as images, CSS, and JavaScript files. Props kkmuffme, devansh2002, johnbillion. Fixes #61942 git-svn-id: https://develop.svn.wordpress.org/trunk@59724 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 1a8297e commit 784e60b

File tree

2 files changed

+26
-4
lines changed

2 files changed

+26
-4
lines changed

src/wp-includes/functions.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,18 +1489,18 @@ function status_header( $code, $description = '' ) {
14891489
* Gets the HTTP header information to prevent caching.
14901490
*
14911491
* The several different headers cover the different ways cache prevention
1492-
* is handled by different browsers.
1492+
* is handled by different browsers or intermediate caches such as proxy servers.
14931493
*
14941494
* @since 2.8.0
14951495
* @since 6.3.0 The `Cache-Control` header for logged in users now includes the
14961496
* `no-store` and `private` directives.
1497+
* @since 6.8.0 The `Cache-Control` header now includes the `no-store` and `private`
1498+
* directives regardless of whether a user is logged in.
14971499
*
14981500
* @return array The associative array of header names and field values.
14991501
*/
15001502
function wp_get_nocache_headers() {
1501-
$cache_control = ( function_exists( 'is_user_logged_in' ) && is_user_logged_in() )
1502-
? 'no-cache, must-revalidate, max-age=0, no-store, private'
1503-
: 'no-cache, must-revalidate, max-age=0';
1503+
$cache_control = 'no-cache, must-revalidate, max-age=0, no-store, private';
15041504

15051505
$headers = array(
15061506
'Expires' => 'Wed, 11 Jan 1984 05:00:00 GMT',

tests/e2e/specs/cache-control-headers-directives.test.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ test.describe( 'Cache Control header directives', () => {
2727
// Dispose context once it's no longer needed.
2828
await context.close();
2929

30+
expect( responseHeaders ).toEqual( expect.not.objectContaining( { "cache-control": "no-cache" } ) );
3031
expect( responseHeaders ).toEqual( expect.not.objectContaining( { "cache-control": "no-store" } ) );
3132
expect( responseHeaders ).toEqual( expect.not.objectContaining( { "cache-control": "private" } ) );
3233
} );
@@ -40,6 +41,27 @@ test.describe( 'Cache Control header directives', () => {
4041
const response = await page.goto( '/wp-admin' );
4142
const responseHeaders = response.headers();
4243

44+
expect( responseHeaders[ 'cache-control' ] ).toContain( 'no-cache' );
45+
expect( responseHeaders[ 'cache-control' ] ).toContain( 'no-store' );
46+
expect( responseHeaders[ 'cache-control' ] ).toContain( 'private' );
47+
} );
48+
49+
test(
50+
'Correct directives present in cache control header when not logged in on 404 page.',
51+
async ( { browser }
52+
) => {
53+
const context = await browser.newContext();
54+
const loggedOutPage = await context.newPage();
55+
56+
const response = await loggedOutPage.goto( '/this-does-not-exist/' );
57+
const responseHeaders = response.headers();
58+
const responseStatus = response.status();
59+
60+
// Dispose context once it's no longer needed.
61+
await context.close();
62+
63+
expect( responseStatus ).toBe( 404 );
64+
expect( responseHeaders[ 'cache-control' ] ).toContain( 'no-cache' );
4365
expect( responseHeaders[ 'cache-control' ] ).toContain( 'no-store' );
4466
expect( responseHeaders[ 'cache-control' ] ).toContain( 'private' );
4567
} );

0 commit comments

Comments
 (0)