| Server IP : 104.21.31.197 / Your IP : 172.70.223.218 Web Server : nginx/1.20.2 System : Linux 172-104-110-161.ip.linodeusercontent.com 3.10.0-1160.36.2.el7.x86_64 #1 SMP Wed Jul 21 11:57:15 UTC 2021 x86_64 User : www ( 1000) PHP Version : 8.1.9 Disable Function : passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /www/wwwroot/data.driver-hp.download/framework-4.1.3/system/Security/ |
Upload File : |
<?php
/**
* This file is part of the CodeIgniter 4 framework.
*
* (c) CodeIgniter Foundation <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CodeIgniter\Security;
use CodeIgniter\Cookie\Cookie;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\Security\Exceptions\SecurityException;
use Config\App;
use Config\Cookie as CookieConfig;
use Config\Security as SecurityConfig;
/**
* Class Security
*
* Provides methods that help protect your site against
* Cross-Site Request Forgery attacks.
*/
class Security implements SecurityInterface
{
/**
* CSRF Hash
*
* Random hash for Cross Site Request Forgery protection cookie
*
* @var string|null
*/
protected $hash = null;
/**
* CSRF Token Name
*
* Token name for Cross Site Request Forgery protection cookie.
*
* @var string
*/
protected $tokenName = 'csrf_token_name';
/**
* CSRF Header Name
*
* Token name for Cross Site Request Forgery protection cookie.
*
* @var string
*/
protected $headerName = 'X-CSRF-TOKEN';
/**
* The CSRF Cookie instance.
*
* @var Cookie
*/
protected $cookie;
/**
* CSRF Cookie Name
*
* Cookie name for Cross Site Request Forgery protection cookie.
*
* @var string
*/
protected $cookieName = 'csrf_cookie_name';
/**
* CSRF Expires
*
* Expiration time for Cross Site Request Forgery protection cookie.
*
* Defaults to two hours (in seconds).
*
* @var integer
*
* @deprecated
*/
protected $expires = 7200;
/**
* CSRF Regenerate
*
* Regenerate CSRF Token on every request.
*
* @var boolean
*/
protected $regenerate = true;
/**
* CSRF Redirect
*
* Redirect to previous page with error on failure.
*
* @var boolean
*/
protected $redirect = true;
/**
* CSRF SameSite
*
* Setting for CSRF SameSite cookie token.
*
* Allowed values are: None - Lax - Strict - ''.
*
* Defaults to `Lax` as recommended in this link:
*
* @see https://portswigger.net/web-security/csrf/samesite-cookies
*
* @var string
*
* @deprecated
*/
protected $samesite = Cookie::SAMESITE_LAX;
/**
* Constructor.
*
* Stores our configuration and fires off the init() method to setup
* initial state.
*
* @param App $config
*/
public function __construct(App $config)
{
/** @var SecurityConfig */
$security = config('Security');
// Store CSRF-related configurations
$this->tokenName = $security->tokenName ?? $config->CSRFTokenName ?? $this->tokenName;
$this->headerName = $security->headerName ?? $config->CSRFHeaderName ?? $this->headerName;
$this->regenerate = $security->regenerate ?? $config->CSRFRegenerate ?? $this->regenerate;
$rawCookieName = $security->cookieName ?? $config->CSRFCookieName ?? $this->cookieName;
/** @var CookieConfig */
$cookie = config('Cookie');
$cookiePrefix = $cookie->prefix ?? $config->cookiePrefix;
$this->cookieName = $cookiePrefix . $rawCookieName;
$expires = $security->expires ?? $config->CSRFExpire ?? 7200;
Cookie::setDefaults($cookie);
$this->cookie = new Cookie($rawCookieName, $this->generateHash(), [
'expires' => $expires === 0 ? 0 : time() + $expires,
]);
}
/**
* CSRF Verify
*
* @param RequestInterface $request
*
* @return $this|false
*
* @throws SecurityException
*
* @deprecated Use `CodeIgniter\Security\Security::verify()` instead of using this method.
*
* @codeCoverageIgnore
*/
public function CSRFVerify(RequestInterface $request)
{
return $this->verify($request);
}
/**
* Returns the CSRF Hash.
*
* @return string|null
*
* @deprecated Use `CodeIgniter\Security\Security::getHash()` instead of using this method.
*
* @codeCoverageIgnore
*/
public function getCSRFHash(): ?string
{
return $this->getHash();
}
/**
* Returns the CSRF Token Name.
*
* @return string
*
* @deprecated Use `CodeIgniter\Security\Security::getTokenName()` instead of using this method.
*
* @codeCoverageIgnore
*/
public function getCSRFTokenName(): string
{
return $this->getTokenName();
}
/**
* CSRF Verify
*
* @param RequestInterface $request
*
* @return $this|false
*
* @throws SecurityException
*/
public function verify(RequestInterface $request)
{
// If it's not a POST request we will set the CSRF cookie.
if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST')
{
return $this->sendCookie($request);
}
// Does the token exist in POST, HEADER or optionally php:://input - json data.
if ($request->hasHeader($this->headerName) && ! empty($request->getHeader($this->headerName)->getValue()))
{
$tokenName = $request->getHeader($this->headerName)->getValue();
}
else
{
$json = json_decode($request->getBody());
if (! empty($request->getBody()) && ! empty($json) && json_last_error() === JSON_ERROR_NONE)
{
$tokenName = $json->{$this->tokenName} ?? null;
}
else
{
$tokenName = null;
}
}
$token = $_POST[$this->tokenName] ?? $tokenName;
// Does the tokens exist in both the POST/POSTed JSON and COOKIE arrays and match?
if (! isset($token, $_COOKIE[$this->cookieName]) || ! hash_equals($token, $_COOKIE[$this->cookieName]))
{
throw SecurityException::forDisallowedAction();
}
if (isset($_POST[$this->tokenName]))
{
// We kill this since we're done and we don't want to pollute the POST array.
unset($_POST[$this->tokenName]);
$request->setGlobal('post', $_POST);
}
elseif (isset($json->{$this->tokenName}))
{
// We kill this since we're done and we don't want to pollute the JSON data.
unset($json->{$this->tokenName});
$request->setBody(json_encode($json));
}
if ($this->regenerate)
{
$this->hash = null;
unset($_COOKIE[$this->cookieName]);
}
$this->cookie = $this->cookie->withValue($this->generateHash());
$this->sendCookie($request);
log_message('info', 'CSRF token verified.');
return $this;
}
/**
* Returns the CSRF Hash.
*
* @return string|null
*/
public function getHash(): ?string
{
return $this->hash;
}
/**
* Returns the CSRF Token Name.
*
* @return string
*/
public function getTokenName(): string
{
return $this->tokenName;
}
/**
* Returns the CSRF Header Name.
*
* @return string
*/
public function getHeaderName(): string
{
return $this->headerName;
}
/**
* Returns the CSRF Cookie Name.
*
* @return string
*/
public function getCookieName(): string
{
return $this->cookieName;
}
/**
* Check if CSRF cookie is expired.
*
* @return boolean
*
* @deprecated
*
* @codeCoverageIgnore
*/
public function isExpired(): bool
{
return $this->cookie->isExpired();
}
/**
* Check if request should be redirect on failure.
*
* @return boolean
*/
public function shouldRedirect(): bool
{
return $this->redirect;
}
/**
* 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 $relativePath Whether to preserve paths
*
* @return string
*/
public function sanitizeFilename(string $str, bool $relativePath = false): string
{
// List of sanitize filename strings
$bad = [
'../',
'<!--',
'-->',
'<',
'>',
"'",
'"',
'&',
'$',
'#',
'{',
'}',
'[',
']',
'=',
';',
'?',
'%20',
'%22',
'%3c',
'%253c',
'%3e',
'%0e',
'%28',
'%29',
'%2528',
'%26',
'%24',
'%3f',
'%3b',
'%3d',
];
if (! $relativePath)
{
$bad[] = './';
$bad[] = '/';
}
$str = remove_invisible_characters($str, false);
do
{
$old = $str;
$str = str_replace($bad, '', $str);
}
while ($old !== $str);
return stripslashes($str);
}
/**
* Generates the CSRF Hash.
*
* @return string
*/
protected function generateHash(): string
{
if (is_null($this->hash))
{
// 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->cookieName])
&& is_string($_COOKIE[$this->cookieName])
&& preg_match('#^[0-9a-f]{32}$#iS', $_COOKIE[$this->cookieName]) === 1
)
{
return $this->hash = $_COOKIE[$this->cookieName];
}
$this->hash = bin2hex(random_bytes(16));
}
return $this->hash;
}
/**
* CSRF Send Cookie
*
* @param RequestInterface $request
*
* @return Security|false
*/
protected function sendCookie(RequestInterface $request)
{
if ($this->cookie->isSecure() && ! $request->isSecure())
{
return false;
}
$this->doSendCookie();
log_message('info', 'CSRF cookie sent.');
return $this;
}
/**
* Actual dispatching of cookies.
* Extracted for this to be unit tested.
*
* @codeCoverageIgnore
*
* @return void
*/
protected function doSendCookie(): void
{
cookies([$this->cookie], false)->dispatch();
}
}