Securing PHP Web Forms from CSRF Attacks - Synchronizer Token Pattern
What is CSRF
Cross-Site Request Forgery (CSRF) is an attack that forces an end user to execute unwanted actions on a web application in which they're currently authenticated. CSRF attacks specifically target state-changing requests, not theft of data, since the attacker has no way to see the response to the forged request.
With a little help of social engineering (such as sending a link via email or chat), an attacker may trick the users of a web application into executing actions of the attacker's choosing. If the victim is a normal user, a successful CSRF attack can force the user to perform state changing requests like transferring funds, changing their email address, and so forth. If the victim is an administrative account, CSRF can compromise the entire web application.(
[To see links please login or register here])
what is synchronizer token pattern
Synchronizer token pattern (STP) is a technique where a token, secret and unique value for each request, is embedded by the web application in all HTML forms and verified on the server side. Then the token is generated by the server with ensuring the uniqueness. The attacker is thus unable to place a correct token in their requests to authenticate them.(Wikipedia)(Image 1)
Implementing CSRF Protection in PHP
In here I have implemented a PHP based money transferring application for the demonstration purpose. This application generates two CSRF tokens for the login form and the money transferring form.
This is a simple login form (login.php) with username and password (Image 2). I have hard coded the username and password as "admin":"admin". I added a token for the login form as well For greater security. if someone tries to bruteforce the login credentials, it won't work because, one token can use for a one submission. every time the form submits it checks the token and validate it.
When this page loads it will call a function named "csrf_token_gen()" in "csrf_token.php" which generates tokens.(Image 3)
When this function(Image 4) is called it will generate a token and save it in a session called "csrf". Then the generated token returns to the login.php.
The returned token is saved as a variable called "$token" which will print as a hidden input value named "csrf" inside the login form.(Image 5)
When the user submit the form, "csrf" token will be submitted along with the username and password.(Image 6)
The submitted data send to the "login_check.php" to validation. First it checks the session "csrf" is set and assign it to a variable called "csrf" and compare it with POST csrf token to check both are equal.(Image 7)
Then check if the user entered the valid credentials and username and session id are saved as cookies and unset the csrf token that used for the login submission.(Image 8)
then the user will redirect to the "transfer.php". (Image 9)
If someone tries to submit the form with the same token, they will see the error message below (Image 10). Therefore, the user must refresh the page to regenerate another token.
Money transferring form
After successful login, the user will redirect to the Money transferring form (transfer.php) (Image 11). This is also a simple form which used to transfer money (only for the demonstration purpose). To make the transaction, the user has to enter the amount and click the transfer button.
When this page loads, using the below script(Image 12), AJAX sends a POST request to get the token from the "csrf_token.php".
After receiving above request below PHP code(Image 13) checks, if it is a valid request, and call functions to generate the token and map the token with the session id.
"csrf_token_gen()" function(Image 14) is used to generate the token as earlier and save the token in a session callled "csrf" and returns the token.
"csrf_map()" function(Image 15) is used to map the token with the session id. First, this function checks if the session id cookie ("sid") is set and then it assign to a variable called "$sid". Then map it with the received token from the function parameters and save it in a session called "map".
after running this function, above php code(Image 13) send the token as AJAX response to the transfer.php. Then it will print as a hidden input value named "csrf" inside the money transferring form.(Image 16)
The submitted data send to the "transfer_check.php". As below php code(Image 17), first it checks the session "map" is set. and split the token and session id from the session "map" and assign them into variables called "$csrf" and "$sid".
Then check the POST token and the "$csrf" is equal or not. And get the cookie "sid" from the browser and check if it is equal to the "$sid". If both are equal, it will do the transaction.(Image 18)
if not, it will show error messages as below.(Image 19)(Image 20)