diff --git a/README.md b/README.md index 3b35374..91820f7 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ Simple, clean and lightweight library escape, security - [x] V1.x, V2.x support all PHP version `>=5.6` - [x] V3.x support all PHP version `>=7.0` +- [x] V4.x support all PHP version `>=8.0` ## Contact & Support @@ -17,4 +18,4 @@ If any question & request, please contact following information |-------------|----------------------|------------------|---------------| | Hung Nguyen | dev@nguyenanhung.com | nguyenanhung5891 | @nguyenanhung | -From Vietnam with Love <3 \ No newline at end of file +From Vietnam with Love <3 diff --git a/composer.json b/composer.json index c522964..0cd0cb2 100644 --- a/composer.json +++ b/composer.json @@ -1,53 +1,53 @@ { - "name": "nguyenanhung/security", - "type": "library", - "description": "Wrapper for Security, Encrypt, Encode, Purifier", - "keywords": [ - "security", - "encrypt", - "encode", - "decode" - ], - "homepage": "https://github.com/nguyenanhung/security", - "license": "GPL-3.0", - "authors": [ - { - "name": "Nguyen An Hung", - "email": "dev@nguyenanhung.com", - "homepage": "https://nguyenanhung.com", - "role": "Developer" - } - ], - "require": { - "php": ">=7.0", - "ext-openssl": "*", - "paragonie/sodium_compat": "^1.17", - "ircmaxell/password-compat": "^1.0", - "symfony/security-csrf": "^5.3 || ^4.4 || ^3.4", - "ezyang/htmlpurifier": "^4.13", - "phpseclib/phpseclib": "^3.0", - "phpseclib/mcrypt_compat": "^2.0", - "voku/anti-xss": "^4.0 || ^3.0", - "nguyenanhung/escape-helper": "^2.0", - "nguyenanhung/math-helper": "^2.0", - "nguyenanhung/htmlawed": "^1.2" - }, - "require-dev": { - "kint-php/kint": ">=3.0" - }, - "suggest": { - "ext-json": "Needed to support JSON", - "ext-mcrypt": "Needed to support mcrypt", - "ext-iconv": "Needed to support iconv", - "ext-openssl": "Needed to support openssl", - "ext-mbstring": "Needed to support mb_string" - }, - "autoload": { - "psr-4": { - "nguyenanhung\\MySecurity\\": "src/" - }, - "files": [ - "helpers/helpers.php" - ] - } + "name": "nguyenanhung/security", + "type": "library", + "description": "Wrapper for Security, Encrypt, Encode, Purifier", + "keywords": [ + "security", + "encrypt", + "encode", + "decode" + ], + "homepage": "https://github.com/nguyenanhung/security", + "license": "GPL-3.0", + "authors": [ + { + "name": "Nguyen An Hung", + "email": "dev@nguyenanhung.com", + "homepage": "https://nguyenanhung.com", + "role": "Developer" + } + ], + "require": { + "php": ">=7.0", + "ext-openssl": "*", + "paragonie/sodium_compat": "^1.17", + "ircmaxell/password-compat": "^1.0", + "symfony/security-csrf": "^5.3 || ^4.4 || ^3.4", + "ezyang/htmlpurifier": "^4.13", + "phpseclib/phpseclib": "^3.0", + "phpseclib/mcrypt_compat": "^2.0", + "voku/anti-xss": "^4.0 || ^3.0", + "nguyenanhung/escape-helper": "^2.0", + "nguyenanhung/math-helper": "^2.0", + "nguyenanhung/htmlawed": "^1.2" + }, + "require-dev": { + "kint-php/kint": ">=3.0" + }, + "suggest": { + "ext-json": "Needed to support JSON", + "ext-mcrypt": "Needed to support mcrypt", + "ext-iconv": "Needed to support iconv", + "ext-openssl": "Needed to support openssl", + "ext-mbstring": "Needed to support mb_string" + }, + "autoload": { + "psr-4": { + "nguyenanhung\\MySecurity\\": "src/" + }, + "files": [ + "helpers/helpers.php" + ] + } } diff --git a/helpers/helpers.php b/helpers/helpers.php index a3552e1..ce8264c 100644 --- a/helpers/helpers.php +++ b/helpers/helpers.php @@ -8,102 +8,102 @@ * Time: 12:38 */ if (!function_exists('xssValidation')) { - /** - * Function xssValidation - * - * @param $value - * - * @return bool - * @author : 713uk13m - * @copyright: 713uk13m - * @time : 30/07/2022 57:32 - */ - function xssValidation($value): bool - { - return \nguyenanhung\MySecurity\Helper\Xss::xssValidation($value); - } + /** + * Function xssValidation + * + * @param $value + * + * @return bool + * @author : 713uk13m + * @copyright: 713uk13m + * @time : 30/07/2022 57:32 + */ + function xssValidation($value): bool + { + return \nguyenanhung\MySecurity\Helper\Xss::xssValidation($value); + } } if (!function_exists('xss_validation')) { - /** - * Function xss_validation - * - * @param $value - * - * @return bool - * @author : 713uk13m - * @copyright: 713uk13m - * @time : 12/02/2023 08:05 - */ - function xss_validation($value): bool - { - return \nguyenanhung\MySecurity\Helper\Xss::xss_validation($value); - } + /** + * Function xss_validation + * + * @param $value + * + * @return bool + * @author : 713uk13m + * @copyright: 713uk13m + * @time : 12/02/2023 08:05 + */ + function xss_validation($value): bool + { + return \nguyenanhung\MySecurity\Helper\Xss::xss_validation($value); + } } if (!function_exists('_force_xss_clean_')) { - /** - * Function _force_xss_clean_ - * - * @param $value - * - * @return mixed|string|string[] - * @author : 713uk13m - * @copyright: 713uk13m - * @time : 13/02/2023 11:23 - */ - function _force_xss_clean_($value) - { - return (new \voku\helper\AntiXSS())->xss_clean($value); - } + /** + * Function _force_xss_clean_ + * + * @param $value + * + * @return mixed|string|string[] + * @author : 713uk13m + * @copyright: 713uk13m + * @time : 13/02/2023 11:23 + */ + function _force_xss_clean_($value) + { + return (new \voku\helper\AntiXSS())->xss_clean($value); + } } if (!function_exists('_forceXssClean_')) { - /** - * Function _forceXssClean_ - * - * @param $value - * - * @return mixed|string|string[] - * @author : 713uk13m - * @copyright: 713uk13m - * @time : 13/02/2023 12:06 - */ - function _forceXssClean_($value) - { - return (new \voku\helper\AntiXSS())->xss_clean($value); - } + /** + * Function _forceXssClean_ + * + * @param $value + * + * @return mixed|string|string[] + * @author : 713uk13m + * @copyright: 713uk13m + * @time : 13/02/2023 12:06 + */ + function _forceXssClean_($value) + { + return (new \voku\helper\AntiXSS())->xss_clean($value); + } } if (!function_exists('_xss_clean_')) { - /** - * Function _xss_clean_ - * - * @param $value - * @param $is_image - * - * @return array|bool|string - * @throws \Exception - * @author : 713uk13m - * @copyright: 713uk13m - * @time : 13/02/2023 15:32 - */ - function _xss_clean_($value, $is_image = false) - { - return \nguyenanhung\MySecurity\Helper\Xss::xss_clean($value, $is_image); - } + /** + * Function _xss_clean_ + * + * @param $value + * @param $is_image + * + * @return array|bool|string + * @throws \Exception + * @author : 713uk13m + * @copyright: 713uk13m + * @time : 13/02/2023 15:32 + */ + function _xss_clean_($value, $is_image = false) + { + return \nguyenanhung\MySecurity\Helper\Xss::xss_clean($value, $is_image); + } } if (!function_exists('_xssClean_')) { - /** - * Function _xssClean_ - * - * @param $value - * @param $is_image - * - * @return array|bool|string - * @throws \Exception - * @author : 713uk13m - * @copyright: 713uk13m - * @time : 13/02/2023 15:22 - */ - function _xssClean_($value, $is_image = false) - { - return \nguyenanhung\MySecurity\Helper\Xss::xss_clean($value, $is_image); - } + /** + * Function _xssClean_ + * + * @param $value + * @param $is_image + * + * @return array|bool|string + * @throws \Exception + * @author : 713uk13m + * @copyright: 713uk13m + * @time : 13/02/2023 15:22 + */ + function _xssClean_($value, $is_image = false) + { + return \nguyenanhung\MySecurity\Helper\Xss::xss_clean($value, $is_image); + } } diff --git a/src/Encryption.php b/src/Encryption.php index 7f4cde8..770acae 100644 --- a/src/Encryption.php +++ b/src/Encryption.php @@ -20,28 +20,28 @@ */ class Encryption implements ProjectInterface { - use VersionTrait; + use VersionTrait; - /** - * Function createKey - * - * @param int $length - * - * @return string|bool - * @author : 713uk13m - * @copyright: 713uk13m - * @time : 09/24/2021 04:19 - */ - public function createKey(int $length = 32) - { - try { - return random_bytes($length); - } catch (Exception $e) { - if (function_exists('log_message')) { - log_message('error', 'Error File: ' . $e->getFile() . ' - Line: ' . $e->getLine() . ' - Message: ' . $e->getMessage()); - log_message('error', $e->getTraceAsString()); - } - return false; - } - } + /** + * Function createKey + * + * @param int $length + * + * @return string|bool + * @author : 713uk13m + * @copyright: 713uk13m + * @time : 09/24/2021 04:19 + */ + public function createKey(int $length = 32) + { + try { + return random_bytes($length); + } catch (Exception $e) { + if (function_exists('log_message')) { + log_message('error', 'Error File: ' . $e->getFile() . ' - Line: ' . $e->getLine() . ' - Message: ' . $e->getMessage()); + log_message('error', $e->getTraceAsString()); + } + return false; + } + } } diff --git a/src/Encryption/AES.php b/src/Encryption/AES.php index 5d97d59..5847df3 100644 --- a/src/Encryption/AES.php +++ b/src/Encryption/AES.php @@ -20,159 +20,159 @@ */ class AES { - /** @var int Key Length */ - private $keyLength = 128; - - /** @var string Private Key */ - private $key = '1234567890qwerty'; - - /** @var string $iv */ - private $iv; - - /** - * AES constructor. - * - * @author : 713uk13m - * @copyright: 713uk13m - */ - public function __construct() - { - } - - /** - * Function setKeyLength - * - * @param int $keyLength - * - * @return $this - * @author : 713uk13m - * @copyright: 713uk13m - * @time : 08/01/2021 04:06 - */ - public function setKeyLength(int $keyLength = 128): AES - { - $this->keyLength = $keyLength; - return $this; - } - - /** - * Function getKeyLength - * - * @return int - * @author : 713uk13m - * @copyright: 713uk13m - * @time : 04/20/2021 21:52 - */ - public function getKeyLength(): int - { - return $this->keyLength; - } - - /** - * Function setKey - * - * @param string $key - * - * @return $this - * @author : 713uk13m - * @copyright: 713uk13m - * @time : 04/20/2021 21:57 - */ - public function setKey(string $key = ''): AES - { - $this->key = $key; - return $this; - } - - /** - * Function getKey - * - * @return string - * @author : 713uk13m - * @copyright: 713uk13m - * @time : 08/01/2021 03:21 - */ - public function getKey(): string - { - return $this->key; - } - - /** - * Function setIv - * - * @param $iv - * - * @return $this - * @author : 713uk13m - * @copyright: 713uk13m - * @time : 04/20/2021 45:16 - */ - public function setIv($iv): AES - { - $this->iv = $iv; - return $this; - } - - /** - * Function getIv - * - * @return string - * @author : 713uk13m - * @copyright: 713uk13m - * @time : 09/24/2021 03:26 - */ - public function getIv(): string - { - return $this->iv; - } - - /** - * Function encrypt - * - * @author: 713uk13m - * @time : 2018-12-03 16:36 - * - * @param string $plainText - * - * @return string - */ - public function encrypt(string $plainText = ''): string - { - $cipher = new CryptAES('ctr'); - // could use AES::MODE_CBC - // keys are null-padded to the closest valid size - // longer than the longest key and it's truncated - $cipher->setKeyLength($this->keyLength); - $cipher->setKey($this->key); - // $cipher->setPassword($this->key, 'pbkdf2', 'sha1', 'phpseclib/salt', 1000, 256 / 8); - // the IV defaults to all-NULLs if not explicitly defined - $cipher->setIV($this->iv); - - return base64_encode($cipher->encrypt($plainText)); - } - - /** - * Function decrypt - * - * @author: 713uk13m - * @time : 2018-12-03 16:35 - * - * @param string $cipherText - * - * @return string - */ - public function decrypt(string $cipherText = ''): string - { - $cipher = new CryptAES('ctr'); - // could use AES::MODE_CBC - // keys are null-padded to the closest valid size - // longer than the longest key and it's truncated - $cipher->setKeyLength($this->keyLength); - $cipher->setKey($this->key); - // $cipher->setPassword($this->key, 'pbkdf2', 'sha1', 'phpseclib/salt', 1000, 256 / 8); - // the IV defaults to all-NULLs if not explicitly defined - $cipher->setIV($this->iv); - - return $cipher->decrypt(base64_decode($cipherText)); - } + /** @var int Key Length */ + private $keyLength = 128; + + /** @var string Private Key */ + private $key = '1234567890qwerty'; + + /** @var string $iv */ + private $iv; + + /** + * AES constructor. + * + * @author : 713uk13m + * @copyright: 713uk13m + */ + public function __construct() + { + } + + /** + * Function setKeyLength + * + * @param int $keyLength + * + * @return $this + * @author : 713uk13m + * @copyright: 713uk13m + * @time : 08/01/2021 04:06 + */ + public function setKeyLength(int $keyLength = 128): AES + { + $this->keyLength = $keyLength; + return $this; + } + + /** + * Function getKeyLength + * + * @return int + * @author : 713uk13m + * @copyright: 713uk13m + * @time : 04/20/2021 21:52 + */ + public function getKeyLength(): int + { + return $this->keyLength; + } + + /** + * Function setKey + * + * @param string $key + * + * @return $this + * @author : 713uk13m + * @copyright: 713uk13m + * @time : 04/20/2021 21:57 + */ + public function setKey(string $key = ''): AES + { + $this->key = $key; + return $this; + } + + /** + * Function getKey + * + * @return string + * @author : 713uk13m + * @copyright: 713uk13m + * @time : 08/01/2021 03:21 + */ + public function getKey(): string + { + return $this->key; + } + + /** + * Function setIv + * + * @param $iv + * + * @return $this + * @author : 713uk13m + * @copyright: 713uk13m + * @time : 04/20/2021 45:16 + */ + public function setIv($iv): AES + { + $this->iv = $iv; + return $this; + } + + /** + * Function getIv + * + * @return string + * @author : 713uk13m + * @copyright: 713uk13m + * @time : 09/24/2021 03:26 + */ + public function getIv(): string + { + return $this->iv; + } + + /** + * Function encrypt + * + * @param string $plainText + * + * @return string + * @author: 713uk13m + * @time : 2018-12-03 16:36 + * + */ + public function encrypt(string $plainText = ''): string + { + $cipher = new CryptAES('ctr'); + // could use AES::MODE_CBC + // keys are null-padded to the closest valid size + // longer than the longest key and it's truncated + $cipher->setKeyLength($this->keyLength); + $cipher->setKey($this->key); + // $cipher->setPassword($this->key, 'pbkdf2', 'sha1', 'phpseclib/salt', 1000, 256 / 8); + // the IV defaults to all-NULLs if not explicitly defined + $cipher->setIV($this->iv); + + return base64_encode($cipher->encrypt($plainText)); + } + + /** + * Function decrypt + * + * @param string $cipherText + * + * @return string + * @author: 713uk13m + * @time : 2018-12-03 16:35 + * + */ + public function decrypt(string $cipherText = ''): string + { + $cipher = new CryptAES('ctr'); + // could use AES::MODE_CBC + // keys are null-padded to the closest valid size + // longer than the longest key and it's truncated + $cipher->setKeyLength($this->keyLength); + $cipher->setKey($this->key); + // $cipher->setPassword($this->key, 'pbkdf2', 'sha1', 'phpseclib/salt', 1000, 256 / 8); + // the IV defaults to all-NULLs if not explicitly defined + $cipher->setIV($this->iv); + + return $cipher->decrypt(base64_decode($cipherText)); + } } diff --git a/src/Helper/Xss.php b/src/Helper/Xss.php index 4ff77e8..24c9813 100644 --- a/src/Helper/Xss.php +++ b/src/Helper/Xss.php @@ -23,668 +23,665 @@ */ class Xss { - /** - * XSS Clean - * - * ************************************************************** - * *********** This function and other functions that it uses - * *********** are taken from Codeigniter 2.1.3 and modified - * *********** them to our needs. In turn, I have taken this from - * *********** JasonMortonNZ. - *************************************************************** - * - * - * Sanitizes data so that Cross Site Scripting Hacks can be - * prevented. This function does a fair amount of work but - * it is extremely thorough, designed to prevent even the - * most obscure XSS attempts. Nothing is ever 100% foolproof, - * of course, but I haven't been able to get anything passed - * the filter. - * - * Note: This function should only be used to deal with data - * upon submission. It's not something that should - * be used for general runtime processing. - * - * This function was based in part on some code and ideas I - * got from Bitflux: http://channel.bitflux.ch/wiki/XSS_Prevention - * - * To help develop this script I used this great list of - * vulnerabilities along with a few other hacks I've - * harvested from examining vulnerabilities in other programs: - * http://ha.ckers.org/xss.html - * - * @param mixed $str string or array - * @param bool $is_image - * - * @return array|bool|string - * @throws \Exception - */ - public static function xss_clean($str, bool $is_image = false) - { - /* - * Is the string an array? - * - */ - if (is_array($str)) { - while (list($key) = each($str)) { - $str[$key] = self::xss_clean($str[$key]); - } - - return $str; - } - - /* - * Remove Invisible Characters - */ - $str = self::removeInvisibleCharacters($str); - - // Validate Entities in URLs - $str = self::validateEntities($str); - - /* - * URL Decode - * - * Just in case stuff like this is submitted: - * - * Google - * - * Note: Use rawurldecode() so it does not remove plus signs - * - */ - $str = rawurldecode($str); - - /* - * Convert character entities to ASCII - * - * This permits our tests below to work reliably. - * We only convert entities that are within tags since - * these are the ones that will pose security problems. - * - */ - $entitiesRegex = "/[a-z]+=([\'\"]).*?\\1/si"; - $str = preg_replace_callback($entitiesRegex, static function($match) { - return str_replace(['>', '<', '\\'], ['>', '<', '\\\\'], $match[0]); - }, $str); - $str = preg_replace_callback("/<\w+.*?(?=>|<|$)/si", 'self::entityDecode', $str); - - /* - * Remove Invisible Characters Again! - */ - $str = self::removeInvisibleCharacters($str); - - /* - * Convert all tabs to spaces - * - * This prevents strings like this: ja vascript - * NOTE: we deal with spaces between characters later. - * NOTE: preg_replace was found to be amazingly slow here on - * large blocks of data, so we use str_replace. - */ - if (mb_strpos($str, "\t") !== false) { - $str = str_replace("\t", ' ', $str); - } - - /* - * Capture converted string for later comparison - */ - $converted_string = $str; - - // Remove Strings that are never allowed - $str = self::doNeverAllowed($str); - - /* - * Makes PHP tags safe - * - * Note: XML tags are inadvertently replaced too: - * - * '], ['<?', '?>'], $str); - } - - /* - * Compact any exploded words - * - * This corrects words like: j a v a s c r i p t - * These words are compacted back to their correct state. - */ - $words = [ - 'javascript', - 'expression', - 'vbscript', - 'script', - 'base64', - 'applet', - 'alert', - 'document', - 'write', - 'cookie', - 'window' - ]; - foreach ($words as $word) { - $temp = ''; - for ($i = 0, $wordlen = mb_strlen($word); $i < $wordlen; $i++) { - $temp .= $word[$i] . "\s*"; - } - // We only want to do this when it is followed by a non-word character - // That way valid stuff like "dealer to" does not become "dealerto" - $str = preg_replace_callback('#(' . mb_substr($temp, 0, -3) . ')(\W)#is', static function($matches) { - return preg_replace('/\s+/s', '', $matches[1]) . $matches[2]; - }, $str); - } - - /* - * Remove disallowed Javascript in links or img tags - * We used to do some version comparisons and use of stripos for PHP5, - * but it is dog slow compared to these simplified non-capturing - * preg_match(), especially if the pattern exists in the string - */ - do { - $original = $str; - if (preg_match("/]*?)(>|$)#si", static function($match) { - $htmlTagPattern = '#href=.*?(alert\(|alert&\#40;|javascript\:|livescript\:|mocha\:|charset\=|window\.|document\.|\.cookie|'], '', $match[1]))), $match[0]); - }, $str); - } - if (preg_match("/]*?)(\s?/?>|$)#si", static function($match) { - $htmlTagPattern = '#src=.*?(alert\(|alert&\#40;|javascript\:|livescript\:|mocha\:|charset\=|window\.|document\.|\.cookie|'], '', $match[1]))), $match[0]); - }, $str); - } - if (preg_match("/script/i", $str) || preg_match("/xss/i", $str)) { - $htmlTagPattern = "#<(/*)(script|xss)(.*?)\>#si"; - $str = preg_replace($htmlTagPattern, '[removed]', $str); - } - } - while ($original !== $str); - unset($original); - - // Remove evil attributes such as style, onclick and xmlns - $str = self::removeEvilAttributes($str, $is_image); - - /* - * Sanitize naughty HTML elements - * - * If a tag containing any of the words in the list - * below is found, the tag gets converted to entities. - * - * So this: - * Becomes: <blink> - */ - $naughty = 'alert|applet|audio|basefont|base|behavior|bgsound|blink|body|embed|expression|form|frameset|frame|head|html|ilayer|iframe|input|isindex|layer|link|meta|object|plaintext|style|script|textarea|title|video|xml|xss'; - $str = preg_replace_callback('#<(/*\s*)(' . $naughty . ')([^><]*)([><]*)#is', static function($matches) { - // encode opening brace - $str = '<' . $matches[1] . $matches[2] . $matches[3]; - - // encode captured opening or closing brace to prevent recursive vectors - $str .= str_replace(['>', '<'], ['>', '<'], $matches[4]); - - return $str; - }, $str); - - /* - * Sanitize naughty scripting elements - * - * Similar to above, only instead of looking for - * tags it looks for PHP and JavaScript commands - * that are disallowed. Rather than removing the - * code, it simply converts the parenthesis to entities - * rendering the code un-executable. - * - * For example: eval('some code') - * Becomes: eval('some code') - */ - $str = preg_replace('#(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', "\\1\\2(\\3)", $str); - - // Final clean up - // This adds a bit of extra precaution in case - // something got through the above filters - $str = self::doNeverAllowed($str); - - /* - * Images are Handled in a Special Way - * - Essentially, we want to know that after all of the character - * conversion is done whether any unwanted, likely XSS, code was found. - * If not, we return TRUE, as the image is clean. - * However, if the string post-conversion does not matched the - * string post-removal of XSS, then it fails, as there was unwanted XSS - * code found and removed/changed during processing. - */ - if ($is_image === true) { - return $str === $converted_string; - } - - return $str; - } - - /** - * Function xssValidation - * - * @param $value - * - * @return bool - * @author : 713uk13m - * @copyright: 713uk13m - * @time : 30/07/2022 57:32 - */ - public static function xssValidation($value): bool - { - $value = preg_replace('/%3A%2F%2F/', '', $value); // :// to empty - $value = preg_replace('/([\x00-\x08][\x0b-\x0c][\x0e-\x20])/', '', $value); - $value = preg_replace('/%u0([a-z0-9]{3})/i', '&#x\\1;', $value); - $value = preg_replace('/%([a-z0-9]{2})/i', '&#x\\1;', $value); - $search_str_ireplace = array( - 'SCRIPT', - '&#x6A;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;', - '/*', - '*/', - '', - '', - ' ', - ' ', - ' ', - '' - ); - $value = str_ireplace($search_str_ireplace, '', $value); - - $search = '/&#[xX]0{0,8}(21|22|23|24|25|26|27|28|29|2a|2b|2d|2f|30|31|32|33|34|35|36|37|38|39|3a|3b|3d|3f|40|41|42|43|44|45|46|47|48|49|4a|4b|4c|4d|4e|4f|50|51|52|53|54|55|56|57|58|59|5a|5b|5c|5d|5e|5f|60|61|62|63|64|65|66|67|68|69|6a|6b|6c|6d|6e|6f|70|71|72|73|74|75|76|77|78|79|7a|7b|7c|7d|7e);?/i'; - $value = preg_replace_callback($search, function($m) { - return chr(hexdec($m[1])); - }, $value); - - $search = '/�{0,8}(33|34|35|36|37|38|39|40|41|42|43|45|47|48|49|50|51|52|53|54|55|56|57|58|59|61|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100|101|102|103|104|105|106|107|108|109|110|111|112|113|114|115|116|117|118|119|120|121|122|123|124|125|126);?/i'; - $value = preg_replace_callback($search, function($m) { - return chr($m[1]); - }, $value); - - $search = array( - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '<', - '\x3c', - '\x3C', - '\u003c', - '\u003C' - ); - $value = str_ireplace($search, '<', $value); - - $search = array( - 'expression' => '/e\s*x\s*p\s*r\s*e\s*s\s*s\s*i\s*o\s*n/si', - 'javascript' => '/j\s*a\s*v\s*a\s*s\s*c\s*r\s*i\s*p\s*t/si', - 'livescript' => '/l\s*i\s*v\s*e\s*s\s*c\s*r\s*i\s*p\s*t/si', - 'behavior' => '/b\s*e\s*h\s*a\s*v\s*i\s*o\s*r/si', - 'vbscript' => '/v\s*b\s*s\s*c\s*r\s*i\s*p\s*t/si', - 'script' => '/s\s*c\s*r\s*i\s*p\s*t/si', - 'applet' => '/a\s*p\s*p\s*l\s*e\s*t/si', - 'alert' => '/a\s*l\s*e\s*r\s*t/si', - 'document' => '/d\s*o\s*c\s*u\s*m\s*e\s*n\s*t/si', - 'write' => '/w\s*r\s*i\s*t\s*e/si', - 'cookie' => '/c\s*o\s*o\s*k\s*i\s*e/si', - 'window' => '/w\s*i\s*n\s*d\s*o\s*w/si', - 'data:' => '/d\s*a\s*t\s*a\s*\:/si' - ); - $value = preg_replace(array_values($search), array_keys($search), $value); - if (preg_match('/(expression|javascript|behavior|vbscript|mocha|livescript)(\:*)/', $value)) { - return false; - } - - if (strcasecmp($value, strip_tags($value)) !== 0) { - return false; - } - - $disableCommands = array( - 'base64_decode', - 'cmd', - 'passthru', - 'eval', - 'exec', - 'system', - 'fopen', - 'fsockopen', - 'file', - 'file_get_contents', - 'readfile', - 'unlink', - 'alert', - 'prompt', - 'confirm', - 'execScript', - 'setTimeout', - 'setInterval', - 'setImmediate', - 'expression', - ); - if (preg_match('#(' . implode('|', $disableCommands) . ')(\s*)\((.*?)\)#si', $value)) { - return false; - } - - return true; - } - - /** - * Function xss_validation - * - * @param $value - * - * @return bool - * @author : 713uk13m - * @copyright: 713uk13m - * @time : 12/02/2023 05:27 - */ - public static function xss_validation($value): bool - { - return self::xssValidation($value); - } - - /** - * Function remove_invisible_characters - * - * @author: 713uk13m - * @time : 2018-12-03 15:50 - * - * @param $str - * @param bool $url_encoded - * - * @return string|string[]|null - */ - public static function removeInvisibleCharacters($str, bool $url_encoded = true) - { - $non_displayables = []; - - // every control character except newline (dec 10) - // carriage return (dec 13), and horizontal tab (dec 09) - - if ($url_encoded) { - $non_displayables[] = '/%0[0-8bcef]/'; // url encoded 00-08, 11, 12, 14, 15 - $non_displayables[] = '/%1[0-9a-f]/'; // url encoded 16-31 - } - - $non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S'; // 00-08, 11, 12, 14-31, 127 - do { - $str = preg_replace($non_displayables, '', $str, -1, $count); - } - while ($count); - - return $str; - } - - /** - * Validate URL entities - * - * Called by xss_clean() - * - * @param $str - * - * @return string - * @throws \Exception - * @author : 713uk13m - * @copyright: 713uk13m - * @time : 09/24/2021 06:16 - */ - protected static function validateEntities($str): string - { - /* - * Protect GET variables in URLs - */ - $xss_hash = md5(time() + random_int(0, 1999999999)); - $entitiesPattern = '|\&([a-z\_0-9\-]+)\=([a-z\_0-9\-]+)|i'; - $str = preg_replace($entitiesPattern, $xss_hash . "\\1=\\2", $str); - - /* - * Validate standard character entities - * - * Add a semicolon if missing. We do this to enable - * the conversion of entities to ASCII later. - * - */ - $str = preg_replace('#(&\#?[0-9a-z]{2,})([\x00-\x20])*;?#i', "\\1;\\2", $str); - - /* - * Validate UTF16 two byte encoding (x00) - * - * Just as above, adds a semicolon if missing. - * - */ - $str = preg_replace('#(&\#x?)([0-9A-F]+);?#i', "\\1\\2;", $str); - - /* - * Un-Protect GET variables in URLs - */ - return str_replace($xss_hash, '&', $str); - } - - /** - * Do Never Allowed - * - * A utility function for xss_clean() - * - * @param string $str - * - * @return string - */ - protected static function doNeverAllowed($str): string - { - /** - * List of never allowed strings - */ - $never_allowed_str = [ - 'document.cookie' => '[removed]', - 'document.write' => '[removed]', - '.parentNode' => '[removed]', - '.innerHTML' => '[removed]', - 'window.location' => '[removed]', - '-moz-binding' => '[removed]', - '' => '-->', - ' '<![CDATA[', - '' => '<comment>', - '(document).cookie' => '[removed]', - '(document).write' => '[removed]', - '.appendChild' => '[removed]', - ' '<?', - '?>' => '?>', - ' '<!ENTITY', - ' '<!DOCTYPE', - ' '<!ATTLIST', - ]; - - /** - * List of never allowed regex replacement - */ - $never_allowed_regex = [ - // default javascript - '(\(?:?document\)?|\(?:?window\)?(?:\.document)?)\.(?:location|on\w*)', - // data-attribute + base64 - "([\"'])?data\s*:\s*(?!image\s*\/\s*(?!svg.*?))[^\1]*?base64[^\1]*?,[^\1]*?\1?", - // old IE, old Netscape - 'expression\s*(?:\(|&\#40;)', - // src="js" - 'src\=(?[\'|"]).*\.js(?:\g{wrapper})', - // comments - '', - '', + '', + ' ', + ' ', + ' ', + '' + ); + $value = str_ireplace($search_str_ireplace, '', $value); + + $search = '/&#[xX]0{0,8}(21|22|23|24|25|26|27|28|29|2a|2b|2d|2f|30|31|32|33|34|35|36|37|38|39|3a|3b|3d|3f|40|41|42|43|44|45|46|47|48|49|4a|4b|4c|4d|4e|4f|50|51|52|53|54|55|56|57|58|59|5a|5b|5c|5d|5e|5f|60|61|62|63|64|65|66|67|68|69|6a|6b|6c|6d|6e|6f|70|71|72|73|74|75|76|77|78|79|7a|7b|7c|7d|7e);?/i'; + $value = preg_replace_callback($search, function ($m) { + return chr(hexdec($m[1])); + }, $value); + + $search = '/�{0,8}(33|34|35|36|37|38|39|40|41|42|43|45|47|48|49|50|51|52|53|54|55|56|57|58|59|61|63|64|65|66|67|68|69|70|71|72|73|74|75|76|77|78|79|80|81|82|83|84|85|86|87|88|89|90|91|92|93|94|95|96|97|98|99|100|101|102|103|104|105|106|107|108|109|110|111|112|113|114|115|116|117|118|119|120|121|122|123|124|125|126);?/i'; + $value = preg_replace_callback($search, function ($m) { + return chr($m[1]); + }, $value); + + $search = array( + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '<', + '\x3c', + '\x3C', + '\u003c', + '\u003C' + ); + $value = str_ireplace($search, '<', $value); + + $search = array( + 'expression' => '/e\s*x\s*p\s*r\s*e\s*s\s*s\s*i\s*o\s*n/si', + 'javascript' => '/j\s*a\s*v\s*a\s*s\s*c\s*r\s*i\s*p\s*t/si', + 'livescript' => '/l\s*i\s*v\s*e\s*s\s*c\s*r\s*i\s*p\s*t/si', + 'behavior' => '/b\s*e\s*h\s*a\s*v\s*i\s*o\s*r/si', + 'vbscript' => '/v\s*b\s*s\s*c\s*r\s*i\s*p\s*t/si', + 'script' => '/s\s*c\s*r\s*i\s*p\s*t/si', + 'applet' => '/a\s*p\s*p\s*l\s*e\s*t/si', + 'alert' => '/a\s*l\s*e\s*r\s*t/si', + 'document' => '/d\s*o\s*c\s*u\s*m\s*e\s*n\s*t/si', + 'write' => '/w\s*r\s*i\s*t\s*e/si', + 'cookie' => '/c\s*o\s*o\s*k\s*i\s*e/si', + 'window' => '/w\s*i\s*n\s*d\s*o\s*w/si', + 'data:' => '/d\s*a\s*t\s*a\s*\:/si' + ); + $value = preg_replace(array_values($search), array_keys($search), $value); + if (preg_match('/(expression|javascript|behavior|vbscript|mocha|livescript)(\:*)/', $value)) { + return false; + } + + if (strcasecmp($value, strip_tags($value)) !== 0) { + return false; + } + + $disableCommands = array( + 'base64_decode', + 'cmd', + 'passthru', + 'eval', + 'exec', + 'system', + 'fopen', + 'fsockopen', + 'file', + 'file_get_contents', + 'readfile', + 'unlink', + 'alert', + 'prompt', + 'confirm', + 'execScript', + 'setTimeout', + 'setInterval', + 'setImmediate', + 'expression', + ); + if (preg_match('#(' . implode('|', $disableCommands) . ')(\s*)\((.*?)\)#si', $value)) { + return false; + } + + return true; + } + + /** + * Function xss_validation + * + * @param $value + * + * @return bool + * @author : 713uk13m + * @copyright: 713uk13m + * @time : 12/02/2023 05:27 + */ + public static function xss_validation($value): bool + { + return self::xssValidation($value); + } + + /** + * Function remove_invisible_characters + * + * @param $str + * @param bool $url_encoded + * + * @return string|string[]|null + * @author: 713uk13m + * @time : 2018-12-03 15:50 + * + */ + public static function removeInvisibleCharacters($str, bool $url_encoded = true) + { + $non_displayables = []; + + // every control character except newline (dec 10) + // carriage return (dec 13), and horizontal tab (dec 09) + + if ($url_encoded) { + $non_displayables[] = '/%0[0-8bcef]/'; // url encoded 00-08, 11, 12, 14, 15 + $non_displayables[] = '/%1[0-9a-f]/'; // url encoded 16-31 + } + + $non_displayables[] = '/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S'; // 00-08, 11, 12, 14-31, 127 + do { + $str = preg_replace($non_displayables, '', $str, -1, $count); + } while ($count); + + return $str; + } + + /** + * Validate URL entities + * + * Called by xss_clean() + * + * @param $str + * + * @return string + * @throws \Exception + * @author : 713uk13m + * @copyright: 713uk13m + * @time : 09/24/2021 06:16 + */ + protected static function validateEntities($str): string + { + /* + * Protect GET variables in URLs + */ + $xss_hash = md5(time() + random_int(0, 1999999999)); + $entitiesPattern = '|\&([a-z\_0-9\-]+)\=([a-z\_0-9\-]+)|i'; + $str = preg_replace($entitiesPattern, $xss_hash . "\\1=\\2", $str); + + /* + * Validate standard character entities + * + * Add a semicolon if missing. We do this to enable + * the conversion of entities to ASCII later. + * + */ + $str = preg_replace('#(&\#?[0-9a-z]{2,})([\x00-\x20])*;?#i', "\\1;\\2", $str); + + /* + * Validate UTF16 two byte encoding (x00) + * + * Just as above, adds a semicolon if missing. + * + */ + $str = preg_replace('#(&\#x?)([0-9A-F]+);?#i', "\\1\\2;", $str); + + /* + * Un-Protect GET variables in URLs + */ + return str_replace($xss_hash, '&', $str); + } + + /** + * Do Never Allowed + * + * A utility function for xss_clean() + * + * @param string $str + * + * @return string + */ + protected static function doNeverAllowed($str): string + { + /** + * List of never allowed strings + */ + $never_allowed_str = [ + 'document.cookie' => '[removed]', + 'document.write' => '[removed]', + '.parentNode' => '[removed]', + '.innerHTML' => '[removed]', + 'window.location' => '[removed]', + '-moz-binding' => '[removed]', + '' => '-->', + ' '<![CDATA[', + '' => '<comment>', + '(document).cookie' => '[removed]', + '(document).write' => '[removed]', + '.appendChild' => '[removed]', + ' '<?', + '?>' => '?>', + ' '<!ENTITY', + ' '<!DOCTYPE', + ' '<!ATTLIST', + ]; + + /** + * List of never allowed regex replacement + */ + $never_allowed_regex = [ + // default javascript + '(\(?:?document\)?|\(?:?window\)?(?:\.document)?)\.(?:location|on\w*)', + // data-attribute + base64 + "([\"'])?data\s*:\s*(?!image\s*\/\s*(?!svg.*?))[^\1]*?base64[^\1]*?,[^\1]*?\1?", + // old IE, old Netscape + 'expression\s*(?:\(|&\#40;)', + // src="js" + 'src\=(?[\'|"]).*\.js(?:\g{wrapper})', + // comments + '', + '