WordPress nonces are a great way to protect from CSRF attacks which is very common throughout the web. In this article I will explain what is CSRF attacks and how to prevent these attacks in wordpress using nonces.
What is CSRF Attacks?
CSRF (Cross Site Request Forgery) is a type of attack in which requests from user are sent to servers without the user knowing about it.
This kinds of attack are very popular in the internet. Let’s look at an example of this kinds of attacks.
index.php
money_transfer.php
The above code uses cookie to check if the user is logged in or not. If user is logged in then the money transfer is done. This scripts are vulnerable to CSRF attacks. A hacker can embed the above form in any website and send the link to the users and forcing some way to click on it. If the cookie is present then the money will be transfer to the hackers account.
Let’s see how this can be done (assume that user is logged in into bank website):
http://hackersite.com/earnmoney.html
<input type="text" name="from" value="username" style="display: hidden">
<input type="text" name="to" value="hackername" style="display: hidden">
<input type="text" name="amount_in_dollars" value="100000" style="display: hidden">
<input type="submit" value="Click here to get $100000000 dollars">
</form>
This page link can be send to a user who is using bank website. And if the user clicks on the submit button on hackers website the given amount will be transferred which will lead to a disaster. So websites should’t depend on cookies to do critical things.
There are many ways to prevent such kinds of attacks. We will see the best and popular ones.
This kinds of attacks can be prevented by using HTTP Referer header, extra verification step or using special token
Lets see all the above preventing methods.
Preventing CSRF using HTTP Referer
{
//HTTP Referer is the address of the page (if any) which referred the user agent to the current page.
if($_SERVER['HTTP_REFERER'] == "http://www.bank.com/")
{
transMoney("from", "to", "amount");
echo "Money transfer done";
}
}
Some browser allow to change HTTP Referer while requesting a link and also there are many other ways to change or break HTTP referer. So this method should be used along with other methods.
Preventing CSRF using special tokens
if(isset($_FORM["form"]) && isset($_FORM["to"]) && isset($_FORM["amount_in_dollars"]) && isset($_COOKIE["user_logged_in"]) )
{
if($_SERVER['HTTP_REFERER'] == "http://www.bank.com/" && user_token_matches($_FORM["secrettoken"]) && is_not_expired($_FORM["secrettoken"]))
{
transMoney("from", "to", "amount");
echo "Money transfer done";
}
}
?>
Every user will have a random secret token assigned to them whenever they make a request for the form and the token will be encrypted and hidden in the form. This token can only be used once and a new token is generated for every user for every new request for the form. And this token will have a expiry time of few minutes. While submitting the form, the form must have the user secret token. There is no way a hacker can find out the secret token of a user so cross site form submissions will not work.
There are many other factors that can be considered while generating this kind of tokens, this method is an simple and full proved way.
Extra Validation
You can use some extra validation steps before transfer money. These steps can be CAPTCHA validation, Re-Authentication (of password), DOB, mobile message verification etc.
By combining the above three methods we can get the best security possible against CSRF attacks.
What is WordPress Nonces
WordPress nonces are special tokens in WordPress which help in preventing CSRF attacks. Nonces are unique for each operation on WordPress and have expiry time. Nonces can be used to protect URLs and forms which make changes to WordPress(adding, deleting, editing data etc).
Nonces needs to be attached to the forms or URLs manually and also needs to be verified manually.
Generating a Nonce
We can generate a nonce using wp_create_nonce() WordPress function. Nonce generating algorithm generates a nonce based on current day(day changes after every 24hrs), passed string(argument representing action) and user id(if user is logged in). Its not compulsory to pass a string argument to this function but its recommended for more uniqueness.
Verifying a Nonce
Whenever a form or URL with a nonce is submitted we need to verify the nonce to prevent CSRF attacks. wp_verify_nonce() is used to verify a nonce. This function takes the same string passed to the wp_create_nonce. If no argument is passed to wp_create_nonce then don’t pass any string to this function.
An Example Nonce Based Form
This is a simple CSRF protected form which can be embedded anywhere in wordpress
if(isset($_POST["post_id"]))
{
//verify nonce on form submit
if(wp_verify_nonce($_POST["nonce"]) == 1)
{
echo "Successfully deleted post";
die();
}
else
{
echo "Security Error";
die();
}
}
else
{
?>
<form method="post" action="">
<input type="text" paceholder="Enter Post Id to delete" value="" name="post_id" />
<input type="text" name="nonce" value="<?php echo wp_create_nonce(); ?>" />
<input type="submit" value="Delete post" />
</form>
<?php
}