It is known as Cross-Site Request Forgery, or XSRF for short. XSRF is a form of temporary identity theft that can cause your computer to initiate banking transactions, send emails or text messages, or even change account info on your favorite site... without your ever realizing it!
THE GOOD NEWS
Before we get started on the doom and gloom, you should know that XSRF, while potentially very devastating, is actually very easy to defend against.
Also, many modern sites employ anti XSS and XSRF techniques (such as the ones listed at the bottom of this article) so that even if somebody tried to pull an XSRF on your account, it would not work.
THE SETUP
As an example of XSRF in action, suppose your favorite bank has a website that uses $_GET to pass account transaction data. So if you wanted to transfer $100 from account 1002 to account 1004, you'd go to:
Expand|Select|Wrap|Line Numbers
- http://myawesomebank.com/transfer.php?from=1002&to=1004&amt=100
Wrong.
So our intrepid hacker goes to your favorite forum site, and creates a post with an image tag in it. But instead of a valid image file, he gives it a nasty uri:
Expand|Select|Wrap|Line Numbers
- <img src="http://myawesomebank.com/transfer.php?from=1002&to=1004&amt=100" />
Now for the fun part. Let's say you were recently visiting myawesomebank.com to check your account balance. Let's also say that, like most normal people, you didn't log out of your account before closing the browser window. Tsk Tsk.
You notice that there's a new post on your favorite forum site, so you go look at it. Oddly, there's an image on there, but it won't show up.
You refresh the page a few times, but you can't see the picture. You give up and go to bed.
The next day, when you go to check your account balance, you're short $500!
WHAT HAPPENED?
When you opened the page that contained the XSRF code, your browser saw an IMG tag and sent a request for the src of that image as part of loading the page.
Never mind that the src didn't end with a valid image extension; that's actually fairly common, as many sites will use a PHP (or other server-side) script to fetch images from a database or outside the server's document root.
So your browser sent the request, and it got a response, namely myawesomebank.com's "transaction complete" page. Of course, this wasn't valid image data, so your browser didn't show you anything.
"But," you might insist, "I wasn't on my bank's website when I loaded the XSRF code!" Maybe you THOUGHT you weren't, but according to your bank, since your session cookie was linked to an unexpired session, you actually were STILL LOGGED IN! Which means that any requests that got sent to your bank's server were processed, even though you didn't type the location into your address bar!
HOW TO PROTECT YOURSELF
- ALWAYS log out of any site that you log into before closing your browser window or going to a different site.
- If an image isn't loading (ESPECIALLY on a 'public-writable' site such as a forum or mailing list, DON'T REFRESH THE PAGE! Right-click on the image and select 'Propertes' (on IE or FireFox), or 'Copy Image Address' (on Safari) and VERIFY THAT THE FILE IS AN IMAGE.
- If you think you are a victim of XSRF, TAKE ACTION IMMEDIATELY! Contact the administrator of the site that was targeted and get the damage undone!
- If you think someone has posted XSRF code on a forum or other site, inform the site administrator IMMEDIATELY so that he can remove the code and ban the offender!
HOW TO SECURE YOUR SITE AGAINST XSRF
- NEVER pass sensitive data in the address. Use POST as much as you can.
- Check the referring page (via $_SESSION['HTTP_REFERER']) before executing any backend code! If the domain doesn't match yours, DON'T PROCESS THE REQUEST!
- Enforce session timeout. When the User hasn't submitted any requests for a period of time, his session should automatically expire.
APPENDIX A: ENFORCING SESSION TIMEOUT
You ever notice how on some sites, if you leave the computer for awhile and then come back, when you click on a link, the site will ask you to log in again because "your session timed out due to inactivity".
How do they do that?
Well, you can't really use a 'timer' because the web doesn't work that way. You don't know when the User will click on a link... or even if he's still on your site! Instead, you have to do sort of a 'reverse timer'.
Instead of counting down from a static 'amount of time until expiration', you compare the timeout variable to the current time and then store the new timeout value.
Expressed in code:
When the User logs in, set his initial timeout value. Traditionally, the User gets 15 minutes of inactivity before his session becomes invalid. Of course, depending on the nature of your site, you may choose to use a different value.
Expand|Select|Wrap|Line Numbers
- // When you log the User in, set his timeout:
- define('SESSION_TIMEOUT', 15);
- $_SESSION['timeout'] = (time() + (SESSION_TIMEOUT * 60));
Expand|Select|Wrap|Line Numbers
- session_start();
- // Check to make sure the User is logged in.
- if(! checkToSeeIfUserIsLoggedIn(yourCodeGoesHere))
- {
- .
- .
- .
- }
- // Check to see if the current time is AFTER the session is marked for timeout.
- if(time() > $_SESSION['timeout'])
- {
- // User's session has expired. Go back to the login screen.
- header('Location: login.php?message=timeout');
- exit;
- }
Expand|Select|Wrap|Line Numbers
- if(isset($_SESSION['timeout']))
- $_SESSION['timeout'] = (time() + (SESSION_TIMEOUT * 60));