IE7 Classic ASP Cache - asp-classic

I have a classic asp website that uses Session variables to store login state ie. userid, isloggedin, etc. On logout, the session variables are reset and Session.Abandon() is called followed by a redirect to the login page. In IE7 I have noticed that after logout I can type in a previously visited url and see what appears to be a cached version of its state prior to the logout. Hitting ctl-f5 will reload from the server again and redirect to the login page. This is the behavior I want to occur even if the url is type in without the ctl-f5. Does anyone know how to get this behavior?

set the no-cache headers so that the pages do not get cached in the first place. see:
http://support.microsoft.com/kb/234067

I think mkoryak's answer (using no-cache headers) seems best. If you want certain pages to be seen only when a user is logged in, the best way is to instruct the browser to simply not cache the page. Furthermore, schemes such as tweaking cookies and using javascript do determine login state on the client are simply reinventing the wheel.
If you want to leverage some caching and your page isn't something that is constantly updating, a good compromise is to set the Response.Expires header to some value you deem appropriate (it's measured in minutes I believe).

I've had a similar problem before, but whenever I've clicked a link on that page, it's asked me to log back in.
You could try either resetting sessionID = "" or sessionID = "XYZ" and make XYZ something your code ignores on log out.
You could also try setting no-cache headers.

You could send no-cache however thats quiet a performance hit just to get what you want. I prefer Liams suggestion and ensuring that everything you do from that page requires you to be logged in, that way no one can do anything they shouldn't. What if its a email system though or similar, the people "could" view other peoples emails which are cached, in those instances then yes, not caching sensitive information is the way to go (you can't cache HTTPS pages by default for instance).
You could also include some javascript in the head which could check for the existance of a "logged in" cookie. This would run every time they loaded the page, if no cookie exists then JS could redirect you off to the login page. Not 100% fool proof but good enough. You logout page would need to clear this cookie and you login page set it.

Related

How do you determine cookies are disabled *without* javascript and *without* redirecting?

If I disable javascript and cookies, Amazon.com detects that cookies are disabled without a redirect. If you click the cart link, there's only a get on the cart page.
I'm guessing amazon.com is most likely not using ASP.NET, but how would you accomplish detecting disabled cookies using ASP.NET without the use of javascript and redirecting? Is it possible to detect if cookies are disabled in one round trip?
I believe what you're describing is impossible. Amazon doesn't appear to do that. As proof:
Disable JavaScript
Clear your cookies (but leave them enabled)
Go here: http://www.amazon.com/gp/cart/view.html/ref=gno_cart
You'll get the message "Please Enable Cookies in your Web Browser to Continue." But if you reload the page, the message will go away, because cookies got set on the first viewing.
The reason this doesn't work is that when a page response sets cookies, the server can't tell they've been properly set until the next request. You can get around that using JavaScript, of course, but without that there's no way for the server to know in advance whether a request comes from a browser that will accept cookies.
You don't need redirect to get at the cookies. All you need is a delayed load content.
Basically, I believe the following would work:
The 'GET /index.html' response sets the Cookies (they come in the header, and are stored before index.html is received and rendered).
You can than check for cookies while serving say 'GET /TinyImage.gif' if you don't run into caching problems and respond to images dynamically.
So, the final problem, is how do you inform the user about your findings from the TinyImage request? Definitely not easily, but if you use IFrame instead of a simple tag, you can essentially have two GET requests for a single page render.
Or, you can be really, really insane and actually stall the first GET until the second GET confirms the browser settings. This is for some HTTP wizards, but if you can wrap your head around Comet (not AJAX, Comet!), it can come in handy.
It's definitely possible, just tricky. Would I try doing so in ASP.NET? Can't promise anything but it will be a neat thing to share.
I guess it may load the page in the javascript / cookies off configuration and then use javascript to do the check and set functionality to cookies enabled if needed.
Could you set a Cookie in Page_Init for instance, then see if you could read from it in Page_PreRender?
Not sure that's even possible, but that's the only way I could think of.

Back arrow after signing out

