Synchronized Token Pattern is one mechanism to prevent or handle the security attack: Cross-Site Request Forgery (CSRF). My previous post on CSRF will give you an idea about what CSRF is.
Each time a user logs in, a new session is created for the user if the site allows multiple logins like Facebook, allowing users to log in from many browsers and devices. In Synchronized Token Pattern, a random string token is generated in the server side whenever a user logs in and a new session is created. This token is stored in the database mapped to each session of the user. The server then exposes a URL which can be accessed by the user to get the generated CSRF token.
Lets assume that the user is an Administrator making a user account for another user of the system. The admin will fill the form providing the relevant details of the user and submit it. The server will receive all the form details through the request made to the backend.
After obtaining the token, the user can embed the token in a hidden field in the form and send the token in the request along with the user details to the server when posting data. This way, the server can identify whether the request is valid as only a valid request will contain the Session Id, Username, and CSRF token that matches the values stored in the database.
The user must make an AJAX call to obtain this CSRF token. The attacker will not be able to obtain this token, as whenever a browser makes an AJAX call, it validates the current domain against the request domain. If the call is made to www.abc.com, this domain should match in the browser and the server call. The browser will only send the request if the domain matches. By default, making Cross-domain AJAX calls is not possible as it is blocked. It can be enabled if needed, but for these security reasons we do not enable it normally.
As attacker will not be able to obtain the CSRF token using an AJAX call as domains will not match, CSRF will not be possible as attacker's form will not contain the CSRF token, making the request invalid even if all the other details match.
The diagram below illustrates the flow of the Synchronized Token Pattern process mentioned above:
The diagram below illustrates the flow of the Synchronized Token Pattern process mentioned above:
You can visit this GitHub link to view the sample implementation of Synchronized Token Pattern to prevent CSRF. In this example, instead of using a real database, the CSRF token generated for each session is mapped to a PHP key-value associative array in the Server-side, and is used in validating the requests. I have also hard-coded the username and password for demonstration purpose.
Username and Password both: ssd
As in the diagram above:
1. User logs in to the system using index.html. The form action points to login.php, and the form details will be submitted to it when the user clicks the Login button.
Login Page:
2. If the user has provided the correct login credentials, the user is redirected to add_user.html.
login.php:
For each login, a new session is made for the user as mentioned earlier, and it is ensured that a new PHP Session Id is generated for each login after invalidating the already existing session.
A CSRF Token is also generated for each user login session, and for demonstration purpose, as mentioned previously, it is stored in a PHP associative array, mapped against the Session Id through the line:
$csrfTokenArray[session_id()] = $csrfToken;
The CSRF Token, being a randomly generated string, in this case, has been produced by hashing and Base64 encoding the random integer created while taking the current timestamp into account, through the line:
$csrfToken = base64_encode(hash("sha256", uniqid(mt_rand(1000, 9999)
.microtime(), true), true));
.microtime(), true), true));
The array that stores CSRF tokens mapped against the Session is added to the Session through the line mentioned below, so that it is accessible from other server-side files throughout the Session:
$_SESSION['csrfTokenArray'] = $csrfTokenArray;
3. The CSRF Token for the session is retrieved using an AJAX call, and when the user fills the form and clicks the Insert button, the form details are submitted to the pointed validate_token.php.
Add User Page:
add_user.html:
When the form body is loading the JavaScript function getCSRFToken() is called, and this function makes the above mentioned AJAX POST call to the server-side token_dispatcher.php to retrieve the CSRF Token generated for the current user's current session. The JSON response returned from the server-side is taken, and when the form has completely loaded as checked by the document.readyState if statement, a new hidden input field is added to the form, and this input field contains the retrieved CSRF token which is to be passed to the server-side in the attempt in enabling the server to recognize whether the request is legitimate or not.
4. When the client-side makes the AJAX call to the server-side, if there is a Session, the CSRF Token for that particular Session is returned to the client-side in JSON format.
token_dispatcher.php:
token_dispatcher.php checks whether the request is POST and checks to see whether the PHPSESSID which is the PHP Session Id has been set, and if these conditions are met, it retrieves the associative array stored in the Session and returns the CSRF Token for that particular Session identified by the Session Id, along with the 200 message status and a message in the JSON format.
5. When the form details are submitted to validate_token.php on Insert button click, the CSRF Token values will be compared and validated, and a message will be returned based on the outcome of the comparison.
validate_token.php:
It performs the same checks previously carried out in token_dispatcher.php, but this time, additionally, the check to see whether a value has been set as the 'csrf_token' is enabled, and if it has been set, the CSRF Token value stored in the array for that particular Session is compared with the value sent in the POST request to see whether the values are equal and the request is legitimate. Either a successful message as in the picture included below, or an error message will be displayed in the client-side based on the equality comparison outcome.
One of the major drawbacks of the Synchronized Token Pattern is that it requires a lot of database space to store all the CSRF tokens generated per each user's each session. Double Submit Cookies Pattern is a better alternative to prevent CSRF while overcoming this storage issue, and I will discuss about Double Submit Cookies Pattern in my next post.
No comments:
Post a Comment