Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Magnus Eriksson committed Oct 16, 2015
0 parents commit 84c9489
Show file tree
Hide file tree
Showing 7 changed files with 325 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/vendor
composer.lock
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2015 Magnus Eriksson

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# A small CSRF package for PHP

Quickly generate and validate tokens to prevent Cross-Site Request Forgery (CSRF) attacks.

> *__Important:__ This package only helps you with the CSRF tokens. To truly be safe from CSRF, you also need to protect yourself against [Cross-site scripting (XSS)](https://en.wikipedia.org/wiki/Cross-site_scripting) as well.*

## Install

Git clone or use composer to download the package with the following command:
```
composer require maer/csrf 0.*
```

## Usage
Include composers autoloader or include the files in the `src/` folder manually. *(start with `CsrfInterface.php`-file)*

#### Create a new instance ####

```
$csrf = new Maer\Security\Csrf\Csrf();
```

*__Important:__ You can create a new instance when ever in your application, but before you make any calls to it, you need to start the session yourself. This package does not make any assumptions on how you manage your sessions (you might use: session_start() or you might use Symfonys Session package etc...)*

#### Approach 1: Manually add the hidden field ####
```
<form method="post" action="...">
<input type="hidden" name="csrftoken" value="<?= $csrf->getToken() ?>" />
...
</form>
```

#### Approach 2: Generate the hidden field ####
```
<form method="post" action="...">
<?= $csrf->getTokenField() ?>
...
</form>
```

#### Validate
When receiving the post:
```
if ($csrf->validateToken($_POST['csrftoken'])) {
echo "Yay! It's a valid token!";
} else {
echo "Nope. That token isn't valid!";
}
```

## More...
Above is the basic usage but there are some more stuff available. I'll update this guide soon...
20 changes: 20 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "maer/csrf",
"description": "A small CSRF package for PHP",
"license": "MIT",
"authors": [
{
"name": "Magnus Eriksson",
"email": "mange@reloop.se"
}
],
"autoload": {
"psr-4": {
"Maer\\Security\\Csrf\\": "src/"
}
},
"minimum-stability": "stable",
"require": {
"php": ">=5.4.0"
}
}
153 changes: 153 additions & 0 deletions src/Csrf.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
<?php namespace Maer\Security\Csrf;
/**
* A small CSRF library for generating/verifying CSRF tokens
*
* @author Magnus Eriksson <mange@reloop.se>
* @version 0.1.0
* @package Maer
* @subpackage Csrf
*/
class Csrf implements CsrfInterface
{
/**
* The default token name if user omit the name from the requests
* @var string
*/
protected $defaultName = 'default';

/**
* Collection that holds all tokens from the session
* @var array
*/
protected $tokens = [];

/**
* Key name for the session with the token collection
* @var string
*/
protected $key = 'csrf_tokens';

/**
* Have we initialized the library yet?
* @var boolean
*/
protected $initialized = false;


/**
* {@inheritdoc}
*/
public function getToken($name = null)
{
$this->initialize();

$hName = $this->hashName($name);
$token = isset($this->tokens[$hName]) ? $this->tokens[$hName]: null;

return $token?: $this->regenerateToken($name);
}


/**
* Get html markup for a hidden input CSRF field
*
* @param string $name If omitted, the default name will be used
* @return string Html markup
*/
public function getTokenField($name = null)
{
$token = $this->getToken();
return '<input type="hidden" name="csrftoken" value="' . $token . '" />';
}


/**
* Validate a token
*
* @param string $userToken The token to validate
* @param string $name If omitted, the default name will be used
* @return bool
*/
public function validateToken($userToken, $name = null)
{
$token = $this->getToken($name);
return !is_null($userToken) && $token === $userToken;
}


/**
* Regenerate a CSRF token
*
* @param string $name If omitted, the default token will be regenerated
*/
public function regenerateToken($name = null)
{
$this->initialize();

$name = $this->hashName($name);
$this->tokens[$name] = base64_encode(openssl_random_pseudo_bytes(64));

if (!isset($_SESSION[$this->key]) || !is_array($_SESSION[$this->key])) {
$_SESSION[$this->key] = [];
}

$_SESSION[$this->key][$name] = $this->tokens[$name];

return $this->tokens[$name];
}


/**
* Reset/delete all tokens
*/
public function resetAll()
{
$this->initialize();

$this->tokens = [];
unset($_SESSION[$this->key]);
}


/**
* Get current session tokens, if there are any.
*
* @return void
*/
protected function initialize()
{
if ($this->initialized) {
// Already initialized
return true;
}

if (session_status() !== PHP_SESSION_NONE) {

if (isset($_SESSION[$this->key]) && is_array($_SESSION[$this->key])) {
// Get the token collection from the session, if we got any
$this->tokens = $_SESSION[$this->key];
}

$this->initialized = true;

} else {

throw new CsrfSessionException('A session must be started before the Csrf library can be used');

}
}


/**
* Normalize and MD5 hash the name (this is not for security reasons
* but rather to remove weird characters in the name)
*
* @param string $name If omitted, the default token will be regenerated
* @return string
*/
protected function hashName($name = null)
{
$name = strtolower($name);
return md5($name?: $this->defaultName);
}
}
54 changes: 54 additions & 0 deletions src/CsrfInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php namespace Maer\Security\Csrf;
/**
* A small CSRF library for generating/verifying CSRF tokens
*
* @author Magnus Eriksson <mange@reloop.se>
* @version 0.1.0
* @package Maer
* @subpackage Csrf
*/
interface CsrfInterface
{

/**
* Get a CSRF token
*
* @param string $name If omitted, the default name will be used
* @return string
*/
public function getToken($name = null);


/**
* Get html markup for a hidden input CSRF field
*
* @param string $name If omitted, the default name will be used
* @return string Html markup
*/
public function getTokenField($name = null);


/**
* Validate a token
*
* @param string $userToken The token to validate
* @param string $name If omitted, the default name will be used
* @return bool
*/
public function validateToken($userToken, $name = null);


/**
* Regenerate a CSRF token
*
* @param string $name If omitted, the default token will be regenerated
*/
public function regenerateToken($name = null);


/**
* Reset/delete all tokens
*/
public function resetAll();

}
13 changes: 13 additions & 0 deletions src/CsrfSessionException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php namespace Maer\Security\Csrf;
/**
* A small CSRF library for generating/verifying CSRF tokens
*
* @author Magnus Eriksson <mange@reloop.se>
* @version 0.1.0
* @package Maer
* @subpackage Csrf
*/
class CsrfSessionException extends \Exception
{

}

0 comments on commit 84c9489

Please sign in to comment.