Our investigations have shown us that not all browsers respect the HTTP cache directives in a uniform manner.
For security reasons we do not want certain pages in our application to be cached, ever, by the web browser. This must work for at least the following browsers:
Our requirement came from a security test. After logging out from our website you could press the back button and view cached pages.
The correct minimum set of headers that works across all mentioned clients (and proxies):
Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache
Expires: 0
The Cache-Control
is per the HTTP 1.1 spec for clients and proxies (and implicitly required by some clients next to Expires
). The Pragma
is per the HTTP 1.0 spec for prehistoric clients. The Expires
is per the HTTP 1.0 and 1.1 specs for clients and proxies. In HTTP 1.1, the Cache-Control
takes precedence over Expires
, so it's after all for HTTP 1.0 proxies only.
If you don't care about IE6 and its broken caching when serving pages over HTTPS with only no-store
, then you could omit Cache-Control: no-cache
.
Cache-Control: no-store, must-revalidate
Pragma: no-cache
Expires: 0
If you don't care about IE6 nor HTTP 1.0 clients (HTTP 1.1 was introduced in 1997), then you could omit Pragma
.
Cache-Control: no-store, must-revalidate
Expires: 0
If you don't care about HTTP 1.0 proxies either, then you could omit Expires
.
Cache-Control: no-store, must-revalidate
On the other hand, if the server auto-includes a valid Date
header, then you could theoretically omit Cache-Control
too and rely on Expires
only.
Date: Wed, 24 Aug 2016 18:32:02 GMT
Expires: 0
But that may fail if e.g. the end-user manipulates the operating system date and the client software is relying on it.
Other Cache-Control
parameters such as max-age
are irrelevant if the abovementioned Cache-Control
parameters are specified. The Last-Modified
header as included in most other answers here is only interesting if you actually want to cache the request, so you don't need to specify it at all.
Using PHP:
header("Cache-Control: no-cache, no-store, must-revalidate"); // HTTP 1.1.
header("Pragma: no-cache"); // HTTP 1.0.
header("Expires: 0"); // Proxies.
Using Java Servlet, or Node.js:
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setHeader("Expires", "0"); // Proxies.
Using ASP.NET-MVC
Response.Cache.SetCacheability(HttpCacheability.NoCache); // HTTP 1.1.
Response.Cache.AppendCacheExtension("no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache"); // HTTP 1.0.
Response.AppendHeader("Expires", "0"); // Proxies.
Using ASP.NET Web API:
// `response` is an instance of System.Net.Http.HttpResponseMessage
response.Headers.CacheControl = new CacheControlHeaderValue
{
NoCache = true,
NoStore = true,
MustRevalidate = true
};
response.Headers.Pragma.ParseAdd("no-cache");
// We can't use `response.Content.Headers.Expires` directly
// since it allows only `DateTimeOffset?` values.
response.Content?.Headers.TryAddWithoutValidation("Expires", 0.ToString());
Using ASP.NET:
Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
Response.AppendHeader("Pragma", "no-cache"); // HTTP 1.0.
Response.AppendHeader("Expires", "0"); // Proxies.
Using ASP.NET Core v3
// using Microsoft.Net.Http.Headers
Response.Headers[HeaderNames.CacheControl] = "no-cache, no-store, must-revalidate";
Response.Headers[HeaderNames.Expires] = "0";
Response.Headers[HeaderNames.Pragma] = "no-cache";
Using ASP:
Response.addHeader "Cache-Control", "no-cache, no-store, must-revalidate" ' HTTP 1.1.
Response.addHeader "Pragma", "no-cache" ' HTTP 1.0.
Response.addHeader "Expires", "0" ' Proxies.
Using Ruby on Rails:
headers["Cache-Control"] = "no-cache, no-store, must-revalidate" # HTTP 1.1.
headers["Pragma"] = "no-cache" # HTTP 1.0.
headers["Expires"] = "0" # Proxies.
Using Python/Flask:
response = make_response(render_template(...))
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate" # HTTP 1.1.
response.headers["Pragma"] = "no-cache" # HTTP 1.0.
response.headers["Expires"] = "0" # Proxies.
Using Python/Django:
response["Cache-Control"] = "no-cache, no-store, must-revalidate" # HTTP 1.1.
response["Pragma"] = "no-cache" # HTTP 1.0.
response["Expires"] = "0" # Proxies.
Using Python/Pyramid:
request.response.headerlist.extend(
(
('Cache-Control', 'no-cache, no-store, must-revalidate'),
('Pragma', 'no-cache'),
('Expires', '0')
)
)
Using Go:
responseWriter.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") // HTTP 1.1.
responseWriter.Header().Set("Pragma", "no-cache") // HTTP 1.0.
responseWriter.Header().Set("Expires", "0") // Proxies.
Using Clojure (require Ring utils):
(require '[ring.util.response :as r])
(-> response
(r/header "Cache-Control" "no-cache, no-store, must-revalidate")
(r/header "Pragma" "no-cache")
(r/header "Expires" 0))
Using Apache .htaccess
file:
<IfModule mod_headers.c>
Header set Cache-Control "no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires 0
</IfModule>
Using HTML:
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
Important to know is that when an HTML page is served over an HTTP connection, and a header is present in both the HTTP response headers and the HTML <meta http-equiv>
tags, then the one specified in the HTTP response header will get precedence over the HTML meta tag. The HTML meta tag will only be used when the page is viewed from a local disk file system via a file://
URL. See also W3 HTML spec chapter 5.2.2. Take care with this when you don't specify them programmatically because the webserver can namely include some default values.
Generally, you'd better just not specify the HTML meta tags to avoid confusion by starters and rely on hard HTTP response headers. Moreover, specifically those <meta http-equiv>
tags are invalid in HTML5. Only the http-equiv
values listed in HTML5 specification are allowed.
To verify the one and the other, you can see/debug them in the HTTP traffic monitor of the web browser's developer toolset. You can get there by pressing F12 in Chrome/Firefox23+/IE9+, and then opening the "Network" or "Net" tab panel, and then clicking the HTTP request of interest to uncover all detail about the HTTP request and response. The below screenshot is from Chrome:
First of all, this question and answer are targeted on "web pages" (HTML pages), not "file downloads" (PDF, zip, Excel, etc). You'd better have them cached and make use of some file version identifier somewhere in the URI path or query string to force a redownload on a changed file. When applying those no-cache headers on file downloads anyway, then beware of the IE7/8 bug when serving a file download over HTTPS instead of HTTP. For detail, see IE cannot download foo.jsf. IE was not able to open this internet site. The requested site is either unavailable or cannot be found.
Answered 2023-09-21 08:09:16
(hey, everyone: please don't just mindlessly copy&paste all headers you can find)
First of all, Back button history is not a cache:
The freshness model (Section 4.2) does not necessarily apply to history mechanisms. That is, a history mechanism can display a previous representation even if it has expired.
In the old HTTP spec, the wording was even stronger, explicitly telling browsers to disregard cache directives for back button history.
Back is supposed to go back in time (to the time when the user was logged in). It does not navigate forward to a previously opened URL.
However, in practice, the cache can influence the back button, in very specific circumstances:
Cache-Control: no-store, must-revalidate
(some browsers observe no-store
and some observe must-revalidate
)You never need any of:
<meta>
with cache headers — it doesn't work at all. Totally useless.post-check
/pre-check
— it's an IE-only directive that only applies to cachable resources.If you want, you could add:
no-cache
or max-age=0
, which will make resource (URL) "stale" and require browsers to check with the server if there's a newer version (no-store
already implies this even stronger).Expires
with a date in the past for HTTP/1.0 clients (although real HTTP/1.0-only clients are completely non-existent these days).Bonus: The new HTTP caching RFC.
Answered 2023-09-21 08:09:16
Cache-Control: must-revalidate
. Why not send Cache-Control: no-cache
since no-cache
already implies must-revalidate
? w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1 - anyone no-cache
with must-revalidate
is true for cache, but back history is not a cache. Browsers special-case explicit must-revalidate
to control history behavior. - anyone As @Kornel stated, what you want is not to deactivate the cache, but to deactivate the history buffer. Different browsers have their own subtle ways to disable the history buffer.
In Chrome (v28.0.1500.95 m) we can do this only by Cache-Control: no-store
.
In FireFox (v23.0.1) any one of these will work:
Cache-Control: no-store
Cache-Control: no-cache
(https only)
Pragma: no-cache
(https only)
Vary: *
(https only)
In Opera (v12.15) we only can do this by Cache-Control: must-revalidate
(https only).
In Safari (v5.1.7, 7534.57.2) any one of these will work:
Cache-Control: no-store
<body onunload="">
in html
Cache-Control: no-store
(https only)
In IE8 (v8.0.6001.18702IC) any one of these will work:
Cache-Control: must-revalidate, max-age=0
Cache-Control: no-cache
Cache-Control: no-store
Cache-Control: must-revalidate
Expires: 0
Cache-Control: must-revalidate
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
(https only)
Vary: *
(https only)
Combining the above gives us this solution which works for Chrome 28, FireFox 23, IE8, Safari 5.1.7, and Opera 12.15: Cache-Control: no-store, must-revalidate
(https only)
Note that https is needed because Opera wouldn't deactivate history buffer for plain http pages. If you really can't get https and you are prepared to ignore Opera, the best you can do is this:
Cache-Control: no-store
<body onunload="">
Below shows the raw logs of my tests:
HTTP:
Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
<body onunload="">
Fail: Opera 12.15
Success: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
<body onunload="">
Fail: Opera 12.15
Success: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
Fail: Safari 5.1.7, Opera 12.15
Success: Chrome 28, FireFox 23, IE8
Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
Fail: Safari 5.1.7, Opera 12.15
Success: Chrome 28, FireFox 23, IE8
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
<body onunload="">
Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
Success: IE8
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
<body onunload="">
Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
Success: IE8
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
<body onunload="">
Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
Success: IE8
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
<body onunload="">
Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
Success: IE8
Cache-Control: no-store
Fail: Safari 5.1.7, Opera 12.15
Success: Chrome 28, FireFox 23, IE8
Cache-Control: no-store
<body onunload="">
Fail: Opera 12.15
Success: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Cache-Control: no-cache
Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
Success: IE8
Vary: *
Fail: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
Success: none
Pragma: no-cache
Fail: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
Success: none
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
<body onunload="">
Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
Success: IE8
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
<body onunload="">
Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
Success: IE8
Cache-Control: must-revalidate, max-age=0
Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
Success: IE8
Cache-Control: must-revalidate
Expires: 0
Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
Success: IE8
Cache-Control: must-revalidate
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Fail: Chrome 28, FireFox 23, Safari 5.1.7, Opera 12.15
Success: IE8
Cache-Control: private, must-revalidate, proxy-revalidate, s-maxage=0
Pragma: no-cache
Vary: *
<body onunload="">
Fail: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
Success: none
HTTPS:
Cache-Control: private, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
<body onunload="">
Fail: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
Success: none
Cache-Control: private, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
<body onunload="">
Fail: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
Success: none
Vary: *
Fail: Chrome 28, Safari 5.1.7, Opera 12.15
Success: FireFox 23, IE8
Pragma: no-cache
Fail: Chrome 28, Safari 5.1.7, Opera 12.15
Success: FireFox 23, IE8
Cache-Control: no-cache
Fail: Chrome 28, Safari 5.1.7, Opera 12.15
Success: FireFox 23, IE8
Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0
Fail: Chrome 28, Safari 5.1.7, Opera 12.15
Success: FireFox 23, IE8
Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
Fail: Chrome 28, Safari 5.1.7, Opera 12.15
Success: FireFox 23, IE8
Cache-Control: private, no-cache, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
Fail: Chrome 28, Safari 5.1.7, Opera 12.15
Success: FireFox 23, IE8
Cache-Control: must-revalidate
Fail: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Success: Opera 12.15
Cache-Control: private, must-revalidate, proxy-revalidate, s-maxage=0
<body onunload="">
Fail: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Success: Opera 12.15
Cache-Control: must-revalidate, max-age=0
Fail: Chrome 28, FireFox 23, Safari 5.1.7
Success: IE8, Opera 12.15
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
<body onunload="">
Fail: Chrome 28, Safari 5.1.7
Success: FireFox 23, IE8, Opera 12.15
Cache-Control: private, no-cache, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
<body onunload="">
Fail: Chrome 28, Safari 5.1.7
Success: FireFox 23, IE8, Opera 12.15
Cache-Control: no-store
Fail: Opera 12.15
Success: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Cache-Control: private, no-cache, no-store, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
Pragma: no-cache
Vary: *
<body onunload="">
Fail: Opera 12.15
Success: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Cache-Control: private, no-cache, no-store, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
<body onunload="">
Fail: Opera 12.15
Success: Chrome 28, FireFox 23, IE8, Safari 5.1.7
Cache-Control: private, no-cache
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
Fail: Chrome 28, Safari 5.1.7, Opera 12.15
Success: FireFox 23, IE8
Cache-Control: must-revalidate
Expires: 0
Fail: Chrome 28, FireFox 23, Safari 5.1.7,
Success: IE8, Opera 12.15
Cache-Control: must-revalidate
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Fail: Chrome 28, FireFox 23, Safari 5.1.7,
Success: IE8, Opera 12.15
Cache-Control: private, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: 0
<body onunload="">
Fail: Chrome 28, FireFox 23, Safari 5.1.7,
Success: IE8, Opera 12.15
Cache-Control: private, must-revalidate, max-age=0, proxy-revalidate, s-maxage=0
Expires: Sat, 12 Oct 1991 05:00:00 GMT
<body onunload="">
Fail: Chrome 28, FireFox 23, Safari 5.1.7,
Success: IE8, Opera 12.15
Cache-Control: private, must-revalidate
Expires: Sat, 12 Oct 1991 05:00:00 GMT
Pragma: no-cache
Vary: *
Fail: Chrome 28, Safari 5.1.7
Success: FireFox 23, IE8, Opera 12.15
Cache-Control: no-store, must-revalidate
Fail: none
Success: Chrome 28, FireFox 23, IE8, Safari 5.1.7, Opera 12.15
Answered 2023-09-21 08:09:16
<body onunload="">
but it seems more like a way around the actual problem. I've tried using the .htaccess and modifying the headers that way, if I use HTTPS should it work that way? It's mainly safari where the problem arrises most. - anyone Cache-Control: no-store
would do the trick. <body onunload="">
is only needed when you don't have HTTPS. - anyone I found the web.config route useful (tried to add it to the answer but doesn't seem to have been accepted so posting here)
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Cache-Control" value="no-cache, no-store, must-revalidate" />
<!-- HTTP 1.1. -->
<add name="Pragma" value="no-cache" />
<!-- HTTP 1.0. -->
<add name="Expires" value="0" />
<!-- Proxies. -->
</customHeaders>
</httpProtocol>
</system.webServer>
And here is the express / node.js way of doing the same:
app.use(function(req, res, next) {
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
res.setHeader('Pragma', 'no-cache');
res.setHeader('Expires', '0');
next();
});
Answered 2023-09-21 08:09:16
web.conf
is: It is the main settings and configuration file for an ASP.NET
web application. It is an XML document that resides in the root directory. (wiki). - anyone I found that all of the answers on this page still had problems. In particular, I noticed that none of them would stop IE8 from using a cached version of the page when you accessed it by hitting the back button.
After much research and testing, I found that the only two headers I really needed were:
Cache-Control: no-store
Vary: *
For an explanation of the Vary header, check out http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.6
On IE6-8, FF1.5-3.5, Chrome 2-3, Safari 4, and Opera 9-10, these headers caused the page to be requested from the server when you click on a link to the page, or put the URL directly in the address bar. That covers about 99% of all browsers in use as of Jan '10.
On IE6, and Opera 9-10, hitting the back button still caused the cached version to be loaded. On all other browsers I tested, they did fetch a fresh version from the server. So far, I haven't found any set of headers that will cause those browsers to not return cached versions of pages when you hit the back button.
Update: After writing this answer, I realized that our web server is identifying itself as an HTTP 1.0 server. The headers I've listed are the correct ones in order for responses from an HTTP 1.0 server to not be cached by browsers. For an HTTP 1.1 server, look at BalusC's answer.
Answered 2023-09-21 08:09:16
After a bit of research we came up with the following list of headers that seemed to cover most browsers:
In ASP.NET we added these using the following snippet:
Response.ClearHeaders();
Response.AppendHeader("Cache-Control", "no-cache"); //HTTP 1.1
Response.AppendHeader("Cache-Control", "private"); // HTTP 1.1
Response.AppendHeader("Cache-Control", "no-store"); // HTTP 1.1
Response.AppendHeader("Cache-Control", "must-revalidate"); // HTTP 1.1
Response.AppendHeader("Cache-Control", "max-stale=0"); // HTTP 1.1
Response.AppendHeader("Cache-Control", "post-check=0"); // HTTP 1.1
Response.AppendHeader("Cache-Control", "pre-check=0"); // HTTP 1.1
Response.AppendHeader("Pragma", "no-cache"); // HTTP 1.0
Response.AppendHeader("Expires", "Sat, 26 Jul 1997 05:00:00 GMT"); // HTTP 1.0
Found from: http://forums.asp.net/t/1013531.aspx
Answered 2023-09-21 08:09:16
Cache-Control: no-cache
and Cache-Control: private
clash - you should never get both together: the former tells browsers and proxies not to cache at all, the latter tells proxies not to cache but lets browsers hold their own private copy. I'm not sure which setting the browser will follow, but it's unlikely to be consistent between browsers and versions. - anyone The use of the pragma header in the response is a wives tale. RFC2616 only defines it as a request header
Answered 2023-09-21 08:09:16
For ASP.NET Core, create a simple middleware class:
public class NoCacheMiddleware
{
private readonly RequestDelegate m_next;
public NoCacheMiddleware( RequestDelegate next )
{
m_next = next;
}
public async Task Invoke( HttpContext httpContext )
{
httpContext.Response.OnStarting( ( state ) =>
{
// ref: http://stackoverflow.com/questions/49547/making-sure-a-web-page-is-not-cached-across-all-browsers
httpContext.Response.Headers.Append( "Cache-Control", "no-cache, no-store, must-revalidate" );
httpContext.Response.Headers.Append( "Pragma", "no-cache" );
httpContext.Response.Headers.Append( "Expires", "0" );
return Task.FromResult( 0 );
}, null );
await m_next.Invoke( httpContext );
}
}
then register it with Startup.cs
app.UseMiddleware<NoCacheMiddleware>();
Make sure you add this somewhere after
app.UseStaticFiles();
Answered 2023-09-21 08:09:16
There's a bug in IE6
Content with "Content-Encoding: gzip" is always cached even if you use "Cache-Control: no-cache".
http://support.microsoft.com/kb/321722
You can disable gzip compression for IE6 users (check the user agent for "MSIE 6")
Answered 2023-09-21 08:09:16
These directives does not mitigate any security risk. They are really intended to force UA's to refresh volatile information, not keep UA's from being retaining information. See this similar question. At the very least, there is no guarantee that any routers, proxies, etc. will not ignore the caching directives as well.
On a more positive note, policies regarding physical access to computers, software installation, and the like will put you miles ahead of most firms in terms of security. If the consumers of this information are members of the public, the only thing you can really do is help them understand that once the information hits their machine, that machine is their responsibility, not yours.
Answered 2023-09-21 08:09:16
DISCLAIMER: I strongly suggest reading @BalusC's answer. After reading the following caching tutorial: http://www.mnot.net/cache_docs/ (I recommend you read it, too), I believe it to be correct. However, for historical reasons (and because I have tested it myself), I will include my original answer below:
I tried the 'accepted' answer for PHP, which did not work for me. Then I did a little research, found a slight variant, tested it, and it worked. Here it is:
header('Cache-Control: no-store, private, no-cache, must-revalidate'); // HTTP/1.1
header('Cache-Control: pre-check=0, post-check=0, max-age=0, max-stale = 0', false); // HTTP/1.1
header('Pragma: public');
header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); // Date in the past
header('Expires: 0', false);
header('Last-Modified: '.gmdate('D, d M Y H:i:s') . ' GMT');
header ('Pragma: no-cache');
That should work. The problem was that when setting the same part of the header twice, if the false
is not sent as the second argument to the header function, header function will simply overwrite the previous header()
call. So, when setting the Cache-Control
, for example if one does not want to put all the arguments in one header()
function call, he must do something like this:
header('Cache-Control: this');
header('Cache-Control: and, this', false);
See more complete documentation here.
Answered 2023-09-21 08:09:16
The RFC for HTTP 1.1 says the proper method is to add an HTTP Header for:
Cache-Control: no-cache
Older browsers may ignore this if they are not properly compliant to HTTP 1.1. For those you can try the header:
Pragma: no-cache
This is also supposed to work for HTTP 1.1 browsers.
Answered 2023-09-21 08:09:16
Setting the modified http header to some date in 1995 usually does the trick.
Here's an example:
Expires: Wed, 15 Nov 1995 04:58:08 GMT Last-Modified: Wed, 15 Nov 1995 04:58:08 GMT Cache-Control: no-cache, must-revalidate
Answered 2023-09-21 08:09:16
If you're facing download problems with IE6-IE8 over SSL and cache:no-cache header (and similar values) with MS Office files you can use cache:private,no-store header and return file on POST request. It works.
Answered 2023-09-21 08:09:16
The PHP documentation for the header function has a rather complete example (contributed by a third party):
header('Pragma: public');
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
header('Last-Modified: '.gmdate('D, d M Y H:i:s') . ' GMT');
header('Cache-Control: no-store, no-cache, must-revalidate'); // HTTP/1.1
header('Cache-Control: pre-check=0, post-check=0, max-age=0', false); // HTTP/1.1
header ("Pragma: no-cache");
header("Expires: 0", false);
Answered 2023-09-21 08:09:16
in my case i fix the problem in chrome with this
<form id="form1" runat="server" autocomplete="off">
where i need to clear the content of a previus form data when the users click button back for security reasons
Answered 2023-09-21 08:09:16
The accepted answer does not appear to work for IIS7+, going by the large number of questions about cache headers not being sent in II7:
And so on
The accepted answer is correct in which headers must be set, but not in how they must be set. This way works with IIS7:
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.AppendCacheExtension("no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache");
Response.AppendHeader("Expires", "-1");
The first line sets Cache-control
to no-cache
, and the second line adds the other attributes no-store, must-revalidate
Answered 2023-09-21 08:09:16
Response.Cache.SetAllowResponseInBrowserHistory(false); Response.Cache.SetCacheability(HttpCacheability.NoCache); Response.Cache.SetNoStore(); Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
- anyone I've had best and most consistent results across all browsers by setting Pragma: no-cache
Answered 2023-09-21 08:09:16
In addition to the headers consider serving your page via https. Many browsers will not cache https by default.
Answered 2023-09-21 08:09:16
The headers in the answer provided by BalusC does not prevent Safari 5 (and possibly older versions as well) from displaying content from the browser cache when using the browser's back button. A way to prevent this is to add an empty onunload event handler attribute to the body tag:
<body onunload="">
This hack apparently breaks the back-forward cache in Safari: Is there a cross-browser onload event when clicking the back button?
Answered 2023-09-21 08:09:16
Also, just for good measure, make sure you reset the ExpiresDefault
in your .htaccess
file if you're using that to enable caching.
ExpiresDefault "access plus 0 seconds"
Afterwards, you can use ExpiresByType
to set specific values for the files you want to cache:
ExpiresByType image/x-icon "access plus 3 month"
This may also come in handy if your dynamic files e.g. php, etc. are being cached by the browser, and you can't figure out why. Check ExpiresDefault
.
Answered 2023-09-21 08:09:16
//In .net MVC
[OutputCache(NoStore = true, Duration = 0, VaryByParam = "*")]
public ActionResult FareListInfo(long id)
{
}
// In .net webform
<%@ OutputCache NoStore="true" Duration="0" VaryByParam="*" %>
Answered 2023-09-21 08:09:16
To complete BalusC -> ANSWER If you are using perl you can use CGI to add HTTP headers.
Using Perl:
Use CGI;
sub set_new_query() {
binmode STDOUT, ":utf8";
die if defined $query;
$query = CGI->new();
print $query->header(
-expires => 'Sat, 26 Jul 1997 05:00:00 GMT',
-Pragma => 'no-cache',
-Cache_Control => join(', ', qw(
private
no-cache
no-store
must-revalidate
max-age=0
pre-check=0
post-check=0
))
);
}
Using apache httpd.conf
<FilesMatch "\.(html|htm|js|css|pl)$">
FileETag None
<ifModule mod_headers.c>
Header unset ETag
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
</ifModule>
Note: When I tried to use the html META, browsers ignored them and cached the page.
Answered 2023-09-21 08:09:16
I just want to point out that if someone wants to prevent caching ONLY dynamic content, adding those additional headers should be made programmatically.
I edited configuration file of my project to append no-cache headers, but that also disabled caching static content, which isn't usually desirable. Modifying response headers in code assures that images and style files will be cached.
This is quite obvious, yet still worth mentioning.
And another caution. Be careful using ClearHeaders method from HttpResponse class. It may give you some bruises if you use it recklessly. Like it gave me.
After redirecting on ActionFilterAttribute event the consequences of clearing all headers are losing all session data and data in TempData storage. It's safer to redirect from an Action or don't clear headers when redirection is taking place.
On second thought I discourage all to use ClearHeaders method. It's better to remove headers separately. And to set Cache-Control header properly I'm using this code:
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
filterContext.HttpContext.Response.Cache.AppendCacheExtension("no-store, must-revalidate");
Answered 2023-09-21 08:09:16
I had no luck with <head><meta>
elements. Adding HTTP cache related parameters directly (outside of the HTML doc) does indeed work for me.
Sample code in Python using web.py web.header
calls follows. I purposefully redacted my personal irrelevant utility code.
import web import sys import PERSONAL-UTILITIES myname = "main.py" urls = ( '/', 'main_class' ) main = web.application(urls, globals()) render = web.template.render("templates/", base="layout", cache=False) class main_class(object): def GET(self): web.header("Cache-control","no-cache, no-store, must-revalidate") web.header("Pragma", "no-cache") web.header("Expires", "0") return render.main_form() def POST(self): msg = "POSTed:" form = web.input(function = None) web.header("Cache-control","no-cache, no-store, must-revalidate") web.header("Pragma", "no-cache") web.header("Expires", "0") return render.index_laid_out(greeting = msg + form.function) if __name__ == "__main__": nargs = len(sys.argv) # Ensure that there are enough arguments after python program name if nargs != 2: LOG-AND-DIE("%s: Command line error, nargs=%s, should be 2", myname, nargs) # Make sure that the TCP port number is numeric try: tcp_port = int(sys.argv[1]) except Exception as e: LOG-AND-DIE ("%s: tcp_port = int(%s) failed (not an integer)", myname, sys.argv[1]) # All is well! JUST-LOG("%s: Running on port %d", myname, tcp_port) web.httpserver.runsimple(main.wsgifunc(), ("localhost", tcp_port)) main.run()
Answered 2023-09-21 08:09:16
See this link to a Case Study on Caching:
http://securityevaluators.com/knowledge/case_studies/caching/
Summary, according to the article, only Cache-Control: no-store
works on Chrome, Firefox and IE. IE accepts other controls, but Chrome and Firefox do not. The link is a good read complete with the history of caching and documenting proof of concept.
Answered 2023-09-21 08:09:16
i have solved in this way.
2 considerations:
1) the server side events are not fired on back click, instead of javascript.
2) i have 2 javascript to read/write cookies
function setCookie(name, value, days)
{
var expires = "";
if (days)
{
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + (value || "") + expires + "; path=/";
}
function getCookie(name)
{
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for (var i = ca.length - 1; i >= 0; i--)
{
var c = ca[i];
while (c.charAt(0) == ' ')
{
c = c.substring(1, c.length);
}
if (c.indexOf(nameEQ) == 0)
{
return c.substring(nameEQ.length, c.length);
}
}
return null;
}
in my Page_Load i inserted this: (this is NOT fired on back click)
protected void Page_Load(object sender, EventArgs e)
{
Page.RegisterClientScriptBlock("", "<script>setCookie('" + Session.SessionID + "', '" + Login + "', '100');</script>");
}
where 'Login' is my id value that is -1 after logout (you could use something else, a boolean for example).
then in my page i added this: (this IS fired on back click)
<script type="text/javascript">
if (getCookie('<%= Session.SessionID %>') < 0)
{
if (history.length > 0)
{
history.go(+1);
}
}
</script>
nothing else.
with this solution back click is enable on every page and disable only after logout on each page on the same browser.
Answered 2023-09-21 08:09:16
you can use location block for set individual file instead of whole app get caching in IIS
<location path="index.html">
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Cache-Control" value="no-cache" />
</customHeaders>
</httpProtocol>
</system.webServer>
</location>
Answered 2023-09-21 08:09:16
Not sure if my answer sounds simple and stupid, and perhaps it has already been known to you since long time ago, but since preventing someone from using browser back button to view your historical pages is one of your goals, you can use:
window.location.replace("https://www.example.com/page-not-to-be-viewed-in-browser-history-back-button.html");
Of course, this may not be possible to be implemented across the entire site, but at least for some critical pages, you can do that. Hope this helps.
Answered 2023-09-21 08:09:16