First Local Commit - After Clean up.
Signed-off-by: Rick Hays <rhays@haysgang.com>
This commit is contained in:
12
system/Security/Exceptions/SecurityException.php
Normal file
12
system/Security/Exceptions/SecurityException.php
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php namespace CodeIgniter\Security\Exceptions;
|
||||
|
||||
use CodeIgniter\Exceptions\ExceptionInterface;
|
||||
use CodeIgniter\Exceptions\FrameworkException;
|
||||
|
||||
class SecurityException extends FrameworkException implements ExceptionInterface
|
||||
{
|
||||
public static function forDisallowedAction()
|
||||
{
|
||||
return new static(lang('HTTP.disallowedAction'), 403);
|
||||
}
|
||||
}
|
||||
389
system/Security/Security.php
Normal file
389
system/Security/Security.php
Normal file
@@ -0,0 +1,389 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* CodeIgniter
|
||||
*
|
||||
* An open source application development framework for PHP
|
||||
*
|
||||
* This content is released under the MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2014-2019 British Columbia Institute of Technology
|
||||
* Copyright (c) 2019 CodeIgniter Foundation
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @package CodeIgniter
|
||||
* @author CodeIgniter Dev Team
|
||||
* @copyright 2019 CodeIgniter Foundation
|
||||
* @license https://opensource.org/licenses/MIT MIT License
|
||||
* @link https://codeigniter.com
|
||||
* @since Version 4.0.0
|
||||
* @filesource
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Security;
|
||||
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\Security\Exceptions\SecurityException;
|
||||
|
||||
/**
|
||||
* HTTP security handler.
|
||||
*/
|
||||
class Security
|
||||
{
|
||||
|
||||
/**
|
||||
* CSRF Hash
|
||||
*
|
||||
* Random hash for Cross Site Request Forgery protection cookie
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $CSRFHash;
|
||||
|
||||
/**
|
||||
* CSRF Expire time
|
||||
*
|
||||
* Expiration time for Cross Site Request Forgery protection cookie.
|
||||
* Defaults to two hours (in seconds).
|
||||
*
|
||||
* @var integer
|
||||
*/
|
||||
protected $CSRFExpire = 7200;
|
||||
|
||||
/**
|
||||
* CSRF Token name
|
||||
*
|
||||
* Token name for Cross Site Request Forgery protection cookie.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $CSRFTokenName = 'CSRFToken';
|
||||
|
||||
/**
|
||||
* CSRF Header name
|
||||
*
|
||||
* Token name for Cross Site Request Forgery protection cookie.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $CSRFHeaderName = 'CSRFToken';
|
||||
|
||||
/**
|
||||
* CSRF Cookie name
|
||||
*
|
||||
* Cookie name for Cross Site Request Forgery protection cookie.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $CSRFCookieName = 'CSRFToken';
|
||||
|
||||
/**
|
||||
* CSRF Regenerate
|
||||
*
|
||||
* If true, the CSRF Token will be regenerated on every request.
|
||||
* If false, will stay the same for the life of the cookie.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $CSRFRegenerate = true;
|
||||
|
||||
/**
|
||||
* Typically will be a forward slash
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $cookiePath = '/';
|
||||
|
||||
/**
|
||||
* Set to .your-domain.com for site-wide cookies
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $cookieDomain = '';
|
||||
|
||||
/**
|
||||
* Cookie will only be set if a secure HTTPS connection exists.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
protected $cookieSecure = false;
|
||||
|
||||
/**
|
||||
* List of sanitize filename strings
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $filenameBadChars = [
|
||||
'../',
|
||||
'<!--',
|
||||
'-->',
|
||||
'<',
|
||||
'>',
|
||||
"'",
|
||||
'"',
|
||||
'&',
|
||||
'$',
|
||||
'#',
|
||||
'{',
|
||||
'}',
|
||||
'[',
|
||||
']',
|
||||
'=',
|
||||
';',
|
||||
'?',
|
||||
'%20',
|
||||
'%22',
|
||||
'%3c', // <
|
||||
'%253c', // <
|
||||
'%3e', // >
|
||||
'%0e', // >
|
||||
'%28', // (
|
||||
'%29', // )
|
||||
'%2528', // (
|
||||
'%26', // &
|
||||
'%24', // $
|
||||
'%3f', // ?
|
||||
'%3b', // ;
|
||||
'%3d', // =
|
||||
];
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Security constructor.
|
||||
*
|
||||
* Stores our configuration and fires off the init() method to
|
||||
* setup initial state.
|
||||
*
|
||||
* @param \Config\App $config
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($config)
|
||||
{
|
||||
// Store our CSRF-related settings
|
||||
$this->CSRFExpire = $config->CSRFExpire;
|
||||
$this->CSRFTokenName = $config->CSRFTokenName;
|
||||
$this->CSRFHeaderName = $config->CSRFHeaderName;
|
||||
$this->CSRFCookieName = $config->CSRFCookieName;
|
||||
$this->CSRFRegenerate = $config->CSRFRegenerate;
|
||||
|
||||
if (isset($config->cookiePrefix))
|
||||
{
|
||||
$this->CSRFCookieName = $config->cookiePrefix . $this->CSRFCookieName;
|
||||
}
|
||||
|
||||
// Store cookie-related settings
|
||||
$this->cookiePath = $config->cookiePath;
|
||||
$this->cookieDomain = $config->cookieDomain;
|
||||
$this->cookieSecure = $config->cookieSecure;
|
||||
|
||||
$this->CSRFSetHash();
|
||||
|
||||
unset($config);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* CSRF Verify
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
*
|
||||
* @return $this|false
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function CSRFVerify(RequestInterface $request)
|
||||
{
|
||||
// If it's not a POST request we will set the CSRF cookie
|
||||
if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST')
|
||||
{
|
||||
return $this->CSRFSetCookie($request);
|
||||
}
|
||||
|
||||
// Do the tokens exist in _POST, HEADER or optionally php:://input - json data
|
||||
$CSRFTokenValue = $_POST[$this->CSRFTokenName] ??
|
||||
(! is_null($request->getHeader($this->CSRFHeaderName)) && ! empty($request->getHeader($this->CSRFHeaderName)->getValue()) ?
|
||||
$request->getHeader($this->CSRFHeaderName)->getValue() :
|
||||
(! empty($request->getBody()) && ! empty($json = json_decode($request->getBody())) && json_last_error() === JSON_ERROR_NONE ?
|
||||
($json->{$this->CSRFTokenName} ?? null) :
|
||||
null));
|
||||
|
||||
// Do the tokens exist in both the _POST/POSTed JSON and _COOKIE arrays?
|
||||
if (! isset($CSRFTokenValue, $_COOKIE[$this->CSRFCookieName]) || $CSRFTokenValue !== $_COOKIE[$this->CSRFCookieName]
|
||||
) // Do the tokens match?
|
||||
{
|
||||
throw SecurityException::forDisallowedAction();
|
||||
}
|
||||
|
||||
// We kill this since we're done and we don't want to pollute the _POST array
|
||||
if (isset($_POST[$this->CSRFTokenName]))
|
||||
{
|
||||
unset($_POST[$this->CSRFTokenName]);
|
||||
$request->setGlobal('post', $_POST);
|
||||
}
|
||||
// We kill this since we're done and we don't want to pollute the JSON data
|
||||
elseif (isset($json->{$this->CSRFTokenName}))
|
||||
{
|
||||
unset($json->{$this->CSRFTokenName});
|
||||
$request->setBody(json_encode($json));
|
||||
}
|
||||
|
||||
// Regenerate on every submission?
|
||||
if ($this->CSRFRegenerate)
|
||||
{
|
||||
// Nothing should last forever
|
||||
$this->CSRFHash = null;
|
||||
unset($_COOKIE[$this->CSRFCookieName]);
|
||||
}
|
||||
|
||||
$this->CSRFSetHash();
|
||||
$this->CSRFSetCookie($request);
|
||||
|
||||
log_message('info', 'CSRF token verified');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* CSRF Set Cookie
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*
|
||||
* @param RequestInterface|\CodeIgniter\HTTP\IncomingRequest $request
|
||||
*
|
||||
* @return Security|false
|
||||
*/
|
||||
public function CSRFSetCookie(RequestInterface $request)
|
||||
{
|
||||
$expire = time() + $this->CSRFExpire;
|
||||
$secure_cookie = (bool) $this->cookieSecure;
|
||||
|
||||
if ($secure_cookie && ! $request->isSecure())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
setcookie(
|
||||
$this->CSRFCookieName, $this->CSRFHash, $expire, $this->cookiePath, $this->cookieDomain, $secure_cookie, true // Enforce HTTP only cookie for security
|
||||
);
|
||||
|
||||
log_message('info', 'CSRF cookie sent');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the current CSRF Hash.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCSRFHash(): string
|
||||
{
|
||||
return $this->CSRFHash;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the CSRF Token Name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCSRFTokenName(): string
|
||||
{
|
||||
return $this->CSRFTokenName;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Sets the CSRF Hash and cookie.
|
||||
*
|
||||
* @return string
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function CSRFSetHash(): string
|
||||
{
|
||||
if ($this->CSRFHash === null)
|
||||
{
|
||||
// If the cookie exists we will use its value.
|
||||
// We don't necessarily want to regenerate it with
|
||||
// each page load since a page could contain embedded
|
||||
// sub-pages causing this feature to fail
|
||||
if (isset($_COOKIE[$this->CSRFCookieName]) && is_string($_COOKIE[$this->CSRFCookieName]) && preg_match('#^[0-9a-f]{32}$#iS', $_COOKIE[$this->CSRFCookieName]) === 1
|
||||
)
|
||||
{
|
||||
return $this->CSRFHash = $_COOKIE[$this->CSRFCookieName];
|
||||
}
|
||||
|
||||
$rand = random_bytes(16);
|
||||
$this->CSRFHash = bin2hex($rand);
|
||||
}
|
||||
|
||||
return $this->CSRFHash;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Sanitize Filename
|
||||
*
|
||||
* Tries to sanitize filenames in order to prevent directory traversal attempts
|
||||
* and other security threats, which is particularly useful for files that
|
||||
* were supplied via user input.
|
||||
*
|
||||
* If it is acceptable for the user input to include relative paths,
|
||||
* e.g. file/in/some/approved/folder.txt, you can set the second optional
|
||||
* parameter, $relative_path to TRUE.
|
||||
*
|
||||
* @param string $str Input file name
|
||||
* @param boolean $relative_path Whether to preserve paths
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function sanitizeFilename(string $str, bool $relative_path = false): string
|
||||
{
|
||||
$bad = $this->filenameBadChars;
|
||||
|
||||
if (! $relative_path)
|
||||
{
|
||||
$bad[] = './';
|
||||
$bad[] = '/';
|
||||
}
|
||||
|
||||
$str = remove_invisible_characters($str, false);
|
||||
|
||||
do
|
||||
{
|
||||
$old = $str;
|
||||
$str = str_replace($bad, '', $str);
|
||||
}
|
||||
while ($old !== $str);
|
||||
|
||||
return stripslashes($str);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
}
|
||||
Reference in New Issue
Block a user