Skip to content

Instantly share code, notes, and snippets.

@Halleck45
Created July 28, 2014 09:56
Show Gist options
  • Save Halleck45/34d08e21934ca9ad1743 to your computer and use it in GitHub Desktop.
Save Halleck45/34d08e21934ca9ad1743 to your computer and use it in GitHub Desktop.
Minimal protection against CRSF exploit without changing any file

# Minimal protection against CSRF exploit

## Installation

Copy-paste thoses files in /path/of/your/choice

Then, edit your php.ini:

auto_prepend_file = /path/of/your/choice/bootstrap.php

## Configuration

Be careful: today only $_POST are checked. If you want to check $_GET request, you should change the method isTokenRequired().

You can change the behavior of CSRF protection.

For example, if you want to redirect user to index.php when token is invalid, you should uncomment the following line in bootstrap.php:

 // strict mode. You can, for example, uncomment the following line to clean session, redirect and inform user
 // $_SESSION = array(); header('Location: "index.php"); exit;
 throw $e;

If you want to be more securized, change the MAX_STACK_TOKENS value:

Csrf::MAX_STACK_TOKENS = 1;
<?php
require_once __DIR__.'/Csrf.php';
ob_start();
session_start();
$csrf = new Csrf(false);
try {
$csrf->enable();
} catch (SecurityException $e) {
// strict mode. You can, for example, uncomment the following line to clean session, redirect and inform user
// $_SESSION = array(); header('Location: "index.php"); exit;
throw $e;
}
<?php
/**
* Class SecurityException
*/
class SecurityException extends Exception {};
/**
* Class Csrf
*
* Allow to avoid CSRF (token method)
*/
class Csrf {
/**
* Maximal number of tokens in history
*/
const MAX_STACK_TOKENS = 5;
/**
* Available tokens
*
* @var array
*/
private $availableTokens = array();
/**
* Constructor
*/
public function __construct() {
if(!isset($_SESSION['availableTokens'])) {
$_SESSION['availableTokens'] = array();
}
$this->availableTokens = $_SESSION['availableTokens'];
// keep only MAX_STACK_TOKENS elements in history
if(sizeof($this->availableTokens, COUNT_NORMAL) >= self::MAX_STACK_TOKENS) {
array_shift($this->availableTokens);
array_shift($_SESSION['availableTokens']);
}
}
/**
* Enable CSRF control
*
* @return $this
*/
public function enable() {
return $this
->checkRequest()
->injectsRequest()
;
}
/**
* Check current request
*
* @throws SecurityException
* @return $this
*/
protected function checkRequest() {
$token = isset($_POST['token'])
? $_POST['token']
: ( isset($_GET['token']) ? $_GET['token'] : null);
if(!$this->isTokenrequired()) {
return $this;
}
// token is null, but it should be provided
if(is_null($token)) {
throw new SecurityException('Token is missing');
}
// compare token
if(!in_array($token, $this->availableTokens)) {
throw new SecurityException('CSRF attempt');
}
return $this;
}
/**
* Enable token integration
*
* @return $this;
*/
protected function injectsRequest() {
$token = sha1(uniqid());
array_push($this->availableTokens, $token);
array_push($_SESSION['availableTokens'], $token);
output_add_rewrite_var('token', $token);
return $this;
}
/**
* Check if token is required
* We can disable token integration here
*
* @return bool
*/
protected function isTokenRequired() {
return (isset($_POST) && !empty($_POST)) ||sizeof($this->availableTokens, COUNT_NORMAL) > 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment