473,320 Members | 2,107 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes and contribute your articles to a community of 473,320 developers and data experts.

XSRF: What is it, How does it work, and How can you thwart it?

pbmods
5,821 Expert 4TB
A somewhat obscure hack has emerged recently that is an offshoot of the now-infamous XSS.

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
  1. http://myawesomebank.com/transfer.php?from=1002&to=1004&amt=100
At this point, you are probably thinking, "there's something REALLY wrong with that!" And you're right. But no problem... even if somebody tried to go to this URL to make a quick $100, he'd still have to be logged in to do it, right?

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
  1. <img src="http://myawesomebank.com/transfer.php?from=1002&to=1004&amt=100" />
  2.  
THE HAPLESS VICTIM

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
  1. // When you log the User in, set his timeout:
  2. define('SESSION_TIMEOUT', 15);
  3. $_SESSION['timeout'] = (time() + (SESSION_TIMEOUT * 60));
  4.  
Then put this code at the top of every page that requires the User to be logged in:
Expand|Select|Wrap|Line Numbers
  1. session_start();
  2.  
  3. // Check to make sure the User is logged in.
  4. if(! checkToSeeIfUserIsLoggedIn(yourCodeGoesHere))
  5. {
  6.     .
  7.     .
  8.     .
  9. }
  10.  
  11. // Check to see if the current time is AFTER the session is marked for timeout.
  12. if(time() > $_SESSION['timeout'])
  13. {
  14.     // User's session has expired.  Go back to the login screen.
  15.     header('Location: login.php?message=timeout');
  16.     exit;
  17. }
  18.  
You may also want to extend the User's timeout even when he is using the non-secured pages on your site:
Expand|Select|Wrap|Line Numbers
  1. if(isset($_SESSION['timeout']))
  2.     $_SESSION['timeout'] = (time() + (SESSION_TIMEOUT * 60));
  3.  
Jul 20 '07 #1
11 26348
tscott
22
Hey,
Nice Tutorial although I would like to add that this is VERY hard to do for hackers and is not as simple as.
[html]
<img src="http://myawesomebank.com/transfer.php?from=1002&to=1004&amt=100" />
[/html]

The only way you can use a PHP file like that is if it is a php generated image. The file itself can't do anything except parse the image otherwise html doesn't process it. I've tried to make a PHP generated image that takes logs. It's impossible and it's denied.

USUALLY this is done by your users clicking a php link (usually disguised as another object). That goes to a script that hijacks your cookie usually or it may include that file that they get from your cookie or session.

It could also be included to a site. But no, it can't be used as an image, you can breath a little easier now ;) . Although yeah... Definately check the referer although that is pretty easy to disguise but not for the purposes here.

$_GET is evil, never use it, On forms to change the page have it submit a post form. Or have them click a checkbox that equals the value of the next page. Etc... This totally will eliminate the need for $_GET.

~Tyler
Jul 24 '07 #2
kovik
1,044 Expert 1GB
I felt that this article was very incomplete, so I'm going to add a bit.

You didn't mention how $_SERVER['PHP_SELF'] opens you up to XSS, or even the more dangerous forms of XSS, such as injection of JavaScript.

Did you know that you could go to ANY website, then simply type some JavaScript code and run it? The next time you make a post (finish typing it first), type this into the address bar:

javascript:document.vbform.submit();

This will submit the form. Luckily, this can't be injected into URLs using 'javascript:', but if you print any unfiltered URL data, a user can inject any code into that URL and pass the 'infected' URL to someone else.

For example, if I went to 'page.php?a=<script type="text/javascript">window.location='http://www.volectricity.com';</script>' and anywhere on your page, you printed out the value of $_GET['a'], I could pass that URL to someone and send them elsewhere. And, every single ASCII character can be url-encoded, so I could even force it to no longer be plain-text and you'd be none the wiser.


Also, you completely neglect XSS inside of HTML such as the dangers of unfiltered user profiles, comments, blog entries, forum signatures, and any other user input.

I just wrote the article on XSS today, so I was surprised to find this post missing all that I had mentioned.
Jul 28 '07 #3
pbmods
5,821 Expert 4TB
Tyler,

While you are correct that the browser will not display the code in the IMG tag, realize that the browser doesn't know if the SRC attribute's value represents a valid image. It can only find this out by sending a request for that file to the server!

In the case of the example illustrated in the article, the browser sends a request for transfer.php?from=1002&to=1004&amt=100 to myawesomebank.com. Since, according to myawesomebank.com, the User was still logged in, the script would EXECUTE THE TRANSFER, and then send back the 'transfer complete!' HTML page.

You would never see the actual HTML, of course, because the browser would not show non-image data inside of an IMG, but the damage was still done; the browser still sent a request to the bank website that initiated the $100 transfer.

Volectricity,

The 'oversight' was intentional. XSS is becoming a security buzzword, and I wanted to focus on XSRF, which is arguably a facet of XSS.
Jul 28 '07 #4
kovik
1,044 Expert 1GB
Volectricity,

