Detecting User pressing back button without Javascript? - http

I know there are ways to tell if an user has pressed the back button using Javascript, but is there a way to tell without resorting to Javascript? Is there a solution that involves just looking at referer URLs perhaps?

Without javascript no.
The problem is the back button will not guarantee you get a server hit. It can cache the page client side and even if it did hit the server (loading the page), then it would have the request from the initial hit not like it came from the page you were just on. The back button doesn't add 'referral' information to the request. It just goes back to the last thing you did without sending the details of where you just were.
You need to handle this client side.

Yes, it is possible. There are two parts to this -
Every URL should have a unique token in it. On the server side, you keep track of the current and past tokens. When a request comes along, if the token matches a past token, the back button was hit. If it equals the current token, process the request normally. Otherwise fail the request.
Now, the page could have been cached and your server may not see the request. So you have to take steps to defeat the browser cache. Setting the following http headers should force the browser to make a request -
Cache-Control : no-Cache
Pragma : No-Cache
Expires : Thu, 01 Jan 1970 00:00:00 GMT
Because it is possible doesn't mean you should use it though. Backbutton is an essential technique for the web, and breaking it is poor usability.

Related

Cache control not working when hit refresh in the browser

I'm trying to implement cache control on my application. I've set up the tomcat filter for the all fonts giving a max-age=120.
When I request a font for the first time with the cache cleared, the call/response is the following:
and as you can see I have the max-age response. Now I expect that if I hit refresh the browser won't send the http request again instead this is what happens:
As you can see the second request has a
cache-control: max-age=0
value and the response is returned from the server cache. What I'm trying to achieve is to block the entire call from the browser.
Am I doing something wrong?
Thanks
Hitting refresh has semantics that are dependent upon the browser you're using, but often it will make a conditional request to make sure the user is seeing a fresh response (because they wanted to refresh).
If you want to check cache operation, try navigating to the page, rather than hitting refresh.
OTOH if you don't want refresh to behave like this -- and you really mean it -- Mozilla is prototyping Cache-Control: immutable to do this (but it's early days, and mob-only for the moment).

What is the difference between Etag and Expires header?

I know this question is asked for several times. But Still I am not clear about the concept. After reading many blogs and answers in SO what I got is,
Expiry headers are used when you don’t even want client (and proxies/caches) to make a request to
the server. In ETAG, the client will check with the server for the update, but in expiry
headers, the client will know, when to expire the file and check for an update, till then it
(browsers and proxies/caches) won’t bother server for checking the update.
So basically it say if we use expires/max-age header , It will not even check for the server for an updated file. So I thought to test it locally.
So I have created on simple html file including 2 js files and 1 image file. In IIS , I have set the Expires header to 2 days for the image folder. So as per my understanding , after getting the image file from the server once, for next request it should not send a request to the server to check the image file is modified or not.
But what I got is each time I refresh the page I see a request sent to the server and the server returns a 304 not modified status. But as per the specs/blogs I read It should not send a request to the server.
Someone please explain.
For what you have described
It is clear that ETag works as it expected to be by responding with 304 not modified for the request with If-None-Match field and ETag value.
so now the browser will load the image from cache instead of getting a new image from server costing bandwidth and time.
It seems that caching is disabled in your browser.That's why a new request has been sent before the cache expiration or else a request wouldn't have been sent in the first place.
Here is a wonderful article that explains how to find caching is disabled in browser programatically
Here is a another wonderful article that explains caching and Etag in depth.
Note:
Generally speaking
If you are using multiple servers with load balancer to host your website
then simple Etag configurations likely going to cost more bandwidth by having Etag in their header and it has no purpose which is checking if browser cache is valid.(Its always going to say invalid)
The important part is what you said: I refresh the page. In this case browser is trying provide you the fresh content so it has no other option than to contact server and check all resources. (There is cache control extension immutable which prevents this behaviour but is not widely used and implemented).
If you want to see behaviour of your browser which respects caches without reload you have to use "standard page entry". Either follow a link to the page or use another tab and write the page url to the url bar and press enter.
Caches respects expiration time so if document is not stale then is returned from the cache. If expired that ETag is used to validation of the resource (and after validation it is possible that resource is still not modified - 304 response)

Google Analytics in a cookie-free environment (brightscript)