I have an ASP.NET application using Forms Authentication. When the user clicks the Sign Out button on the page it runs the following code.
FormsAuthentication.SignOut();
Response.Expires = 0;
Response.Cache.SetNoStore();
Response.AppendHeader("Pragma", "no-cache");
However the user can still just press the back arrow and see the previous page without needing to log in again. I am sure it has something to do with the previous page being cached. How can I make sure they are prompted to log in again with going back?
Response.Cache.SetCacheability(HttpCacheability.NoCache);
And now you know why you get the message, "You've been logged out. Please close this browser window for security reasons."
No cache is a workaround.
The penultimate workaround is to use ajax to pull any sensitive information down - this would be run again in the back case, and the information should not be cached. It's more connections and more latency, but due to modern browser caching there's not much that can be done except workarounds such as these.
-Adam
While caching is not guaranteed, this works for me for the most part
//Used for disabling page caching
HttpContext.Current.Response.Cache.SetExpires(
DateTime.UtcNow.AddDays(-1));
HttpContext.Current.Response.Cache.SetValidUntilExpires(false);
HttpContext.Current.Response.Cache.SetRevalidation(
HttpCacheRevalidation.AllCaches);
HttpContext.Current.Response.Cache.SetCacheability(
HttpCacheability.NoCache);
HttpContext.Current.Response.Cache.SetNoStore();
Run this in any page's OnInit() method (maybe by using a base class) on any page you don't want the users to be able to cache.
Be careful though, some pages may require you to allow caching such as doing file downloads on SSL pages etc.
I found this code somewhere, if I find the link I'll update the post.

session lost on redirect

