Introduction
Two years ago I was facing a nice security problem
when I start dealing to prevent to go back in my asp.net application and
avoiding a refresh page already visited.
This request came from my boss. He was angry
to see how the user after logging off from app can go back to my app just by
heating the navigator's back button. This means that the logged user can go
away from my app on typing in the address bar: www.codeproject.com and came back again to my app easily.
My boss asked me how to prevent this because many of users can use the app on
public computers and can forget to close the app before leaving.
To get this done, of course I started
searching on the net and discussing this matter on many forums. At first I find
an article on code project but it doesn't fit my needs. And I came to the
point, with my colleague Mathieu that we should deal with this at our ends.
So this is the solution I came up with:
Our security solution reposes on a simple yet
very effective method to track what pages have been seen so far by the user
(based on each session individually, do not base this on the whole server).
Simply
described
Pass in a GET parameter (or query string parameter) a
random page number of your choice. This random number is generated by your
server ( c# function) and each
time a number is generated, it is kept in a mechanism on the server. You could
use files, databases, caching or session variables. Its up to you. This list
will grow adding all the random numbers already visited. When a page requested
contains the same number as one used before, you may assume that the page is a
FAVORITE link that has been used or a BACK in the browser history since the
page numbers should never repeat. It is as simple as that and prevents any
refresh of the current page but also prevents going BACK in the history of the
browser.
Process is simple
Look for a parameter passed in the GET vars (Query string). If
this variable doesn't exist, bump to the login screen.
If the variable is found, look it up in the tracking system to
match the pages seen. If the page number was already used, bump to the login
screen
Add the current page number to the tracking system (this number
must not be used anymore)
Create a new page number from a random system avoiding numbers
already used
Append this new page number to all links in the page
From this point on, any link will look at least like :
asdf.aspx?random_page_number=987
And the number should always change automatically on
each page request. All the links in the page ask for the same number and it's
normal. The point of adding this number to the links makes it impossible for a
user to go back in its history of press back since he will ask for a URL
containing the random variable number that was already used before when the
page was asked.
Potential security flaws
It is possible for anyone to copy a URL and append whatever number
he knows has not been used yet; therefore, the person can re-ask the page anew.
A quick fix to that is to create a hash of the page number. (Get something
complex that is very hard to crack, not just a sha1 or md5, that's too easy)
That hash number must be based on the random number already generated. If you
append this hash with the random_page_number you created, just add one more
step to your initial verification to recreate the hash from the page number. If
the new generated hash and the provided hash are the same, you can assume
either the person has cracked your hash code algorithm therefore your security
is cracked or that the hash provided and the page number have not been tempered
with…
Problems concerning this method
This method obviously takes a lot of space in memory to work with
depending on the way your implement the page tracking. It's certain that if you
have 5 pages to visit max, a random number of 0 to 99 is great; this means the
person can visit a total of 100 pages before touching the limit. This then
bumps the user back to the login and the tracking system is reset for this
user's session. Why put a limit? Simple, first of all random number generation
has to have a limit; second, you want to limit the size of the tracking stack.
Having too many items in the stack depending on your tracking method can be
dangerous. For example, we chose a simple session based tracking with 0 to 999.
This limits us to 1000 page navigated, but the problem is not there, imagine
the numbers 0 to 999 lined together with commas. This makes the session data
very heavy in the long run. Databases will handle this more gracefully but to
the cost of adding several new SQL queries on each page just for that...
Conclusion
Good system, lots of alternative ways to build it,
lots of alternative ways to secure it. Have fun with it…