I'm implementing analytics event and page view tracking on a Roku box (brightscript). That part isn't so important, but know that JS is not an option, nor is cookie setting. I can set variables, but they're not typical cookies. Ok - so I've implemented a great solution (google-analytics-for-roku-developers/) and all is well - EXCEPT!!
Analytics doesn't seem to track uniques, and is listing ZERO. It is tracking events beautifully, however :)
Here's a sample of my URI request (decoded for clarity):
http://www.google-analytics.com/__utm.gif?utmwv=1&utmn=1736644096&utmsr=720p HDTV&utmsc=24-bit&utmul=en-us&utmje=0&utmfl=-&utmdt=RokuPageView&utmhn=Home&utmr=-&utmp=Home&utmac=UA-5035974-13&utmcc=__utma=1394882688.2097034752.1347384621.1347384621.1347384621.2;+__utmb=1394882688;+__utmc=1394882688;+__utmz=1394882688.1347384621.2.2.utmccn=(direct)|utmcsr=(direct)|utmcmd=(none);+__utmv=1394882688.13C1CJ109560;
so, question #1 - I understand from the docs that the __utma is the element that tracks uniques. Do you see anything there that's wrong?
question #2 - The development code I implemented sends a NEW random cookie for EACH EVENT. That seems wrong to me. I'm considering changing it to a session-based cookie that persists through all events. That's when I'm way beyond my understanding. Any guidance on this?
I think the answer to #2 is the answer to #1. Basically, you need to emulate how a browser handles cookies within your code. A "session cookie" is just a cookie, that is, a value passed as an HTTP header along with the request and response -- what makes it a session cookie is that it's expiration date is set to the past, which tells the browser to delete it when the browser instance closes.
Cookies are pretty straightforward -- a mechanism to get around the fact that HTTP is stateless (has no memory). If you pass an HTTP header Set-cookie: <value> in the response, the client is supposed to remember the value and pass it back in a Cookie: <value> header in subsequent requests. (There's a bit more to cookies relating to domains and expiration, and so on, but it's not that much).
So if your client (the Roku) has some mechanism for persistance, then you just need to store any new cookie, then before setting a new random one, check the header and if the cookie has been stored, just send it back as is. You'll probably need to implement some sort of task that cleans up expired cookies periodically, and so on.
Do not fear the cookie. It's just a header (with browser-imparted magical powers).

In what scenario could an AJAX request not have the cookies set by the page which fired the AJAX?

Some small percentage of the time, we see a flow like this, deducing from looking at server logs (I have not been able to reproduce this case with any browser):
At time A, client hits our page:
with no cookies
gets back a response with a Set-Cookie HTTP response header that gives them a session id of B
body has JS to fire an AJAX request /ajax/foo.
At time A + 1 second, client hits us with the AJAX request to /ajax/foo
the referrer is set to the page in step 1 that fired the AJAX, as expected
with no cookies - why?
gets back a response with a Set-Cookie header that gives them a session id of C (expected, since they didn't send us a cookie)
At some time slightly later, all of the client requests are sending either session id B or C - so the problem is not that the browser has cookies turned off.
This seems to be essentially a race condition -- the main page request and the AJAX request come in together very close in time, both with no cookies, and there is a race to set the cookie. One wins and one loses.
What is puzzling to me is how could this happen? My assumption is that by time the browser has read enough of the response to know that it needs to fire an AJAX request, it has already received the HTTP response headers and thus the Set-Cookie response header. So it seems to me that the client would always send back the cookie that we set in the page that fired the AJAX request. I just don't see how this could happen unless the browser is not promptly processing the Set-Cookie response.
Like I said, I can't reproduce this in Firefox, Safari, or Chrome, but we do see it several times a day.
There is a new feature in google chrome that could cause this misbehavior. It is called prerender.
Prerendering is an experimental feature in Chrome (versions 13 and up)
that can take hints from a site’s author to speed up the browsing
experience of users. A site author includes an element in HTML that
instructs Chrome to fetch and render an additional page in advance of
the user actually clicking on it.
Even if you do not proactively trigger prerendering yourself, it is
still possible that another site will instruct Chrome to prerender
your site. If your page is being prerendered, it may or may not ever
be shown to the user (depending on if the user clicks the link). In
the vast majority of cases, you shouldn’t have to do anything special
to handle your page being prerendered—it should just work.
For more information read: http://code.google.com/chrome/whitepapers/prerender.html
Edit:
You could trigger prerender on your page with: http://prerender-test.appspot.com/
a) Does the cookie have an expiration time?
b) If so, have you tried to reproduce it by setting the computer's clock back or forward by more than the TTL of the cookie? (I mean the clock of the computer running the browser, obviously; not the server running the app ... which should be a separate computer whose clock is set accurately.)
I've seen this as well; it seems to be triggered by users with screwed up system clocks. The cookie was sent with an expiration date that, from the browser's perspective, was already past.

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