The 'oversight' was intentional. XSS is becoming a security buzzword, and I wanted to focus on XSRF, which is arguably a facet of XSS.
Understood.

I'd also like to add that any tag that accepts a 'src' attribute is vulnerable to the <img> tag exploit. The 'src' attribute accepts any file and opens it, regardless of what it is.


I do like your suggestion for timing out sessions, however. :-D
The best way to do it is to also make sure that the session technically lasts longer than the timeout you have given so that the $_SESSION['timeout'] will still exist. The session GC is generally unpredictable.
Jul 28 '07 #5
nathj
938 Expert 512MB
I felt that this article was very incomplete, so I'm going to add a bit.

You didn't mention how $_SERVER['PHP_SELF'] opens you up to XSS, or even the more dangerous forms of XSS, such as injection of JavaScript.

Did you know that you could go to ANY website, then simply type some JavaScript code and run it? The next time you make a post (finish typing it first), type this into the address bar:

javascript:document.vbform.submit();

This will submit the form. Luckily, this can't be injected into URLs using 'javascript:', but if you print any unfiltered URL data, a user can inject any code into that URL and pass the 'infected' URL to someone else.

For example, if I went to 'page.php?a=<script type="text/javascript">window.location='http://www.volectricity.com';</script>' and anywhere on your page, you printed out the value of $_GET['a'], I could pass that URL to someone and send them elsewhere. And, every single ASCII character can be url-encoded, so I could even force it to no longer be plain-text and you'd be none the wiser.


Also, you completely neglect XSS inside of HTML such as the dangers of unfiltered user profiles, comments, blog entries, forum signatures, and any other user input.

I just wrote the article on XSS today, so I was surprised to find this post missing all that I had mentioned.

Volectricity,

I read your article, very informative and opeened my eyes to a few areas I need to change on my own site. I note the suggested use of basename() so I did some reading around to see how it works.

What I don't understand is how this can be used to tell you where you are - what the current url is? I use $_SERVER['PHP_SELF'] to figure this out and it works nicely. The purpose is to disable a navigation item if you are on that page. How would basename be used in that case?

Cheers
nathj
Aug 8 '07 #6
kovik
1,044 Expert 1GB
What I don't understand is how this can be used to tell you where you are - what the current url is? I use $_SERVER['PHP_SELF'] to figure this out and it works nicely. The purpose is to disable a navigation item if you are on that page. How would basename be used in that case?
basename() can be used to get the name of a particular file. $_SERVER['SCRIPT_NAME'] will give you the URL of the file actually being executed minus the XSS vulnerability of PHP_SELF.

Do some testing. print_r($_SERVER) and play around with the URL. A little interesting thing I noticed once was that PATH_INFO is created when you add a slash to the end of a script name, as well as PATH_TRANSLATED as though the server was attempting to check if two requests were being made at once. I can't state these as set in-stone facts though, because different servers work differently.

