“I connect as always to my blog, I decide to write a new awesome post about Harry Potter. Meanwhile, I walk on other sites and when I return to my blog, horror, no post. All previously written articles are erased and I do not understand what happened. I did not touch anything! ”

This story could well be the result of a successful exploitation of the CSRF fault , very easy to implement and very formidable.

What is the CSRF Fault?

The CSRF name comes from Cross-Site Request Forgery which, if one tries to give a definition in French, means Falsification of inter-site query. We are not more advanced, I know.

In fact, it is about performing an action aimed at a site or a specific page by using the user as a trigger, without being aware of it.

We’ll guess a link that a user usually gets, and just make sure that he clicks on that link himself.

An example ?

By repeating the story above, we can imagine that on a given blog, the link to delete an article is as follows:


Here, id = 1 means that we want to delete the article whose identifier is 1 , typically it is the first article.

If a visitor who is not connected to the administration page now clicks on such a link, he will have a message of the type:

You do not have the rights to delete this item, please login and try again.

Normal, any visitor does not have the right to edit or delete articles from a blog that does not belong to him.

But now if any visitor knows this link , it is enough for him to send the link to the administrator by making sure that the latter clicks.

What happens after the administrator clicks?

The delete link runs successfully because the administrator is connected and his article is deleted.

How to protect yourself against CSRF?

Usually, if you use a content management system (CMS) like WordPress or Joomla, which is a protected minimum, you do not have much to do. Finally …

If, on the other hand, you are using an old system or have programmed yourself, this risk is present.

To protect against the CSRF fault, 2 complementary principles are usually used:

Token authentication

A token (also known as a token ) is a number or string of random characters that will be tested before any modification or edition of an article.

It usually comes in the form of hash md5 like this:


This token must be created in a PHP file that will be called on all pages. Typically, it is a file of the type config.php or functions.php .

We often generate a “random” number with functions using time in PHP. For example we can generate a token with:

  md5 (uniqid (mt_rand (), true)); 

The uniqid () function generates a unique time-based identifier in microseconds. However PHP does not recommend this function because it does not generate strings that can not be guessed in advance.

So, we will rather use:

  md5 (bin2hex (openssl_random_pseudo_bytes (6))); 

which is this time highly secure .

The function openssl random pseudo bytes () generates a pseudo-random string of bytes of size 6 bits * 2 which is then converted into hexadecimal, 6 being the number given in parameter of the function (it can be changed).

So, in a global PHP file we will write the following code:

  <? Php
if (! isset ($ _ SESSION ['token'])) {
$ _SESSION ['token'] = bin2hex (openssl_random_pseudo_bytes (6));

This code means: If the session token is not yet defined, it is generated randomly and saved for the current session.

Then, each time a user logs in, we will have to generate a token of his own .

For that, one can before each connection regenerate the token, by removing the token of the previous session:

  unset ($ _ SESSION [ 'token']); 

It remains then to dynamically modify the deletion links, let us admit that the previous link was written of the form:

  <a href = "http://www.domain.com/del.php?id= <? echo get_article_id ();
? >> Delete the article </a>

It is replaced by:

  <a href = "http://www.domain.com/del.php?id= <? echo get_article_id ().
"& Token =". $ _ SESSION [ 'token']; ? >> Delete the article </a>

The delete URL will be displayed like this:


Instead of displaying like this:


And finally, in our del.php deletion file , we will make sure that there is a token and that this token is valid. The file, before any modification, was like this:

  <? Php
if (isset ($ _ GET ['id'])) {
supprimer_article ($ _ GET [ 'id']);
} else {
die ("No selected article ID.");

It becomes:

  <? Php
if (isset ($ _ GET ['id']) && isset ($ _ GET ['token']) &&
($ _GET ['token'] == $ _SESSION ['token'])) {
supprimer_article ($ _ GET [ 'id']);
} else {
die ("Invalid session ID or token.");

Which means: If the id of the article is defined but also the token and that token corresponds to the current session’s token, then we can delete.

Last note, we use $ _GET which retrieves the parameters from a URL, it would have been better is even more secure to use $ _POST with a form to not display a token in the URLs.

Confirmation request

Whether to avoid deletion by mistake or attempts to exploit the CSRF flaw, it is essential to request confirmation of deletion of an article.

Here, if I click delete my article and it is immediately and permanently deleted, you have to think three times before clicking.

This method is used a lot to redefine a password: First, ask for the old one.

Watch out for CSRF security techniques that do not really work.

We often hear that to guard against the CSRF flaw, we must check the HTTP_REFERER PHP variable which indicates which site the user comes from. If it comes from a different site, then it will not be allowed to edit the article.

Yes it is a good idea at the base (and it is always a complementary protection), except that the referent link ( HTTP_REFERER ) can be modified (one says spoofed ).

This variable is defined by the browser, so the client side . That is to say that I can very well post the link http://www.monblog.fr/del.php?id=1 from another site, while making believe that it comes from the same site, example with cURL:

 curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'Host: www.domain.com', 'Referer:
', 'FauxHEADER: FauxHeaderQuiSeraEnvoye'));

Last remark

Ajax ( Asynchronous JavaScript and XML ) allows you to perform actions without reloading the page. Typically this is what happens when you click the Facebook Like button . The request is sent in the background and the button becomes depressed when the server response has arrived.

So the question of the CSRF flaw arises, what happens if we try to delete a post using Ajax?

The answer is simple, Ajax uses the Same-origin policy that prevents code execution across sites. The term “origin” is defined about the protocol, the domain name and the port: two pages have the same origin if and only if these 3 values ​​are the same .

Want to learn more about web vulnerabilities?

This flaw and many more is seen in detail in my video course on web intrusion testing.

We will talk about the fundamentals: how HTTP, HTTPs, DNS and web architecture work in general.

We will also set up a test lab with virtual machines to host and scan our vulnerable sites to learn without breaking anything.

We will of course talk about all the web vulnerabilities (XSS, CSRF, SQL, LFI, RFI, … etc) by following the Top 10 OWASP but also of all that revolves around web security: denials of service, bad configurations, personal data, recognition, etc …