CSRF, this abbreviation appears again and again in the WordPress core update notes. The method behind it is now old hat and exploits the usually abundant cookies of a browser. Fortunately, it is quite easy to protect yourself against cross-site request forgery. All you need is a little time and attention.
You probably also use a whole range of services where there is an option to stay logged in even after you have left the website. If you then visit the website again, you don't have to enter your login details again, but are logged in directly. This is of course great because - just like password management or single sign-on - it saves you the hassle of filling in forms.
The following happens in the background: When you log in to the website for the first time, the website stores a cookie in your browser. This is a small text file in which certain information can be stored. In the case of staying logged in, this is a randomly generated string.
The next time you visit the website, the server checks this string and, if it can find the corresponding counterpart, logs you in automatically. Incidentally, this is also the reason why you are logged out everywhere when you clear your browser cache. This is because all cookies are also deleted during this process.
CSRF attacks are essentially an abuse of trust
As you can see, a corresponding attack tricks the service that reads the cookies into believing something. I will explain exactly how this happens below using two examples.
The danger of this manipulation lies in someone making changes to your Facebook profile in your name, for example. However, cross-site request forgery also often relies on phishing. Trust is also relevant here - your trust in the sender of emails, for example.
How vulnerable is WordPress?
You probably haven't heard the term cross-site request forgery as often as brute force attacks or cross site scripting. There is a reason for this: the non-profit organization OWASP (Open Web Application Security Project) regularly publishes a list of the ten most critical vulnerabilities in web applications. Over the years, CSRF has slipped further and further down the list as a security risk and has now disappeared from the top 10.
This is probably partly due to the fact that CSRF attacks are almost as old as the Internet itself. Professional developers are now practiced in securing their code against them. Security risks are therefore quite easily and quickly eliminated.
WordPress is also on guard. For example, security update 4.7.5 was released in May, which fixed six vulnerabilities that could have been used by hackers to launch an attack via cross-site scripting or cross-site request forgery. However, cross-site scripting is often considered to be much more dangerous.
In addition, the issue of cross-site request forgery tends to be more relevant for plugins and applications than for web design, agencies and SMEs. This is because protection against CSRF is also a question of programming. CSRF could become relevant for in-plugin purchases, for example.
But how does it all work?
The anatomy of cross-site request forgery
The basic idea behind a CSRF attack is relatively simple and usually takes place in two steps:
- The victim is tricked into loading a manipulated website or clicking on a link, for example by making it appear that the message is from a trusted person. Or human curiosity is exploited. In other words, phishing plays an important role in this type of attack.
- When the manipulated links or websites are loaded or clicked on, the victim's browser executes an HTTP request without the victim noticing.
Two relatively simple examples illustrate how such an attack works.
Let's assume that Justus wants to transfer €100 to Bob via the website www.bank.de and Skinny is sitting in wait to carry out a CSRF attack. Skinny can use the GET or POST method for his attack.
The following examples are taken from the following sources:
- "Cross Site Request Forgery (CSRF)" - the OWASP overview article
- "Preventing CSRF Attacks In WordPress Using Nonces" - by qnimate.com
Cross-site request forgery with the GET method
The GET method is used to request a resource from a server, for example an HTML file. The parameters required for the call are simply added to the URL. And as we already know from SQL injections: A URL is relatively easy to manipulate.
Justus logs in to www.bank.de and enters all the required data. The following (completely fictitious) input would be sent to the server:
GET http://bank.de/transfer.do?acct=BOB&betrag=100 HTTP/1.1
Skinny now constructs a URL that transfers €100,000 to his own account instead. It looks like this:
http://bank.de/transfer.do?acct=SKINNY&betrag=100000
Of course, Justus has to carry out the action hidden behind the fake link. This is why Skinny sends Justus an e-mail with a fake link. The HTML code can look like this, for example:
<a href="http://bank.de/transfer.do?acct=SKINNY&betrag=100000">Wer dieses Rätsel nicht lösen kann, ist kein echter Detektiv!</a>
Or he sends him an e-mail containing an "invisible" (because 0 by 0 pixels) image. When trying to load the image, the browser accesses the URL without Justus even noticing:
<img src="http://bank.de/transfer.do?acct=SKINNY&betrag=100000" width="0" height="0" border="0">
When Justus calls up the link - consciously or unconsciously - the parameters are transferred to the server, the transfer is triggered and €100,000 disappears from his account.
Of course, Justus has to click on the link while he is logged in. But if, unfortunately, there is a login cookie from his bank in his browser, the attack works even if he hasn't opened the website.
This is exactly what makes cross-site request forgery so insidious: Justus is probably not even aware that the cookie exists.
Cross-site request forgery with the POST method
The GET method can be used in links and is therefore particularly easy to distribute. However, providers can now ensure that GET requests do not receive write authorization in principle.
This leaves the POST method: Here, data is transferred to a server so that it can process it further. However, the data is not part of the URL, but is appended to the header.
It may sound a bit cumbersome, but you are certainly familiar with the use case, because forms work in this way.
For our attacker Skinny, this means that he has to make more of an effort, but can still reach his goal.
Same scenario: Justus wants to transfer money to Bob. So he fills out the following form at www.bank.de:
<form method="POST" action="geld_ueberweisen.php">
<input type="text" name="von">
<input type="text" name="an">
<input type="text" name="betrag_in_euro">
<input type="submit">
</form>
This sends the command geld_ueberweisen.php, which looks like this:
if(isset($_FORM["von"]) && isset($_FORM["an"]) &&isset($_FORM["menge_in_euro"]) && isset($_CMOKIE["user_eingeloggt"]))
{
transMoney("von", "an", "betrag");
echo "Überweisung erfolgreich!";
}
As you can see, the code first uses the cookie to check whether Justus is logged in. Only then will the transfer be executed.
Skinny now stores an invisible form on a manipulated website, for example:
<form method="POST" action="http://www.bank.de/geld_ueberweisen.php">
<input type="text" name="von" value="Justus" style="display: hidden">
<input type="text" name="an" value="Skinny" style="display: hidden">
<input type="text" name="betrag_in_euro" value="100000" style="display: hidden">
<input type="submit" value="Wer dieses Rätsel nicht lösen kann, ist kein echter Detektiv!">
</form>
He sends Justus the link to this manipulated website. He feels challenged, clicks on the button to see the puzzle - and unknowingly executes the function geld_ueberweisen.php. As this finds a corresponding cookie in his browser, another €100,000 is transferred to Skinny.
Attack via detours
Incidentally, this is why it is called cross-site request forgery: the command is usually sent from another website. In order to attack website A, it deposits malicious code on website B. He then lures the unsuspecting victim here so that their browser executes the code.
"*" indicates required fields
How to protect yourself against CSRF attacks
The good news is that cross-site request forgery has been known for ages. The risk is known and the development team is working hard to eliminate it.
The bad news is that you can't actually protect yourself against it on the technical side. The WordPress core is now relatively well protected and, as you can see from the ongoing updates, it is constantly being worked on. As with other types of attack, most vulnerabilities come from plugins. So you have to trust that the extensions you use are being developed well.
In concrete terms, this means:
- Don't install too many plugins and only install the plugins you really need
- Be careful with plugins that have not been updated for some time. Unresolved security vulnerabilities may be hidden here.
- Find out beforehand about the plugins you are installing, for example about their compatibility with other plugins or the WordPress version you are using (so that the plugin can also be updated).
- Update your plugins and the WordPress core regularly. Because the continuous updates are there precisely to close such security gaps.
- Be critical with regard to phishing.
- If you're unsure: take a close look at the plugin in the WP repository. How are the ratings, what were the biggest problems in the past and has the plugin possibly not closed a prominent security hole?
Conclusion: CSRF is old hat
Cross-site request forgery has been around since the beginning of the digital age. In addition, the number of cases is extremely small compared to brute force attacks.
This is also confirmed by the OWASP's assessment, which assumes that the attack is not very widespread, easy to detect and only serious in very specific cases.
Nevertheless, it is good to know how the attacks work. This is because attacks often only work thanks to human error. Time and again, users open emails out of curiosity or click on links that they would have been better off not opening.
The best way to protect yourself from cross-site request forgery is with research and a little common sense.