Really, the point of the article is never to trust URLs. They are user input no matter how you slice it.
Aug 12 '07 #7
Thanks for bringing this to our attention :)
Aug 12 '07 #8
pbmods
5,821 Expert 4TB
Thanks for bringing this to our attention :)
No problem (I'm hoping you were directing that at me!).
Aug 12 '07 #9
nathj
938 Expert 512MB
basename() can be used to get the name of a particular file. $_SERVER['SCRIPT_NAME'] will give you the URL of the file actually being executed minus the XSS vulnerability of PHP_SELF.

Do some testing. print_r($_SERVER) and play around with the URL. A little interesting thing I noticed once was that PATH_INFO is created when you add a slash to the end of a script name, as well as PATH_TRANSLATED as though the server was attempting to check if two requests were being made at once. I can't state these as set in-stone facts though, because different servers work differently.

Really, the point of the article is never to trust URLs. They are user input no matter how you slice it.

Hi Volectricity,

Thanks for answering my question, I think I have a better understanding of what attacks may threaten a site, and how to handle some of them.

Cheers
nathj
Aug 14 '07 #10
FLEB
30
Hey,
Nice Tutorial although I would like to add that this is VERY hard to do for hackers and is not as simple as.
[html]
<img src="http://myawesomebank.com/transfer.php?from=1002&to=1004&amt=100" />
[/html]

The only way you can use a PHP file like that is if it is a php generated image. The file itself can't do anything except parse the image otherwise html doesn't process it. I've tried to make a PHP generated image that takes logs. It's impossible and it's denied.

...snip...

~Tyler

If the action is performed by the PHP script on the server side, it's done when the request is made, not when the browser interprets the reply. A more reasonable example than this "bank" script (and one that comes up in the real world) would be a poorly-designed log-out script.

Oftentimes, a site will have a "Log out" link or button, that goes to a simple PHP page. The PHP page-- call it "logout.php" takes no input, and merely invalidates the session on the server (so the session cookie will no longer work), and possibly reset the client's cookie. Then, the script either returns an HTML "Thank you" page, or redirects to the home page.

Even though the document returned is HTML-- not an image-- the action is still taken when the "logout.php" page is hit. Thus, if a person posts the image:

Expand|Select|Wrap|Line Numbers
  1. <img src="http://www.example.com/logout.php" />
it will result in the viewer being logged out of the site. The fact that the returned content-- an HTML page-- cannot be understood by the browser is irrelevant. As a result of the file being requested, the server-side action was taken.

This also applies to requests that use information passed via the GET protocol. Simply add the GET variables...

Expand|Select|Wrap|Line Numbers
  1. <img src="http://www.example.com/logout.php?orly=yarly" />
...and it's just as if you'd passed a link or submitted a form.

To prevent this, even simple scripts that cause server-side effects should have a "gatekeeper" token that gets passed via a POST submission. While an image tag can simulate a GET (which is, after all, just information appended to the URL), it cannot simulate a POST request.

So, this logout script should be called by a simple form with a HIDDEN field and a submit button:

Expand|Select|Wrap|Line Numbers
  1. <form method="POST" action="logout.php">
  2. <input type="hidden" name="really" value="yes" />
  3. <input type="submit" value="Log Out" />
  4. </form>
  5.  
Then, test for the existence and value of the $_POST['really'] value before actually doing anything.

Now, the one thing you can't do with a simple injection like this is read or redirect the information that is returned. Given that the file is in a format that can't be understood by the browser (an HTML page in an Image context), the only actions you can really take with a static "reference" attack like this are ones that can be performed in a single action, and without needing to know the outcome.
Aug 21 '08 #11
bakertaylor28
45 32bit
The better way of dealing with XSRF is to deal with it outside of PHP. XSS/XSRF is better dealt with by sending the appropriate headers in the server config (e.g. apache's conf file using mod_headers). This is because if the server forces headers that prevent XSS/XSRF we then prevent PHP (or any other CGI) from invoking an XSS/XSRF attack. (e.g. we cause Apache, Nginx, etc. to shut down the attack before it even gets started). Therefore, if we are using apache we might do the following in Apache's conf file (If you're not using apache, you should find a way to do the equivlent in the server config file) :

Expand|Select|Wrap|Line Numbers
  1. ###apache2.conf ###
  2. ...
  3. Header always set Cache-Control "private, max-age=0"
  4. Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure
  5. Header always append X-Frame-Options DENY
  6. Header always set X-XSS-Protection "1; mode=block"
  7. Header always set Content-Security-Policy "default-src 'self';"
  8. Header always set X-Content-Type-Options "nosniff"
  9. Header always set Referrer-Policy "strict-origin"
  10. Header always set X-Permitted-Cross-Domain-Policies "none"
  11. ...
  12.  
The only drawback to this is that you have to host your content and assets on the same server, as opposed to being able to load off-server URL references for assets in HTML, etc.
Feb 26 '23 #12

Sign in to post your reply or Sign up for a free account.

Similar topics

7
by: Jonas | last post by:
This works fine in Win XP but does not work at all in Win 98. Private WithEvents objIExplorer As InternetExplorer I have to do it like this to get it to work in Win 98 Dim objIExplorer As...
5
by: me | last post by:
I have a Class Library that contains a Form and several helper classes. A thread gets created that performs processing of data behind the scenes and the Form never gets displayed (it is for debug...
22
by: Robert Bralic | last post by:
CAN anybody tell me any address where I can download some small(1000-2000) lines C++ proghram source. Or send me ,a small(1000-2000) lines C++ program source that I can compille with gpp under...
12
by: Frank Hauptlorenz | last post by:
Hello Out there! I have a DB2 V7.2 Database (Fix11) on Win 2000 Professional. It was before a NT 4 based Domain - now it is a Win 2000 Domain. The database server is a domain member. Now...
11
by: dreamcatcher | last post by:
bool isBlankLine(char *line) { char *tmp=line; bool blank=true; while(*tmp++!='\0') {
0
by: BH | last post by:
I heard there are tools that can disassemble a .NET DLL or EXE into source code in high level language of the choice. I'm not talking about disassembling into the .NET Intermediate Language but...
0
by: Jarod_24 | last post by:
How does tabindex work in ASP .net pages I dosen't seem to work quite like in regular forms. and there isn't any TabStop property either. 1 .How do you prevent a control form beign "tabbed"....
14
by: Anoop | last post by:
Hi, I am new to this newsgroup and need help in the following questions. 1. I am workin' on a GUI application. Does C# provides Layout Managers the way Java does to design GUI? I know that it...
162
by: Sh4wn | last post by:
Hi, first, python is one of my fav languages, and i'll definitely keep developing with it. But, there's 1 one thing what I -really- miss: data hiding. I know member vars are private when you...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
0
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.