CSRF implementation (using Slim\Csrf\Guard)

This commit is contained in:
Bojidar Marinov
2016-08-11 12:11:34 +03:00
parent 4dd296a29c
commit 38eb42f994
12 changed files with 148 additions and 14 deletions

View File

@@ -1,6 +1,7 @@
{
"require": {
"slim/slim": "^3.0",
"dflydev/fig-cookies": "^1.0"
"dflydev/fig-cookies": "^1.0",
"slim/csrf": "^0.7.0"
}
}

102
composer.lock generated
View File

@@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "2508447cd8e8239db46496d8acf426ea",
"content-hash": "5e966a788c3c01a701c59ff122677d3a",
"hash": "c7786a3f61a555547053a39a9bace6a7",
"content-hash": "8c77aed001f64c5af18413f8ad5cb15b",
"packages": [
{
"name": "container-interop/container-interop",
@@ -206,6 +206,54 @@
],
"time": "2015-06-18 19:15:47"
},
{
"name": "paragonie/random_compat",
"version": "v2.0.2",
"source": {
"type": "git",
"url": "https://github.com/paragonie/random_compat.git",
"reference": "088c04e2f261c33bed6ca5245491cfca69195ccf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/088c04e2f261c33bed6ca5245491cfca69195ccf",
"reference": "088c04e2f261c33bed6ca5245491cfca69195ccf",
"shasum": ""
},
"require": {
"php": ">=5.2.0"
},
"require-dev": {
"phpunit/phpunit": "4.*|5.*"
},
"suggest": {
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
},
"type": "library",
"autoload": {
"files": [
"lib/random.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com",
"homepage": "https://paragonie.com"
}
],
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
"keywords": [
"csprng",
"pseudorandom",
"random"
],
"time": "2016-04-03 06:00:07"
},
{
"name": "pimple/pimple",
"version": "v3.0.2",
@@ -339,6 +387,56 @@
],
"time": "2012-12-21 11:40:51"
},
{
"name": "slim/csrf",
"version": "0.7.0",
"source": {
"type": "git",
"url": "https://github.com/slimphp/Slim-Csrf.git",
"reference": "788f658de275e5d856d498aa8698cde70029decd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/slimphp/Slim-Csrf/zipball/788f658de275e5d856d498aa8698cde70029decd",
"reference": "788f658de275e5d856d498aa8698cde70029decd",
"shasum": ""
},
"require": {
"paragonie/random_compat": "^1.1|^2.0",
"php": ">=5.5.0",
"psr/http-message": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0",
"slim/slim": "~3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Slim\\Csrf\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Josh Lockhart",
"email": "hello@joshlockhart.com",
"homepage": "http://joshlockhart.com"
}
],
"description": "Slim Framework 3 CSRF protection middleware",
"homepage": "http://slimframework.com",
"keywords": [
"csrf",
"framework",
"middleware",
"slim"
],
"time": "2016-06-08 18:26:56"
},
{
"name": "slim/php-view",
"version": "2.0.6",

View File

@@ -59,6 +59,11 @@ $container['utils'] = function ($c) {
return new Utils($c);
};
// csrf guard
$container['csrf'] = function ($c) {
return new \Slim\Csrf\Guard;
};
// cookies
$container['cookies'] = function ($c) {
return [

View File

@@ -1,23 +1,25 @@
<?php
if(isset($frontend) && $frontend) {
$container = $app->getContainer();
$app->get('/', function ($request, $response) {
return $response->withJson(['url' => 'asset']);
});
$app->add(function ($request, $response, $next) {
$cookie = $this->cookies['requestCookies']::get($request, 'token');
$body = $request->getParsedBody();
if($cookie->getValue() !== null && !isset($body['token'])) {
$cookieValue = (string) $cookie->getValue();
$body['token'] = $cookieValue;
$request = $request->withParsedBody($body);
}
$response = $next($request, $response);
$response->getBody()->rewind();
$preresult = json_decode($response->getBody()->getContents(), true);
if(!isset($preresult['error'])) {
$cookie = $this->cookies['requestCookies']::get($request, 'token');
$body = $request->getParsedBody();
if($cookie->getValue() !== null && !isset($body['token'])) {
$cookieValue = (string) $cookie->getValue();
$body['token'] = $cookieValue;
$request = $request->withParsedBody($body);
}
$response = $next($request, $response);
}
$static_routes = [
'/login' => true,
@@ -44,6 +46,7 @@ if(isset($frontend) && $frontend) {
$queryUri = $request->getMethod() . ' ' . $queryUri;
if($route) {
$response->getBody()->rewind();
$result = json_decode($response->getBody()->getContents(), true);
if($result === null) {
return $response;
@@ -96,6 +99,10 @@ if(isset($frontend) && $frontend) {
'params' => $request->getQueryParams(),
'categories' => [], // Filled later
'constants' => $this->constants,
'csrf_name_key' => $this->csrf->getTokenNameKey(),
'csrf_name' => $request->getAttribute('csrf_name'),
'csrf_value_key' => $this->csrf->getTokenValueKey(),
'csrf_value' => $request->getAttribute('csrf_value'),
//'body' => $request->getParsedBody(),
];
@@ -128,8 +135,20 @@ if(isset($frontend) && $frontend) {
$response = $this->cookies['responseCookies']::set($response, $this->cookies['setCookie']('token')
->withValue($result['token'])
->withDomain($_SERVER['HTTP_HOST'])
->withPath($request->getUri()->getBasePath())
->withHttpOnly(true)
);
}
return $response;
});
// Adding after the real middleware, since it has to run first... o.O
$app->add($container->get('csrf'));
$container->get('csrf')->setFailureCallable(function ($request, $response, $next) {
$response = $response->withJson([
'error' => 'CSRF check failed',
]);
return $next($request, $response);
});
}

View File

@@ -178,6 +178,7 @@ $app->post('/asset/{id:[0-9]+}/support_level', function ($request, $response, $a
$body = $request->getParsedBody();
$error = $this->utils->ensure_logged_in(false, $response, $body, $user);
$error = $this->utils->get_user_for_id($error, $response, $user_id, $user);
$error = $this->utils->error_reponse_if_not_user_has_level($error, $response, $user, 'moderator');
$error = $this->utils->error_reponse_if_missing_or_not_string($error, $response, $body, 'support_level');
if($error) return $response;

2
templates/_csrf.phtml Normal file
View File

@@ -0,0 +1,2 @@
<input type="hidden" name="<?php echo esc($csrf_name_key) ?>" value="<?php echo esc($csrf_name) ?>">
<input type="hidden" name="<?php echo esc($csrf_value_key) ?>" value="<?php echo esc($csrf_value) ?>">

View File

@@ -144,10 +144,12 @@ $preview_field_names = [
<?php if($user['type'] >= 50) { ?>
<?php if($data['status'] == 'new') { ?>
<form class="form-inline" action="<?php echo raw($basepath) ?>/asset/edit/<?php echo url($data['edit_id']) ?>/review" method="post">
<?php include("_csrf.phtml") ?>
<button type="submit" class="btn btn-primary">Put in queue</button>
</form>
<?php } elseif($data['status'] == 'in_review') { ?>
<form class="form-inline" action="<?php echo raw($basepath) ?>/asset/edit/<?php echo url($data['edit_id']) ?>/accept" method="post">
<?php include("_csrf.phtml") ?>
<div class="form-group panel">
<button type="submit" class="btn btn-success">Accept</button>
<label class="control-label" for="hash">Hash:</label>
@@ -156,6 +158,7 @@ $preview_field_names = [
</form>
<form class="form-inline" action="<?php echo raw($basepath) ?>/asset/edit/<?php echo url($data['edit_id']) ?>/reject" method="post">
<?php include("_csrf.phtml") ?>
<div class="form-group panel">
<button type="submit" class="btn btn-danger">Reject</button>
<label class="control-label" for="reason">Reason:</label>

View File

@@ -1,6 +1,7 @@
<?php include("_header.phtml") ?>
<?php $_asset_values = $data ?>
<form class="form-horizontal" action="<?php echo raw($basepath) ?>/asset/<?php echo url($data['asset_id']) ?>" method="post">
<?php include("_csrf.phtml") ?>
<fieldset>
<!-- Form Name -->
<legend>

View File

@@ -5,6 +5,7 @@
$_asset_values = $data;
} ?>
<form class="form-horizontal" action="<?php echo raw($basepath) ?>/asset/edit/<?php echo url($data['edit_id']) ?>" method="post">
<?php include("_csrf.phtml") ?>
<fieldset>
<!-- Form Name -->
<legend>

View File

@@ -9,6 +9,7 @@
<?php endif ?>
<form action="<?php echo raw($basepath) ?>/login" method="post">
<?php include("_csrf.phtml") ?>
<div class="form-group">
<label for="login-form-username">Username</label>
<input type="text" name="username" class="form-control" id="login-form-username" placeholder="Username">

View File

@@ -9,6 +9,7 @@
<?php endif ?>
<form action="<?php echo raw($basepath) ?>/register" method="post">
<?php include("_csrf.phtml") ?>
<div class="form-group">
<label for="login-form-username">Username</label>
<input type="text" name="username" class="form-control" id="login-form-username" placeholder="Username">

View File

@@ -1,5 +1,6 @@
<?php include("_header.phtml") ?>
<form class="form-horizontal" action="<?php echo raw($basepath) ?>/asset" method="post">
<?php include("_csrf.phtml") ?>
<fieldset>
<!-- Form Name -->