Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- /**
- * Cross Site Request Forgery protection class.
- *
- * This class implements CSRF. The initiate method needs to be called on top of
- * all pages where CSRF needs to be implemented. The script will save the token
- * in a cookie. Cookies is to prevent an attacker to just spoof the session-
- * identifier. Cookie-data is stored client side.
- *
- * On requerst pages, you can call the static method validate that returns true
- * in case of valid CSRF tokens else false. You need to handle the false-return
- * by your self in your system.
- *
- * Upon each request the token is invalidated.
- *
- * @author Andreas Krüger
- * @copyright (c) 2012, Andreas Krüger
- * @version 1.0
- */
- class csrf
- {
- /**
- * Sets the CSRF token.
- */
- public static function initiate( $renew = false )
- {
- if (!isset($_COOKIE['__csrf_token']) || $renew === true)
- {
- $token = self::generate_token();
- $_COOKIE['__csrf_token'] = $token;
- @setcookie('__csrf_token', $token);
- }
- }
- /**
- * Returns a truely random token of 512 characters.
- * Uses openssl_random_pseudo_bytes() if available, else SHA512 if
- * available. If either is not available, then a
- * random string is created using mt_rand and chr(ord()).
- *
- * @return string
- */
- private static function generate_token()
- {
- if (function_exists('openssl_random_pseudo_bytes'))
- {
- $token = bin2hex(openssl_random_pseudo_bytes(256));
- }
- elseif (function_exists('hash_algos') and in_array('sha512', hash_algos()))
- {
- $token = hash("sha512", mt_rand(0, mt_getrandmax()));
- }
- else
- {
- $token = '';
- for ($i = 0; $i < 512; ++$i)
- {
- $r = mt_rand(0, 35);
- if ($r < 26)
- $token .= chr(ord('a') + $r);
- else
- $token .= chr(ord('0') + $r - 26);
- }
- }
- return $token;
- }
- /**
- * Validates a CSRF request. Looks firstly for the CSRF in _POST, and if
- * not found, then in _GET.
- *
- * Will renew CSRF token upon validate request.
- *
- * @return boolean
- */
- public function validate()
- {
- // If the csrf token is not found in cookies, we dont know what to
- // compare. Renew the token.
- if (!isset($_COOKIE['__csrf_token']))
- {
- self::initiate(true); // Renew token
- return false;
- }
- else
- $csrf_token = $_COOKIE['__csrf_token'];
- $token = '';
- // Request token has to be set and be a string.
- if (isset($_POST['__csrf_token']) && is_string($_POST['__csrf_token']))
- $token = $_POST['__csrf_token'];
- // Request token was not found in POST request, lets see if it's in a GET request.
- if (empty($token) && isset($_GET['csrf_token']) && is_string($_GET['__csrf_token']))
- $token = $_GET['__csrf_token'];
- // Renew the token upon each request, making sure to invalidate the request everytime.
- self::initiate(true);
- // Compare tokens.
- if ($csrf_token == $token)
- return true;
- // Tokens wasn't equal
- return false;
- }
- /**
- * Returns the current token.
- *
- * @return string
- */
- public static function getToken()
- {
- // If no token is set, renew it to get a fresh one.s
- if (!isset($_COOKIE['__csrf_token']))
- self::initiate(true); // Renew token
- // Return token.
- return $_COOKIE['__csrf_token'];
- }
- }
- // Initiate CSRF
- csrf::initiate();
- // Ajax return call:
- if (isset($_POST['type']))
- {
- echo (csrf::validate() ? 'true' : 'false');
- exit;
- }
- // Form request
- $form_result = false;
- if (isset($_POST) && count($_POST) > 0)
- $form_result = csrf::validate();
- ?>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <script src="http://cdn.jquerytools.org/1.2.6/jquery.tools.min.js"></script>
- <script type="text/javascript">
- // Get cookie content
- function getCookie(name) {
- var cookieValue = null;
- if (document.cookie && document.cookie != '') {
- var cookies = document.cookie.split(';');
- for (var i = 0; i < cookies.length; i++) {
- var cookie = jQuery.trim(cookies[i]);
- // Does this cookie string begin with the name we want?
- if (cookie.substring(0, name.length + 1) == (name + '=')) {
- cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
- break;
- }
- }
- }
- return cookieValue;
- }
- // Do a ajax call, read csrf token from cookie.
- function doAjax()
- {
- if (typeof jQuery != 'undefined')
- {
- $.post("csrf.php", { type: "ajax", __csrf_token: getCookie('__csrf_token') },
- function(data)
- {
- $('#result').html('Ajax result: ' + data);
- });
- }
- }
- function doAjaxWithout()
- {
- if (typeof jQuery != 'undefined')
- {
- $.post("csrf.php", { type: "ajax" },
- function(data)
- {
- $('#result').html('Ajax result: ' + data);
- });
- }
- }
- if (typeof jQuery != 'undefined')
- {
- // Append CSRF token upon form submit, getting token from cookie.
- $(document).ready(function()
- {
- $('form').submit(function(e)
- {
- if (!$(this).hasClass('notoken'))
- {
- // Dont allow form to submit before we added the token
- e.preventDefault();
- // Add token to the form we're trying to submit
- $(this).append($("<input>").attr("type", "hidden").attr("name", "__csrf_token").val(getCookie('__csrf_token')));
- // Remove bind and submit form!
- $(this).unbind('submit').submit();
- }
- });
- });
- }
- </script>
- </head>
- <body>
- <h3>Form example</h3>
- <form action="" method="post">
- <input type="submit" name="send" value="Click me to submit form" />
- </form>
- <form action="" method="post" class="notoken">
- <input type="submit" name="send" value="Click me to submit form without token" />
- </form>
- <br>
- <?php echo "Form result: " . ($form_result ? 'true' : 'false') . "<br>"; ?>
- <h3>Ajax post call example</h3>
- <span onclick="doAjax()" style="border: 1px solid #FF0000; padding: 3px;background:#cccccc; cursor: pointer;">Click me with token</span>
- <span onclick="doAjaxWithout()" style="border: 1px solid #FF0000; padding: 3px;background:#cccccc; cursor: pointer;">Click me without token</span>
- <br>
- <br>
- <span id="result">Ajax result: false</span>
- </body>
- </html>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement