Let's see..previously i was researching on session attacks and find it really useful in ensuring a web portal to be secured on the server side. Preventing client side security was also discovered on XSS. However, i missed out something important on the client side that is required to protect my users! Another important security measure that i forgotten was cross-site request forgery! Therefore, in this article i will write all the things i know about such attack and how serious it can affect your web portal.
Cross-Site Request Forgery
Cross-site request forgery which is also known as CSRF. CSRF attacks exploit the trust that a site has for a particular user. This means that the attacks is launched by one of the users of the website. Unlike XSS which exploits the trust a user has for a particular site, CSRF exploits the trust that a site has in a user's browser. As mention on XSS article where images can be placed with URL instead of image is the exact thing that is happening on CSRF.
Example of Cross-Site Request Forgery
Let's consider an example of cross-site request forgery. Assume there is a user 'Attacker A' in your system. Your system is an auction site or any site that required credit on an account in order to perform a service or purchase a product. Currently, 'Attack A' do not have any credit. He wants to find a way to get it and CSRF is something he wished to do.
Let's say the attacker send an email to the administrator to enquiry him on a particular issues and embedded some harmful links back to their site as shown below,
Hi, i have a problem updating the following images <img src='http://example.com/givecredit.php?give=clay&credit=9999' width='200px' height='200px'/> into your form <a href='http://example.com/givecredit.php?give=clay&credit=9999'>this</a> particular page to purchase credit. i tried and it return me an error message. Please help me out on this. Regards, Clay
On the PHP part we have a handler givecredit.php as written below,
<?php #validate session and cookie to check whether the user is logged in if(isLogin()) { $clean['give'] = filter($REQUEST['give']); $clean['credit'] = filter($REQUEST['credit']); addAmount($clean['give'], $clean['credit']); #other instructions } ?>
Our not careful administrator entered the link on the email to verify (this is also used to trick administrator of a site to attempt an XSS attack) and an attack was launch on the site easily. Please take note that the display on the email is totally pure text and images without any html code written unless the user change the mode of viewing. On the other hand, the administrator is logged in, the code will be valid and whatever within the code will be run. This is the best way to illustrate cross-site request forgery (CSRF).
Requirement of Cross-site request forgery
An attacker will have to consider a few requirement before CSRF can be achieved.
- A site that doesn't check the Referrer header (which is common) or a victim with a browser or plugin bug that allows Referrer spoofing
- A form submission page that is useful for the attacker (example, getcredit.php)
- Guess all the correct value needed for such submission page to be valid. If there is a need for a valid identifier in the previous page and the attacker can't guess, CSRF will fail.
- Attack must lure the user to the page or mail to click on the link provided or visit the page to cause the damage
Different CSRF Attacks Location
There are many places that CSRF codes can be placed to lure victim into clicking them. Some doesn't even required any clicking as it is embedded on the page itself. Below are some examples.
#IMG SRC <img src="http://example.com/getcredit.php?give=clay&credit=9999"> #SCRIPT SRC <script src="http://example.com/getcredit.php?give=clay&credit=9999"> #IFRAME SRC <iframe src="http://example.com/getcredit.php?give=clay&credit=9999"> #JavaScript Methods 'Image' Object <script> var obj = new Image(); obj.src = "http://example.com/getcredit.php?give=clay&credit=9999"; </script> #'XMLHTTP' Object, $_POST is vulnerable as shown below #IE <script> var post_data = 'give=clay&credit=9999'; var xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); xmlhttp.open("POST", 'http://example.com/getcredit.php', true); xmlhttp.onreadystatechange = function () { if (xmlhttp.readyState == 4) xmlhttp.responseText; }; xmlhttp.send(post_data); </script> #Mozilla <script> var post_data = 'give=clay&credit=9999'; var xmlhttp=new XMLHttpRequest(); xmlhttp.open("POST", 'http://example.com/path/file.ext', true); xmlhttp.onreadystatechange = function () { if (xmlhttp.readyState == 4) xmlhttp.responseText; }; xmlhttp.send(post_data); </script>
As shown above, using GET, POST or REQUEST can still be vulnerable. But using POST can caused certain level of difficulty for the attackers. Thus, using POST is still preferable.
Solutions to cross-site request forgery
We see above how CSRF can be used to attack our server and caused important monetary value to be wrongly distributed. We won't want this to happen to our users. Hence, some protection has to be implement into our server. On the other hand, end user will also be advisable to perform certain action on a portal to further protect themselves in a website (in the case where CSRF can be launch against you)
End user
Below list some solutions for end user to protect themselves from poor implementation site.
Always log out
It is a good practice to always log out any web application after finish using. Logging out will help ensure any attempt to use your account for attacker benefit is eliminated.
Don't save password/username
It is best not to save any password and username on any browser to prevent other form of attacks. 'Remember Me' feature should not be used as it will usually logged in the user automatically upon accessing the site. Hence, 'Always log out' principle became invalid since every visit will always automatic logged in the user.
Use difference browser for different purpose
Pure surfing and accessing sensitive data on your web application should be separated to prevent attacks on your sensitive data. Default browser will always be used for pure surfing while other non default browser should be used for sensitive data access usage. This will help ensure that links or unknown page accidentally visited will not caused major damage to your sensitive data.
Plain text email
Although it is always secure to view your email in plain text to easily identify any attacks and eliminate script from running through opening an email. However, it is not practical to do this. Thus, always try to use plain text for any suspicious email or check the links on the mail before clicking it.
Avoid Spam Mail
Spam mail are usually mails that contains such attacks which are being reported by other users to the email provider. Hence, avoid displaying external images or not clicking links in "spam" or untrusted e-mails may also help.
Developer
Below listed some ways to protect our users against cross-site request forgery attacks.
Always use POST method
Although using POST can still be vulnerable to CSRF attacks through flash application or XMLHttps request as shown above. Nonetheless, it does make it harder for attackers to exploit your system structure than using pure GET or REQUEST method. However, this doesn't really solved CSRF attack problem.
Always check HTTP Referrer header
Another simple counter measurement against CSRF attacks is to check the HTTP Referrer header. However, the header is optional and may not be present. In some browsers, it is disabled and is not available when interactions occur between HTTPS and HTTP served pages. The risk of header spoofing exists, and tracking the valid sources of invocations may be difficult in some applications. Hence, empty or invalid HTTP Referrer header should be marked as dangerous and access should be denial.
Automatic Log out
Implement automatic log out mechanism for your web application will greatly help your user to secure their account from being attacked. One of the criteria that makes CSRF attack possible is when user remain logged in to the website while links or page is being visited. Automatic log out mechanism can help minimize such mistake made by the users and reduce the risk of CSRF attacks.
Authenticate POST and Cookie data
Another security measure is to authenticate your variable POST and Cookie data. We can ensure that the global variable is being authenticate by ensuring certain criteria is being met such as length, data type, value and etc. This can help ensure other form of attack is eliminated and possible CSRF attack is being minimized. On the other hand, Cookie data can be manipulated by attacker and is required to be authenticate always through some information such as information previously stored in the cookie that can be verify through your database or user browser.
Double Confirm Form Submission
Another simple method you can apply is to write a simple script to alert the user of an action to be performed on behalf of the user before processing so that the user is aware that some form of submission is being create out. Another more proper way of handling such confirmation is to send in an email or sms to authenticate the action by providing an action code to be submitted by the account user themselves. This will help prevent the attackers from getting what they want when they do not hold the email or sms of the system provided. (sniffing is possible but the whole process harden the system security)
Secret Key Required
Make all form submission required a secret key to be passed along. The key will act as a protection for our user as the key is generated by a self made authentication process that will change in every form submission. typically this key is tied to the user session and validate that you get the same value back in the form post. In this way, we can ensure that the session contains such secret key and post method also return such key to verify that the submission is valid and previous page was a form. The form is the one which initial the session key and post key that will be bought to the submission page. If the user have not visited the form page and was bought directly to the form submission page, the attack will fail since the key wasn't provided and generated on the form page previously. Consider the following form which create the key initially.
<?php session_start(); $key = md5(uniqid(rand(), TRUE)); $_SESSION['key'] = $key; $_SESSION['key_time'] = time(); ?> <form action="givecredit.php" method="post"> <input type="hidden" name="key" value="<?php echo $key; ?>" /> <p> To: <input type="text" name="give" /><br /> Credit: <input type="text" name="credit" /><br /> <input type="submit" value="Submit" /> </p> </form>
On the form submission page we will validate whether the submission and post value is the same.
<?php if(isset($_POST['key']) && isset($_SESSION['key'])) if ($_POST['key'] == $_SESSION['key']) { $key_age = time() - $_SESSION['key_time']; if ($key_age <= 600) { /* Less than ten minutes has passed. */ } } ?>
if we didn't get the post key value and session key value to be identical, we can assume there is an attempt of attack on our system and you might consider to log that up for further investigation and protection.
Below contains some recommended reading which is pretty good in this topic.
Good Reading
Below are some resources on CSRF
Summary
Even Digg, GMail, and Wikipedia suffer CSRF attacks previously. Do not make such mistake and protect your system carefully before it become a problem in your system. The solutions above might not be full bullet proof solution for future cross-site request forgery attacks. Nonetheless, it can be used for discussion on solutions of future such attack.