I have a web app that is being hit by facebook. The login page retrieves the keys that I need and sets some session variables. When the server then redirects the user to the next page, the session information is lost. I’m running the IIS engine on vista ultimate at the moment, the app pools don’t matter because I’m using a state service and I’m still losing the session state. I’ve tried both the overloaded method of the response.redirect function and also adding a header to the page to force the redirect and none of this seems to work. Does anyone have any ideas of what I’m missing?
I’ve tried both of these:
Response.Headers.Add("refresh", "3;url=Dashboard.aspx")
And
Response.Redirect("Dashboard.aspx", False)
[EDIT]
So i just did a little experiment and well it turns out that when I hit the url directly from the facebook page I get the problem, but when i copy the url for the IFrame into a new browser window and try it it works fine.
[EDIT]
So I found an article on this and after addin gthe header the problem was solved (for now)
http://support.microsoft.com/kb/323752
Response.AddHeader("P3P: CP", "CAO PSA OUR")
when I hit the url directly from the facebook page I get the problem, but when i copy the url for the IFrame into a new browser window and try it it works fine.
If you're in an iframe, any cookies you set are “third-party cookies”. Third-party cookies may be subject to more stringent conditions than the normal “first-party” cookies you are setting when the user is directly on your site. This can be due to different browser default cookie handling or because the user has deliberately configured it like that. (And for good reason: many third-parties are unpleasant privacy-invading advertisers.)
In particular, in IE6+ with the default settings, you cannot set a third-party cookie unless you write a P3P policy promising that you will be a good boy and not flog your users' data to the nearest identify thief.
(In practice of course P3P is a dead loss, since there's nothing stopping the site owner from just lying. Another worthless complication that provides no actual security. Yay.)
I'd try running Fiddler and see if your session cookie is being sent properly with the response when interacting with your app via Facebook.
The session depends also on cookie support by the client. When you say the app "is being hit by facebook" are you sure that by what ever means they are "hitting" you they are supporting cookies?
Response.Redirect and refresh don't carry session. Server.Transfer() can but loses the ability to transfer to other servers/sites.

ASP.net: Cache problem when logout

I can't find any post regarding the cache on logout so I'm going to ask this question. If there is a similar question. Please let me know.
I have a Logout page that basically call FormAuthentications signout method then redirect the user to the login page. It work fine but the problem is user can click on the browser's back button and get the cached page. I tried to set the no-cache header on my master page but that doesn't work.
Can someone point me to a article or tutorial or post some tips on how you handle this situation?
thank
Depending on your requirements a possible solution might be to set the Cache-Control header to "no-cache" on every authenticated page. This will prevent pages from being cached downstream. It could be achieved by writing a custom HttpModule that will set the header:
// Prevent the browser from caching the ASPX page
Response.Cache.SetNoStore();
You can also set this in your page's HEAD section by adding the following line of code:
<meta http-equiv="Cache-Control" content="no-cache" />
By doing that if a user clicks the Back button once he's been signed out, he will be redirected to the login form instead of seeing a cached version of his last page which could be a problem if he is using a public computer.
If you're using forms authentication, make sure the forms authentication cookie is deleted when the user logs out. As soon as the user goes to do anything on the cached page (the page they pressed the back button to get to), the site will ask the user to re-login, and then redirect them back to the original page, with fresh data. Viola!
Additionally, regarding caching of pages, you need to set a pretty good number of headers to turn the caching mechanism in the browser and proxy servers off:
"Expires" - set to some date in the past
"Last-Modified" - set to the current date/time
"Cache-Control" - set to "no-cache, must-revalidate"
"Pragma" - set to "no-cache"
That should just about make the page uncacheable. The date/times need to be in RFC1123 format (format specifier "R" in .net e.g. "Mon, 17 Apr 2006 21:22:48 GMT"). You would implement this as:
Response.AddHeader("Expires", new DateTime(1940, 1, 1).ToString("R"));
Response.AddHeader("Last-Modified", DateTime.Now.ToString("R"));
Response.AddHeader("Cache-Control", "no-cache, must-revalidate");
Response.AddHeader("Pragma", "no-cache");
Or something similar, depending on where you want to add all of the headers. I have had good success with this across many browsers and proxy servers, but nothing is fool-proof where page caching is concerned.
There's no foolproof way to accomplish this. The user ultimately has control over the cache settings and no-cache headers can't override these.
Is there a particular concern you are trying to address here (security?), or are you just trying to ensure that users aren't seeing stale data?
This is a hard problem to tackle. You can create a base page and in the constructor you can check that if the person is logged in or not. If the person is not logged in that simply redirect to the login page. This base page will be inherited by all the other ASP.NET pages.
IE6 seems to ignore some cache headers.
Another technique ontop of cache headers would be some clientside javascript to check for the authentication cookie and use history.Forward() if its not there.
Add this to global.asax and it will set the no-cache headers for all pages in the web application. Be sure that disabling caching is really what you want to do however - because caching is a performance benefit.
You can of course, also apply the same Response.Cache commands to pages individually.
This works in FireFox 3, IE7, and somewhat in Opera 9.6. (In Opera, it will work if you don't to any post requests. If you do, the page will still be accessible from the back button the first time, but not afterwards.)
protected void Application_PreSendRequestHeaders(object sender, EventArgs e)
{
if (!Request.Path.Contains("/Content/")) //We WANT images, css, javascripts to be cached!
{
//Otherwise, all of our pages contain sensitive information, and we don't want them cached.
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches); //for Opera. May only work on https sites
Response.Cache.SetNoStore();
}
}
There is no way you can actually stop is behavior people have removed the back button disabled it but the user would still have controls from short cut for any browser , my suggestion would be that for all those pages where you want the users to be logged in Put them on a POST method i.e. instead of a regular GET use post. What this would do is anytime a user presses the back button for that url the browser would ask the user with an alert box to post the last data cached for this request and there would be a server call where form authentication would work.
It is a bit crude using post where get might work but it solves this issue of yours.

Is there a way to keep a page from rendering once a person has logged out but hit the "back" button?

I have some website which requires a logon and shows sensitive information.
The person goes to the page, is prompted to log in, then gets to see the information.
The person logs out of the site, and is redirected back to the login page.
The person then can hit "back" and go right back to the page where the sensitive information is contained. Since the browser just thinks of it as rendered HTML, it shows it to them no problem.
Is there a way to prevent that information from being displayed when the person hits the "back" button from the logged out screen? I'm not trying to disable the back button itself, I'm just trying to keep the sensitive information from being displayed again because the person is not logged into the site anymore.
For the sake of argument, the above site/scenario is in ASP.NET with Forms Authentication (so when the user goes to the first page, which is the page they want, they're redirected to the logon page - in case that makes a difference).
The short answer is that it cannot be done securely.
There are, however, a lot of tricks that can be implemented to make it difficult for users to hit back and get sensitive data displayed.
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetExpires(Now.AddSeconds(-1));
Response.Cache.SetNoStore();
Response.AppendHeader("Pragma", "no-cache");
This will disable caching on client side, however this is not supported by all browsers.
If you have the option of using AJAX then sensitive data can be retrieved using a updatepanel that is updated from client code and therefore it will not be displayed when hitting back unless client is still logged in.
Cache and history are independent and one shouldn't affect each other.
The only exception made for banks is that combination of HTTPS and Cache-Control: must-revalidate forces refresh when navigating in history.
In plain HTTP there's no way to do this except by exploiting browser bugs.
You could hack around it using Javascript that checks document.cookie and redirects when a "killer" cookie is set, but I imagine this could go seriously wrong when browser doesn't set/clear cookies exactly as expected.
From aspdev.org:
Add the following line on top of the Page_Load event handler and your ASP.NET page will not be cached in the users browsers:
Response.Cache.SetCacheability(HttpCacheability.NoCache)
Settings this property ensures that if the user hits the back-button the content will be gone, and if he presses "refresh" he will be redirected to the login-page.
DannySmurf, <meta> elements are extremely unreliable when it comes to controlling caching, and Pragma in particular even more so. Reference.
dannyp and others, no-cache does not stop caches from storing sensitive resources. It merely means that a cache cannot serve a resource it has stored without revalidating it first. If you wish to prevent sensitive resources from being cached, you need to use the no-store directive.
You could have a javascript function does a quick server check (ajax) and if the user is not logged in, erases the current page and replaces it with a message. This would obviously be vulnerable to a user whos javascript is off, but that is pretty rare. On the upside, this is both browser and server technology (asp/php etc) agnostic.
You are looking for a no-cache directive:
<META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">
If you've got a master page design going, this may be a little bit of a juggle, but I believe you can put this directive on a single page, without affecting the rest of your site (assuming that's what you want).
If you've got this directive set, the browser will dutifully head back to the server looking for a brand new copy of the page, which will cause your server to see that the user is not authenticated and bump him to the login page.
Have the logout operation be a POST. Then the browser will prompt for "Are you sure you want to re-post the form?" rather than show the page.
I don't know how to do it in ASP.NET but in PHP I would do something like:
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Cache-Control: no-cache");
header("Pragma: no-cache");
Which forces the browser to recheck that the item, so your authentication checking should be triggered, denying the user access.
It's a bit of a strain, but if you had a java applet or a flash application that was embedded and authentication was done through that you could make it so that they had to authenticate in, erm, 'real-time' with the server everytime they wanted to view the information.
Using this you could also encrypt any information.
There's always the possibility that someone can just save the page with the sensitive information on, having no cache isn't going to get around this situation (but then a screenshot can always be taken of a flash or java application).
For completeness:
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetNoStore();
Response.Cache.SetExpires(DateTime.Now.AddMinutes(-1));
The correct answer involves use of setting the HTTP Cache-Control header on the response. If you want to ensure that they never cache the output, you can do Cache-Control: no-cache. This is often used in coordination with no-store as well.
Other options, if you want limited caching, include setting an expires time and must-revalidate, but these could potentially all cause a cached page to be displayed again.
See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4
Well, in a major brazilian bank corporation (Banco do Brasil) which is known by having one of the world´s most secure and efficient home banking software, they simply put history.go(1) in every page.So, if you hit the back button, you will be returned. Simple.
Please look into the HTTP response headers. Most of the ASP code that people are posting looks to be setting those. Be sure.
The chipmunk book from O'Reilly is the bible of HTTP, and Chris Shiflett's HTTP book is good as well.
You can have the web page with the sensitive be returned as an HTTP POST, then in most cases browsers will give you the message asking if you want want to resubmit the data. (Unfortunately I cannot find a canonical source for this behavior.)
I just had the banking example in mind.
The page of my bank has this in it:
<meta http-equiv="expires" content="0" />
This should be about this I suppose.

Resources