Introdotta libreria OWASP CSRF

This commit is contained in:
Thomas Zilio 2018-07-08 18:25:36 +02:00
parent 0e91e8eede
commit 89cd1499f3
5 changed files with 31 additions and 311 deletions

View File

@ -34,6 +34,7 @@
"monolog/monolog": "^1.22",
"mpdf/mpdf": "^7.1",
"mpociot/vat-calculator": "^2.3",
"owasp/csrf-protector-php": "^1.0",
"phpmailer/phpmailer": "^6.0",
"respect/validation": "^1.1",
"servo/fluidxml": "^1.21",

19
config/csrf_config.php Normal file
View File

@ -0,0 +1,19 @@
<?php
/**
* Configuration file for CSRF Protector.
*/
return [
'logDirectory' => DOCROOT.'/logs',
'failedAuthAction' => [
'GET' => 0,
'POST' => 0,
],
'jsUrl' => ROOTDIR.'/assets/dist/js/csrf/csrfprotector.js',
'tokenLength' => 10,
'cookieConfig' => [
'path' => ROOTDIR,
'secure' => isHTTPS(true),
],
'verifyGetFor' => [],
];

View File

@ -132,7 +132,7 @@ if (!API::isAPIRequest()) {
ini_set('session.use_trans_sid', '0');
ini_set('session.use_only_cookies', '1');
session_set_cookie_params(0, $rootdir);
session_set_cookie_params(0, $rootdir, null, isHTTPS(true));
session_start();
}
@ -159,11 +159,8 @@ if (!API::isAPIRequest()) {
// Impostazioni di Content-Type e Charset Header
header('Content-Type: text/html; charset=UTF-8');
/*
// Controllo CSRF
if(!CSRF::getInstance()->validate()){
die(tr('Constrollo CSRF fallito!'));
}*/
csrfProtector::init();
// Aggiunta del wrapper personalizzato per la generazione degli input
if (!empty($HTMLWrapper)) {

View File

@ -206,6 +206,14 @@ gulp.task('chartjs', function () {
.pipe(gulp.dest(config.production + '/' + config.paths.js + '/chartjs'));
});
gulp.task('csrf', function () {
gulp.src([
'./vendor/owasp/csrf-protector-php/js/csrfprotector.js',
])
.pipe(flatten())
.pipe(gulp.dest(config.production + '/' + config.paths.js + '/csrf'));
});
gulp.task('pdfjs', function () {
gulp.src([
config.main.bowerDirectory + '/pdf/web/**/*',
@ -364,7 +372,7 @@ gulp.task('other', ['clean'], function () {
gulp.start('chartjs');
gulp.start('php-debugbar');
gulp.start('csrf');
});
gulp.task('default', ['clean', 'bower']);

View File

@ -1,305 +0,0 @@
<?php
/**
* Sistema di protezione CSRF, basato sulla libreria Slim CSRF.
*
* @since 2.3
*/
class CSRF extends Util\Singleton
{
/**
* Prefix for CSRF parameters (omit trailing "_" underscore).
*
* @var string
*/
protected $prefix;
/**
* CSRF storage.
*
* Should be either an array or an object. If an object is used, then it must
* implement ArrayAccess and should implement Countable and Iterator (or
* IteratorAggregate) if storage limit enforcement is required.
*
* @var array|ArrayAccess
*/
protected $storage;
/**
* Number of elements to store in the storage array.
*
* @var int
*/
protected $storageLimit;
/**
* CSRF Strength.
*
* @var int
*/
protected $strength = 16;
/**
* Stores the latest key-pair generated by the class.
*
* @var array
*/
protected $keyPair = null;
/**
* Create new CSRF guard.
*
* @param string $prefix
* @param null|array|ArrayAccess $storage
* @param int $storageLimit
*/
protected function __construct($prefix = 'csrf', &$storage = null, $storageLimit = -1)
{
$this->prefix = rtrim($prefix, '_');
$this->storage = &$storage;
$this->validateStorage();
$this->storageLimit = $storageLimit;
}
/**
* @return string
*/
public function getToken()
{
if (!$this->keyPair && (!$this->isPersistent() || !$this->loadLastToken())) {
$this->generateToken();
}
return $this->keyPair;
}
/**
* Generates a new CSRF token.
*
* @return array
*/
protected function generateToken()
{
// Generate new CSRF token
$name = uniqid($this->prefix);
$value = $this->createToken();
$this->saveToStorage($name, $value);
$this->keyPair = [
$this->prefix.'_name' => $name,
$this->prefix.'_value' => $value,
];
return $this->keyPair;
}
public function validate()
{
$result = true;
$this->validateStorage();
if (in_array($_SERVER['REQUEST_METHOD'], ['POST'])) {
$name = isset($_POST[$this->prefix.'_name']) ? $_POST[$this->prefix.'_name'] : false;
$value = isset($_POST[$this->prefix.'_value']) ? $_POST[$this->prefix.'_value'] : false;
if (!$name || !$value || !$this->validateToken($name, $value)) {
// Need to regenerate a new token, as the validateToken removed the current one.
$this->generateToken();
$result = false;
}
}
// Enforce the storage limit
$this->enforceStorageLimit();
return $result;
}
/**
* @param $prefix
* @param $storage
*
* @return mixed
*/
protected function validateStorage()
{
if (is_array($this->storage)) {
return $this->storage;
}
if ($this->storage instanceof ArrayAccess) {
return $this->storage;
}
if (!array_key_exists($this->prefix, $_SESSION)) {
$_SESSION[$this->prefix] = [];
}
$this->storage = &$_SESSION[$this->prefix];
return $this->storage;
}
/**
* Validate CSRF token from current request against token value stored in $_SESSION.
*
* @param string $name CSRF name
* @param string $value CSRF token value
*
* @return bool
*/
protected function validateToken($name, $value)
{
$token = $this->getFromStorage($name);
if (function_exists('hash_equals')) {
$result = ($token !== false && hash_equals($token, $value));
} else {
$result = ($token !== false && $token === $value);
}
// If we're not in persistent token mode, delete the token.
if (!$this->isPersistent() || !$result) {
$this->removeFromStorage($name);
}
return $result;
}
/**
* Create CSRF token value.
*
* @return string
*/
protected function createToken()
{
return bin2hex(random_bytes($this->strength));
}
/**
* Save token to storage.
*
* @param string $name CSRF token name
* @param string $value CSRF token value
*/
protected function saveToStorage($name, $value)
{
$this->storage[$name] = $value;
}
/**
* Get token from storage.
*
* @param string $name CSRF token name
*
* @return string|bool CSRF token value or `false` if not present
*/
protected function getFromStorage($name)
{
return isset($this->storage[$name]) ? $this->storage[$name] : false;
}
/**
* Get the most recent key pair from storage.
*
* @return string[]|null Array containing name and value if found, null otherwise
*/
protected function loadLastToken()
{
// Use count, since empty ArrayAccess objects can still return false for `empty`
if (count($this->storage) < 1) {
return null;
}
foreach ($this->storage as $name => $value) {
continue;
}
$keyPair = [
$this->prefix.'_name' => $name,
$this->prefix.'_value' => $value,
];
if ($keyPair) {
$this->keyPair = $keyPair;
return true;
}
return false;
}
/**
* Remove token from storage.
*
* @param string $name CSRF token name
*/
protected function removeFromStorage($name)
{
$this->storage[$name] = ' ';
unset($this->storage[$name]);
}
/**
* Remove the oldest tokens from the storage array so that there
* are never more than storageLimit tokens in the array.
*
* This is required as a token is generated every request and so
* most will never be used.
*/
protected function enforceStorageLimit()
{
if ($this->storageLimit < 1) {
return;
}
// $storage must be an array or implement Countable and Traversable
if (!is_array($this->storage)
&& !($this->storage instanceof Countable && $this->storage instanceof Traversable)
) {
return;
}
if (is_array($this->storage)) {
while (count($this->storage) > $this->storageLimit) {
array_shift($this->storage);
}
} else {
// array_shift() doesn't work for ArrayAccess, so we need an iterator in order to use rewind()
// and key(), so that we can then unset
$iterator = $this->storage;
if ($this->storage instanceof \IteratorAggregate) {
$iterator = $this->storage->getIterator();
}
while (count($this->storage) > $this->storageLimit) {
$iterator->rewind();
unset($this->storage[$iterator->key()]);
}
}
}
/**
* Setter for storageLimit.
*
* @param int $storageLimit Value to set
*
* @return $this
*/
public function setStorageLimit($storageLimit)
{
$this->storageLimit = (int) $storageLimit;
}
/**
* Getter for persistentTokenMode.
*
* @return bool
*/
public function isPersistent()
{
return $this->storageLimit < 0;
}
}