Skip to content

Commit 1a805c4

Browse files
committed
Destroy session when CSRF check fails.
Rails does this I believe. It's more graceful than just halting the application. I also simplified the code and tweaked exception error messages.
1 parent 271d528 commit 1a805c4

File tree

1 file changed

+60
-71
lines changed

1 file changed

+60
-71
lines changed

Middleware/CsrfGuard.php

Lines changed: 60 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,74 @@
11
<?php
22
namespace Slim\Extras\Middleware;
33

4-
/**
5-
* CsrfGuard
6-
*
7-
* This middleware provides protection from CSRF attacks
8-
* USAGE
9-
*
10-
* // Adding middleware
11-
* $app = new Slim();
12-
* $app->add(new CsrfGuard());
13-
*
14-
* // Setting token in view
15-
* <input type="hidden" name="<?=$csrf_key?>" value="<?=$csrf_token?>">
16-
*
17-
* @author Mikhail Osher, https://github.com/miraage
18-
* @version 1.0
19-
*/
204
class CsrfGuard extends \Slim\Middleware
215
{
226
/**
23-
* Request key
24-
*
25-
* @var string
26-
*/
27-
protected $key;
7+
* CSRF token key.
8+
*
9+
* @var string
10+
*/
11+
protected $key;
2812

29-
/**
30-
* Constructor
31-
*
32-
* @param string $key Request key
33-
*/
34-
public function __construct($key = 'csrf_token')
35-
{
36-
// Validate key (i won't use htmlspecialchars)
37-
if (!is_string($key) || empty($key) || preg_match('/[^a-zA-Z0-9\-\_]/', $key)) {
38-
throw new OutOfBoundsException('Invalid key' . $key);
39-
}
13+
/**
14+
* Constructor.
15+
*
16+
* @param string $key CSRF token key.
17+
* @return void
18+
*/
19+
public function __construct($key = 'csrf_token')
20+
{
21+
if (! is_string($key) || empty($key) || preg_match('/[^a-zA-Z0-9\-\_]/', $key)) {
22+
throw new \OutOfBoundsException('Invalid CSRF token key "' . $key . '"');
23+
}
4024

41-
$this->key = $key;
42-
}
25+
$this->key = $key;
26+
}
4327

44-
/**
45-
* Call middleware
46-
*/
47-
public function call()
48-
{
49-
// Attach as hook
50-
$this->app->hook('slim.before', array($this, 'check'));
28+
/**
29+
* Call middleware.
30+
*
31+
* @return void
32+
*/
33+
public function call()
34+
{
35+
// Attach as hook.
36+
$this->app->hook('slim.before', array($this, 'check'));
5137

52-
// Call next middleware
53-
$this->next->call();
54-
}
38+
// Call next middleware.
39+
$this->next->call();
40+
}
5541

56-
/**
57-
* Check token
58-
*/
59-
public function check()
60-
{
61-
// Create token
62-
if (session_id() !== "") {
63-
if (!isset($_SESSION[$this->key])) {
64-
$_SESSION[$this->key] = sha1(serialize($_SERVER) . rand(0, 0xffffffff));
65-
}
66-
} else {
67-
throw new Exception( "Session are required to use CSRF Guard" );
68-
}
69-
$token = $_SESSION[$this->key];
42+
/**
43+
* Check CSRF token is valid.
44+
* Note: Also checks POST data to see if a Moneris RVAR CSRF token exists.
45+
*
46+
* @return void
47+
*/
48+
public function check() {
49+
// Check sessions are enabled.
50+
if (session_id() === '') {
51+
throw new \Exception('Sessions are required to use the CSRF Guard middleware.');
52+
}
53+
54+
if (! isset($_SESSION[$this->key])) {
55+
$_SESSION[$this->key] = sha1(serialize($_SERVER) . rand(0, 0xffffffff));
56+
}
57+
58+
$token = $_SESSION[$this->key];
7059

71-
// Validate
72-
if (in_array($this->app->request()->getMethod(), array('POST', 'PUT', 'DELETE'))) {
73-
$usertoken = $this->app->request()->post($this->key);
74-
if ($token !== $usertoken) {
75-
$this->app->halt(400, 'Missing token');
60+
// Validate the CSRF token.
61+
if (in_array($this->app->request()->getMethod(), array('POST', 'PUT', 'DELETE'))) {
62+
$userToken = $this->app->request()->post($this->key);
63+
if ($token !== $userToken) {
64+
session_destroy();
7665
}
77-
}
66+
}
7867

79-
// Assign to view
80-
$this->app->view()->appendData(array(
81-
'csrf_key' => $this->key,
82-
'csrf_token' => $token,
83-
));
84-
}
85-
}
68+
// Assign CSRF token key and value to view.
69+
$this->app->view()->appendData(array(
70+
'csrf_key' => $this->key,
71+
'csrf_token' => $token,
72+
));
73+
}
74+
}

0 commit comments

Comments
 (0)