From a9b02e5ac1dafc39d2b8578f673c5db327420ed8 Mon Sep 17 00:00:00 2001 From: Steeven Andrian Date: Sat, 23 May 2020 21:56:28 +0700 Subject: [PATCH] code re-formats --- .gitignore | 4 +- LICENSE | 42 +- composer.json | 92 +- src/Authentication/WebToken.php | 96 +- src/Filters/Utf8.php | 366 ++++---- src/Filters/Xss.php | 1186 ++++++++++++------------- src/Form/Validation.php | 1458 +++++++++++++++---------------- src/Protections/Csrf.php | 200 ++--- src/Protections/Firewall.php | 468 +++++----- src/Protections/Xss.php | 224 ++--- src/autoload.php | 92 +- 11 files changed, 2114 insertions(+), 2114 deletions(-) diff --git a/.gitignore b/.gitignore index 1258669..9bea433 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ - -.DS_Store + +.DS_Store diff --git a/LICENSE b/LICENSE index aaefb5a..cd5ace5 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2016 Steeve Andrian Salim - -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. +MIT License + +Copyright (c) 2016 Steeve Andrian Salim + +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. diff --git a/composer.json b/composer.json index af5c3de..0eb77d0 100644 --- a/composer.json +++ b/composer.json @@ -1,46 +1,46 @@ -{ - "name": "o2system/security", - "description": "O2System Security", - "type": "package", - "keywords": [ - "utilities", - "php", - "framework", - "libraries", - "interfaces" - ], - "authors": [ - { - "name": "Steeven Andrian Salim", - "email": "steevenz@steevenz.com", - "homepage": "http://www.steevenz.com", - "role": "Founder and Lead Project" - }, - { - "name": "Teguh Rianto", - "email": "teguh.rianto22@gmail.com", - "homepage": "http://teguhrianto22.pusku.com", - "role": "Template Designer" - } - ], - "support": { - "email": "o2system.framework@gmail.com", - "issues": "https://github.com/o2system/psr/issues", - "forum": "https://www.facebook.com/groups/498147006994512" - }, - "links": { - "info": "http://www.o2system.id/libraries/psr.html", - "documentation": "http://www.o2system.id/libraries/psr/documentation.html", - "github-wiki": "http://github.com/o2system/psr/wiki" - }, - "require": { - "php": "^7.2.0", - "ext-openssl": "*", - "o2system/session": "*" - }, - "autoload": { - "psr-4": { - "O2System\\Security\\": "src" - } - } -} +{ + "name": "o2system/security", + "description": "O2System Security", + "type": "package", + "keywords": [ + "utilities", + "php", + "framework", + "libraries", + "interfaces" + ], + "authors": [ + { + "name": "Steeven Andrian Salim", + "email": "steevenz@steevenz.com", + "homepage": "http://www.steevenz.com", + "role": "Founder and Lead Project" + }, + { + "name": "Teguh Rianto", + "email": "teguh.rianto22@gmail.com", + "homepage": "http://teguhrianto22.pusku.com", + "role": "Template Designer" + } + ], + "support": { + "email": "o2system.framework@gmail.com", + "issues": "https://github.com/o2system/psr/issues", + "forum": "https://www.facebook.com/groups/498147006994512" + }, + "links": { + "info": "http://www.o2system.id/libraries/psr.html", + "documentation": "http://www.o2system.id/libraries/psr/documentation.html", + "github-wiki": "http://github.com/o2system/psr/wiki" + }, + "require": { + "php": "^7.2.0", + "ext-openssl": "*", + "o2system/session": "*" + }, + "autoload": { + "psr-4": { + "O2System\\Security\\": "src" + } + } +} diff --git a/src/Authentication/WebToken.php b/src/Authentication/WebToken.php index 41c3e52..6278899 100644 --- a/src/Authentication/WebToken.php +++ b/src/Authentication/WebToken.php @@ -1,49 +1,49 @@ -server('HTTP_X_WEB_TOKEN'); - - if (is_null($token)) { - return false; - } elseif (is_callable($callback)) { - return call_user_func($callback, $token); - } - - return false; - } +server('HTTP_X_WEB_TOKEN'); + + if (is_null($token)) { + return false; + } elseif (is_callable($callback)) { + return call_user_func($callback, $token); + } + + return false; + } } \ No newline at end of file diff --git a/src/Filters/Utf8.php b/src/Filters/Utf8.php index 1dd6f05..bbdccb7 100644 --- a/src/Filters/Utf8.php +++ b/src/Filters/Utf8.php @@ -1,184 +1,184 @@ -config[ 'charset' ]); -ini_set('default_charset', $charset); - -if (extension_loaded('mbstring')) { - define('MB_ENABLED', true); - - // mbstring.internal_encoding is deprecated starting with PHP 5.6 - // and it's usage triggers E_DEPRECATED messages. - if (is_php('5.6', '<=')) { - @ini_set('mbstring.internal_encoding', $charset); - } - - // This is required for mb_convert_encoding() to strip invalid characters. - // That's utilized by UTF8 Class, but it's also done for consistency with iconv. - mb_substitute_character('none'); -} else { - define('MB_ENABLED', false); -} - -// There's an ICONV_IMPL constant, but the PHP manual says that using -// iconv's predefined constants is "strongly discouraged". -if (extension_loaded('iconv')) { - define('ICONV_ENABLED', true); - - // iconv.internal_encoding is deprecated starting with PHP 5.6 - // and it's usage triggers E_DEPRECATED messages. - - if (is_php('5.6', '<=')) { - @ini_set('iconv.internal_encoding', $charset); - } -} else { - define('ICONV_ENABLED', false); -} - -if (is_php('5.6')) { - ini_set('php.internal_encoding', $charset); -} - - -class Utf8 -{ - protected $isEnabled = false; - - /** - * Class constructor - * - * Determines if UTF-8 support is to be enabled. - * - * @access public - */ - public function __construct() - { - if ( - defined('PREG_BAD_UTF8_ERROR') // PCRE must support UTF-8 - AND (ICONV_ENABLED === true || MB_ENABLED === true) // iconv or mbstring must be installed - AND strtoupper(o2system()->config[ 'charset' ]) === 'UTF-8' // Application charset must be UTF-8 - ) { - $this->isEnabled = true; - logger()->debug('LOG_DEBUG_UTF8_SUPPORT_ENABLED'); - } else { - $this->isEnabled = false; - logger()->debug('LOG_DEBUG_UTF8_SUPPORT_DISABLED'); - } - - logger()->debug('LOG_DEBUG_CLASS_INITIALIZED', [__CLASS__]); - } - - // -------------------------------------------------------------------- - - public function isEnabled() - { - return (bool)$this->isEnabled; - } - - /** - * Clean UTF-8 strings - * - * Ensures strings contain only valid UTF-8 characters. - * - * @param string $string String to clean - * - * @return string - */ - public function cleanString($string) - { - if ($this->isAscii($string) === false) { - if (MB_ENABLED) { - $string = mb_convert_encoding($string, 'UTF-8', 'UTF-8'); - } elseif (ICONV_ENABLED) { - $string = @iconv('UTF-8', 'UTF-8//IGNORE', $string); - } - } - - return $string; - } - - // -------------------------------------------------------------------- - - /** - * Is ASCII? - * - * Tests if a string is standard 7-bit ASCII or not. - * - * @param string $string String to check - * - * @return bool - */ - public function isAscii($string) - { - return (preg_match('/[^\x00-\x7F]/S', $string) === 0); - } - - // -------------------------------------------------------------------- - - /** - * Remove ASCII control characters - * - * Removes all ASCII control characters except horizontal tabs, - * line feeds, and carriage returns, as all others can cause - * problems in XML. - * - * @param string $string String to clean - * - * @return string - */ - public function safeAsciiForXML($string) - { - return remove_invisible_characters($string, false); - } - - // -------------------------------------------------------------------- - - /** - * Convert to UTF-8 - * - * Attempts to convert a string to UTF-8. - * - * @param string $string Input string - * @param string $encoding Input encoding - * - * @return string $str encoded in UTF-8 or FALSE on failure - */ - public function convertString($string, $encoding) - { - if (MB_ENABLED) { - return mb_convert_encoding($string, 'UTF-8', $encoding); - } elseif (ICONV_ENABLED) { - return @iconv($encoding, 'UTF-8', $string); - } - - return false; - } +config[ 'charset' ]); +ini_set('default_charset', $charset); + +if (extension_loaded('mbstring')) { + define('MB_ENABLED', true); + + // mbstring.internal_encoding is deprecated starting with PHP 5.6 + // and it's usage triggers E_DEPRECATED messages. + if (is_php('5.6', '<=')) { + @ini_set('mbstring.internal_encoding', $charset); + } + + // This is required for mb_convert_encoding() to strip invalid characters. + // That's utilized by UTF8 Class, but it's also done for consistency with iconv. + mb_substitute_character('none'); +} else { + define('MB_ENABLED', false); +} + +// There's an ICONV_IMPL constant, but the PHP manual says that using +// iconv's predefined constants is "strongly discouraged". +if (extension_loaded('iconv')) { + define('ICONV_ENABLED', true); + + // iconv.internal_encoding is deprecated starting with PHP 5.6 + // and it's usage triggers E_DEPRECATED messages. + + if (is_php('5.6', '<=')) { + @ini_set('iconv.internal_encoding', $charset); + } +} else { + define('ICONV_ENABLED', false); +} + +if (is_php('5.6')) { + ini_set('php.internal_encoding', $charset); +} + + +class Utf8 +{ + protected $isEnabled = false; + + /** + * Class constructor + * + * Determines if UTF-8 support is to be enabled. + * + * @access public + */ + public function __construct() + { + if ( + defined('PREG_BAD_UTF8_ERROR') // PCRE must support UTF-8 + AND (ICONV_ENABLED === true || MB_ENABLED === true) // iconv or mbstring must be installed + AND strtoupper(o2system()->config[ 'charset' ]) === 'UTF-8' // Application charset must be UTF-8 + ) { + $this->isEnabled = true; + logger()->debug('LOG_DEBUG_UTF8_SUPPORT_ENABLED'); + } else { + $this->isEnabled = false; + logger()->debug('LOG_DEBUG_UTF8_SUPPORT_DISABLED'); + } + + logger()->debug('LOG_DEBUG_CLASS_INITIALIZED', [__CLASS__]); + } + + // -------------------------------------------------------------------- + + public function isEnabled() + { + return (bool)$this->isEnabled; + } + + /** + * Clean UTF-8 strings + * + * Ensures strings contain only valid UTF-8 characters. + * + * @param string $string String to clean + * + * @return string + */ + public function cleanString($string) + { + if ($this->isAscii($string) === false) { + if (MB_ENABLED) { + $string = mb_convert_encoding($string, 'UTF-8', 'UTF-8'); + } elseif (ICONV_ENABLED) { + $string = @iconv('UTF-8', 'UTF-8//IGNORE', $string); + } + } + + return $string; + } + + // -------------------------------------------------------------------- + + /** + * Is ASCII? + * + * Tests if a string is standard 7-bit ASCII or not. + * + * @param string $string String to check + * + * @return bool + */ + public function isAscii($string) + { + return (preg_match('/[^\x00-\x7F]/S', $string) === 0); + } + + // -------------------------------------------------------------------- + + /** + * Remove ASCII control characters + * + * Removes all ASCII control characters except horizontal tabs, + * line feeds, and carriage returns, as all others can cause + * problems in XML. + * + * @param string $string String to clean + * + * @return string + */ + public function safeAsciiForXML($string) + { + return remove_invisible_characters($string, false); + } + + // -------------------------------------------------------------------- + + /** + * Convert to UTF-8 + * + * Attempts to convert a string to UTF-8. + * + * @param string $string Input string + * @param string $encoding Input encoding + * + * @return string $str encoded in UTF-8 or FALSE on failure + */ + public function convertString($string, $encoding) + { + if (MB_ENABLED) { + return mb_convert_encoding($string, 'UTF-8', $encoding); + } elseif (ICONV_ENABLED) { + return @iconv($encoding, 'UTF-8', $string); + } + + return false; + } } \ No newline at end of file diff --git a/src/Filters/Xss.php b/src/Filters/Xss.php index 04d6d12..3645299 100644 --- a/src/Filters/Xss.php +++ b/src/Filters/Xss.php @@ -1,594 +1,594 @@ -Google - * - * Note: Use rawurldecode() so it does not remove plus signs - */ - do { - $string = rawurldecode($string); - } while (preg_match('/%[0-9a-f]{2,}/i', $string)); - - /* - * 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. - */ - $string = preg_replace_callback( - "/[^a-z0-9>]+[a-z0-9]+=([\'\"]).*?\\1/si", - [self::class, 'convertAttribute'], - $string - ); - - $string = preg_replace_callback('/<\w+.*/si', [self::class, 'decodeEntity'], $string); - - // Remove Invisible Characters Again! - $string = remove_invisible_characters($string); - - /* - * 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. - */ - $string = str_replace("\t", ' ', $string); - - // Capture converted string for later comparison - $convertedString = $string; - - // Remove Strings that are never allowed - $string = self::doNeverAllowed($string); - - /* - * Makes PHP tags safe - * - * Note: XML tags are inadvertently replaced too: - * - * '], ['<?', '?>'], $string); - } - - /* - * 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', - 'jscript', - 'wscript', - 'vbs', - 'script', - 'base64', - 'applet', - 'alert', - 'document', - 'write', - 'cookie', - 'window', - 'confirm', - 'prompt', - 'eval', - ]; - - foreach ($words as $word) { - $word = implode('\s*', str_split($word)) . '\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" - $string = preg_replace_callback( - '#(' . substr($word, 0, -3) . ')(\W)#is', - [self::class, 'compactExplodedWords'], - $string - ); - } - - /* - * Remove disallowed Javascript in links or img tags - * We used to do some version comparisons and use of stripos(), - * but it is dog slow compared to these simplified non-capturing - * preg_match(), especially if the pattern exists in the string - * - * Note: It was reported that not only space characters, but all in - * the following pattern can be parsed as separators between a tag name - * and its attributes: [\d\s"\'`;,\/\=\(\x00\x0B\x09\x0C] - * ... however, remove_invisible_characters() above already strips the - * hex-encoded ones, so we'll skip them below. - */ - do { - $original = $string; - if (preg_match('/]+([^>]*?)(?:>|$)#si', - [self::class, 'jsLinkRemoval'], - $string - ); - } - if (preg_match('/]*?)(?:\s?/?>|$)#si', - [self::class, 'jsImgRemoval'], - $string - ); - } - if (preg_match('/script|xss/i', $string)) { - $string = preg_replace('##si', '[removed]', $string); - } - } while ($original !== $string); - unset($original); - - /* - * 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> - */ - $pattern = '#' - . '<((?/*\s*)(?[a-z0-9]+)(?=[^a-z0-9]|$)' - // tag start and name, followed by a non-tag character - . '[^\s\042\047a-z0-9>/=]*' - // a valid attribute character immediately after the tag would count as a separator - // optional attributes - . '(?(?:[\s\042\047/=]*' - // non-attribute characters, excluding > (tag close) for obvious reasons - . '[^\s\042\047>/=]+' - // attribute characters - // optional attribute-value - . '(?:\s*=' - // attribute-value separator - . '(?:[^\s\042\047=><`]+|\s*\042[^\042]*\042|\s*\047[^\047]*\047|\s*(?U:[^\s\042\047=><`]*))' - // single, double or non-quoted value - . ')?' - // end optional attribute-value group - . ')*)' - // end optional attributes group - . '[^>]*)(?\>)?#isS'; - // Note: It would be nice to optimize this for speed, BUT - // only matching the naughty elements here results in - // false positives and in turn - vulnerabilities! - do { - $oldString = $string; - $string = preg_replace_callback($pattern, [self::class, 'sanitizeNaughtyHTML'], $string); - } while ($oldString !== $string); - - unset($oldString); - - /* - * 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') - */ - $string = preg_replace( - '#(alert|prompt|confirm|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', - '\\1\\2(\\3)', - $string - ); - - // Final clean up - // This adds a bit of extra precaution in case - // something got through the above filters - $string = self::doNeverAllowed($string); - - /* - * 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 ($isImage === true) { - return ($string === $convertedString); - } - - return $string; - } - - /** - * Do Never Allowed - * - * @used-by XSS::clean() - * - * @param string - * - * @return string - */ - protected static function doNeverAllowed($string) - { - $string = str_replace( - array_keys(self::getConfig('never_allowed_strings')), - self::getConfig('never_allowed_strings'), - $string - ); - - foreach (self::getConfig('never_allowed_regex') as $regex) { - $string = preg_replace('#' . $regex . '#is', '[removed]', $string); - } - - return $string; - } - - // -------------------------------------------------------------------------------------- - - protected function getConfig($index) - { - static $config; - - if (empty($config)) { - $config = require('../Config/Xss.php'); - } - - return $config[ $index ]; - } - - // -------------------------------------------------------------------- - - /** - * Compact Exploded Words - * - * Callback method for xss_clean() to remove whitespace from - * things like 'j a v a s c r i p t'. - * - * @used-by XSS::clean() - * - * @param array $matches - * - * @return string - */ - protected static function compactExplodedWords($matches) - { - return preg_replace('/\s+/s', '', $matches[ 1 ]) . $matches[ 2 ]; - } - - // -------------------------------------------------------------------- - - /** - * Sanitize Naughty HTML - * - * Callback method for xss_clean() to remove naughty HTML elements. - * - * @used-by XSS::clean() - * - * @param array $matches - * - * @return string - */ - protected static function sanitizeNaughtyHTML($matches) - { - // First, escape unclosed tags - if (empty($matches[ 'closeTag' ])) { - return '<' . $matches[ 1 ]; - } // Is the element that we caught naughty? If so, escape it - elseif (in_array(strtolower($matches[ 'tagName' ]), self::getConfig('naughty_tags'), true)) { - return '<' . $matches[ 1 ] . '>'; - } // For other tags, see if their attributes are "evil" and strip those - elseif (isset($matches[ 'attributes' ])) { - // We'll store the already fitlered attributes here - $attributes = []; - - // Attribute-catching pattern - $attributesPattern = '#' - . '(?[^\s\042\047>/=]+)' - // attribute characters - // optional attribute-value - . '(?:\s*=(?[^\s\042\047=><`]+|\s*\042[^\042]*\042|\s*\047[^\047]*\047|\s*(?U:[^\s\042\047=><`]*)))' - // attribute-value separator - . '#i'; - - // Blacklist pattern for evil attribute names - $is_evil_pattern = '#^(' . implode('|', self::getConfig('evil_attributes')) . ')$#i'; - - // Each iteration filters a single attribute - do { - // Strip any non-alpha characters that may preceed an attribute. - // Browsers often parse these incorrectly and that has been a - // of numerous XSS issues we've had. - $matches[ 'attributes' ] = preg_replace('#^[^a-z]+#i', '', $matches[ 'attributes' ]); - - if ( ! preg_match($attributesPattern, $matches[ 'attributes' ], $attribute, PREG_OFFSET_CAPTURE)) { - // No (valid) attribute found? Discard everything else inside the tag - break; - } - - if ( - // Is it indeed an "evil" attribute? - preg_match($is_evil_pattern, $attribute[ 'name' ][ 0 ]) - // Or does it have an equals sign, but no value and not quoted? Strip that too! - OR (trim($attribute[ 'value' ][ 0 ]) === '') - ) { - $attributes[] = 'xss=removed'; - } else { - $attributes[] = $attribute[ 0 ][ 0 ]; - } - - $matches[ 'attributes' ] = substr( - $matches[ 'attributes' ], - $attribute[ 0 ][ 1 ] + strlen($attribute[ 0 ][ 0 ]) - ); - } while ($matches[ 'attributes' ] !== ''); - $attributes = empty($attributes) - ? '' - : ' ' . implode(' ', $attributes); - - return '<' . $matches[ 'slash' ] . $matches[ 'tagName' ] . $attributes . '>'; - } - - return $matches[ 0 ]; - } - - // -------------------------------------------------------------------- - - /** - * JS Link Removal - * - * Callback method for xss_clean() to sanitize links. - * - * This limits the PCRE backtracks, making it more performance friendly - * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in - * PHP 5.2+ on link-heavy strings. - * - * @used-by XSS::clean() - * - * @param array $match - * - * @return string - */ - protected static function jsLinkRemoval($match) - { - return str_replace( - $match[ 1 ], - preg_replace( - '#href=.*?(?:(?:alert|prompt|confirm)(?:\(|&\#40;)|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|'], '', $match[ 1 ])) - ), - $match[ 0 ] - ); - } - - // -------------------------------------------------------------------- - - /** - * Filter Attributes - * - * Filters tag attributes for consistency and safety. - * - * @used-by Security::jsImgRemoval() - * @used-by Security::jsLinkRemoval() - * - * @param string $str - * - * @return string - */ - protected static function filterAttributes($str) - { - $out = ''; - if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#is', $str, $matches)) { - foreach ($matches[ 0 ] as $match) { - $out .= preg_replace('#/\*.*?\*/#s', '', $match); - } - } - - return $out; - } - - // -------------------------------------------------------------------- - - /** - * JS Image Removal - * - * Callback method for xss_clean() to sanitize image tags. - * - * This limits the PCRE backtracks, making it more performance friendly - * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in - * PHP 5.2+ on image tag heavy strings. - * - * @used-by XSS::clean() - * - * @param array $match - * - * @return string - */ - protected static function jsImgRemoval($match) - { - return str_replace( - $match[ 1 ], - preg_replace( - '#src=.*?(?:(?:alert|prompt|confirm)(?:\(|&\#40;)|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|'], '', $match[ 1 ])) - ), - $match[ 0 ] - ); - } - - // -------------------------------------------------------------------- - - /** - * Attribute Conversion - * - * @used-by XSS::clean() - * - * @param array $match - * - * @return string - */ - protected static function convertAttribute($match) - { - return str_replace(['>', '<', '\\'], ['>', '<', '\\\\'], $match[ 0 ]); - } - - // ------------------------------------------------------------------------ - - /** - * HTML Entity Decode Callback - * - * @used-by XSS::clean() - * - * @param array $match - * - * @return string - */ - protected static function decodeEntity($match) - { - // Protect GET variables in URLs - // 901119URL5918AMP18930PROTECT8198 - $match = preg_replace('|\&([a-z\_0-9\-]+)\=([a-z\_0-9\-/]+)|i', self::token . '\\1=\\2', $match[ 0 ]); - - $charset = 'UTF-8'; - if (function_exists('config')) { - $charset = config()->getItem('charset'); - } - - // Decode, then un-protect URL GET vars - return str_replace( - self::token, - '&', - self::entityDecode($match, $charset) - ); - } - - // -------------------------------------------------------------------- - - /** - * HTML Entities Decode - * - * A replacement for html_entity_decode() - * - * The reason we are not using html_entity_decode() by itself is because - * while it is not technically correct to leave out the semicolon - * at the end of an entity most browsers will still interpret the entity - * correctly. html_entity_decode() does not convert entities without - * semicolons, so we are left with our own little solution here. Bummer. - * - * @link http://php.net/html-entity-decode - * - * @param string $string Input - * @param string $charset Character set - * - * @return string - */ - protected static function entityDecode($string, $charset = null) - { - if (strpos($string, '&') === false) { - return $string; - } - - static $entities; - - isset($charset) || $charset = 'UTF-8'; - - if (function_exists('config')) { - $charset = config()->getItem('charset'); - } - - $flag = ENT_COMPAT | ENT_HTML5; - - do { - $comparissonString = $string; - - // Decode standard entities, avoiding false positives - if ($c = preg_match_all('/&[a-z]{2,}(?![a-z;])/i', $string, $matches)) { - if ( ! isset($entities)) { - $entities = array_map( - 'strtolower', - get_html_translation_table(HTML_ENTITIES, $flag) - ); - } - - $replace = []; - $matches = array_unique(array_map('strtolower', $matches[ 0 ])); - for ($i = 0; $i < $c; $i++) { - if (($char = array_search($matches[ $i ] . ';', $entities, true)) !== false) { - $replace[ $matches[ $i ] ] = $char; - } - } - - $string = str_ireplace(array_keys($replace), array_values($replace), $string); - } - - // Decode numeric & UTF16 two byte entities - $string = html_entity_decode( - preg_replace('/(&#(?:x0*[0-9a-f]{2,5}(?![0-9a-f;])|(?:0*\d{2,4}(?![0-9;]))))/iS', '$1;', $string), - $flag, - $charset - ); - } while ($comparissonString !== $string); - - return $string; - } - +Google + * + * Note: Use rawurldecode() so it does not remove plus signs + */ + do { + $string = rawurldecode($string); + } while (preg_match('/%[0-9a-f]{2,}/i', $string)); + + /* + * 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. + */ + $string = preg_replace_callback( + "/[^a-z0-9>]+[a-z0-9]+=([\'\"]).*?\\1/si", + [self::class, 'convertAttribute'], + $string + ); + + $string = preg_replace_callback('/<\w+.*/si', [self::class, 'decodeEntity'], $string); + + // Remove Invisible Characters Again! + $string = remove_invisible_characters($string); + + /* + * 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. + */ + $string = str_replace("\t", ' ', $string); + + // Capture converted string for later comparison + $convertedString = $string; + + // Remove Strings that are never allowed + $string = self::doNeverAllowed($string); + + /* + * Makes PHP tags safe + * + * Note: XML tags are inadvertently replaced too: + * + * '], ['<?', '?>'], $string); + } + + /* + * 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', + 'jscript', + 'wscript', + 'vbs', + 'script', + 'base64', + 'applet', + 'alert', + 'document', + 'write', + 'cookie', + 'window', + 'confirm', + 'prompt', + 'eval', + ]; + + foreach ($words as $word) { + $word = implode('\s*', str_split($word)) . '\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" + $string = preg_replace_callback( + '#(' . substr($word, 0, -3) . ')(\W)#is', + [self::class, 'compactExplodedWords'], + $string + ); + } + + /* + * Remove disallowed Javascript in links or img tags + * We used to do some version comparisons and use of stripos(), + * but it is dog slow compared to these simplified non-capturing + * preg_match(), especially if the pattern exists in the string + * + * Note: It was reported that not only space characters, but all in + * the following pattern can be parsed as separators between a tag name + * and its attributes: [\d\s"\'`;,\/\=\(\x00\x0B\x09\x0C] + * ... however, remove_invisible_characters() above already strips the + * hex-encoded ones, so we'll skip them below. + */ + do { + $original = $string; + if (preg_match('/]+([^>]*?)(?:>|$)#si', + [self::class, 'jsLinkRemoval'], + $string + ); + } + if (preg_match('/]*?)(?:\s?/?>|$)#si', + [self::class, 'jsImgRemoval'], + $string + ); + } + if (preg_match('/script|xss/i', $string)) { + $string = preg_replace('##si', '[removed]', $string); + } + } while ($original !== $string); + unset($original); + + /* + * 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> + */ + $pattern = '#' + . '<((?/*\s*)(?[a-z0-9]+)(?=[^a-z0-9]|$)' + // tag start and name, followed by a non-tag character + . '[^\s\042\047a-z0-9>/=]*' + // a valid attribute character immediately after the tag would count as a separator + // optional attributes + . '(?(?:[\s\042\047/=]*' + // non-attribute characters, excluding > (tag close) for obvious reasons + . '[^\s\042\047>/=]+' + // attribute characters + // optional attribute-value + . '(?:\s*=' + // attribute-value separator + . '(?:[^\s\042\047=><`]+|\s*\042[^\042]*\042|\s*\047[^\047]*\047|\s*(?U:[^\s\042\047=><`]*))' + // single, double or non-quoted value + . ')?' + // end optional attribute-value group + . ')*)' + // end optional attributes group + . '[^>]*)(?\>)?#isS'; + // Note: It would be nice to optimize this for speed, BUT + // only matching the naughty elements here results in + // false positives and in turn - vulnerabilities! + do { + $oldString = $string; + $string = preg_replace_callback($pattern, [self::class, 'sanitizeNaughtyHTML'], $string); + } while ($oldString !== $string); + + unset($oldString); + + /* + * 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') + */ + $string = preg_replace( + '#(alert|prompt|confirm|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', + '\\1\\2(\\3)', + $string + ); + + // Final clean up + // This adds a bit of extra precaution in case + // something got through the above filters + $string = self::doNeverAllowed($string); + + /* + * 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 ($isImage === true) { + return ($string === $convertedString); + } + + return $string; + } + + /** + * Do Never Allowed + * + * @used-by XSS::clean() + * + * @param string + * + * @return string + */ + protected static function doNeverAllowed($string) + { + $string = str_replace( + array_keys(self::getConfig('never_allowed_strings')), + self::getConfig('never_allowed_strings'), + $string + ); + + foreach (self::getConfig('never_allowed_regex') as $regex) { + $string = preg_replace('#' . $regex . '#is', '[removed]', $string); + } + + return $string; + } + + // -------------------------------------------------------------------------------------- + + protected function getConfig($index) + { + static $config; + + if (empty($config)) { + $config = require('../Config/Xss.php'); + } + + return $config[ $index ]; + } + + // -------------------------------------------------------------------- + + /** + * Compact Exploded Words + * + * Callback method for xss_clean() to remove whitespace from + * things like 'j a v a s c r i p t'. + * + * @used-by XSS::clean() + * + * @param array $matches + * + * @return string + */ + protected static function compactExplodedWords($matches) + { + return preg_replace('/\s+/s', '', $matches[ 1 ]) . $matches[ 2 ]; + } + + // -------------------------------------------------------------------- + + /** + * Sanitize Naughty HTML + * + * Callback method for xss_clean() to remove naughty HTML elements. + * + * @used-by XSS::clean() + * + * @param array $matches + * + * @return string + */ + protected static function sanitizeNaughtyHTML($matches) + { + // First, escape unclosed tags + if (empty($matches[ 'closeTag' ])) { + return '<' . $matches[ 1 ]; + } // Is the element that we caught naughty? If so, escape it + elseif (in_array(strtolower($matches[ 'tagName' ]), self::getConfig('naughty_tags'), true)) { + return '<' . $matches[ 1 ] . '>'; + } // For other tags, see if their attributes are "evil" and strip those + elseif (isset($matches[ 'attributes' ])) { + // We'll store the already fitlered attributes here + $attributes = []; + + // Attribute-catching pattern + $attributesPattern = '#' + . '(?[^\s\042\047>/=]+)' + // attribute characters + // optional attribute-value + . '(?:\s*=(?[^\s\042\047=><`]+|\s*\042[^\042]*\042|\s*\047[^\047]*\047|\s*(?U:[^\s\042\047=><`]*)))' + // attribute-value separator + . '#i'; + + // Blacklist pattern for evil attribute names + $is_evil_pattern = '#^(' . implode('|', self::getConfig('evil_attributes')) . ')$#i'; + + // Each iteration filters a single attribute + do { + // Strip any non-alpha characters that may preceed an attribute. + // Browsers often parse these incorrectly and that has been a + // of numerous XSS issues we've had. + $matches[ 'attributes' ] = preg_replace('#^[^a-z]+#i', '', $matches[ 'attributes' ]); + + if ( ! preg_match($attributesPattern, $matches[ 'attributes' ], $attribute, PREG_OFFSET_CAPTURE)) { + // No (valid) attribute found? Discard everything else inside the tag + break; + } + + if ( + // Is it indeed an "evil" attribute? + preg_match($is_evil_pattern, $attribute[ 'name' ][ 0 ]) + // Or does it have an equals sign, but no value and not quoted? Strip that too! + OR (trim($attribute[ 'value' ][ 0 ]) === '') + ) { + $attributes[] = 'xss=removed'; + } else { + $attributes[] = $attribute[ 0 ][ 0 ]; + } + + $matches[ 'attributes' ] = substr( + $matches[ 'attributes' ], + $attribute[ 0 ][ 1 ] + strlen($attribute[ 0 ][ 0 ]) + ); + } while ($matches[ 'attributes' ] !== ''); + $attributes = empty($attributes) + ? '' + : ' ' . implode(' ', $attributes); + + return '<' . $matches[ 'slash' ] . $matches[ 'tagName' ] . $attributes . '>'; + } + + return $matches[ 0 ]; + } + + // -------------------------------------------------------------------- + + /** + * JS Link Removal + * + * Callback method for xss_clean() to sanitize links. + * + * This limits the PCRE backtracks, making it more performance friendly + * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in + * PHP 5.2+ on link-heavy strings. + * + * @used-by XSS::clean() + * + * @param array $match + * + * @return string + */ + protected static function jsLinkRemoval($match) + { + return str_replace( + $match[ 1 ], + preg_replace( + '#href=.*?(?:(?:alert|prompt|confirm)(?:\(|&\#40;)|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|'], '', $match[ 1 ])) + ), + $match[ 0 ] + ); + } + + // -------------------------------------------------------------------- + + /** + * Filter Attributes + * + * Filters tag attributes for consistency and safety. + * + * @used-by Security::jsImgRemoval() + * @used-by Security::jsLinkRemoval() + * + * @param string $str + * + * @return string + */ + protected static function filterAttributes($str) + { + $out = ''; + if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#is', $str, $matches)) { + foreach ($matches[ 0 ] as $match) { + $out .= preg_replace('#/\*.*?\*/#s', '', $match); + } + } + + return $out; + } + + // -------------------------------------------------------------------- + + /** + * JS Image Removal + * + * Callback method for xss_clean() to sanitize image tags. + * + * This limits the PCRE backtracks, making it more performance friendly + * and prevents PREG_BACKTRACK_LIMIT_ERROR from being triggered in + * PHP 5.2+ on image tag heavy strings. + * + * @used-by XSS::clean() + * + * @param array $match + * + * @return string + */ + protected static function jsImgRemoval($match) + { + return str_replace( + $match[ 1 ], + preg_replace( + '#src=.*?(?:(?:alert|prompt|confirm)(?:\(|&\#40;)|javascript:|livescript:|mocha:|charset=|window\.|document\.|\.cookie|'], '', $match[ 1 ])) + ), + $match[ 0 ] + ); + } + + // -------------------------------------------------------------------- + + /** + * Attribute Conversion + * + * @used-by XSS::clean() + * + * @param array $match + * + * @return string + */ + protected static function convertAttribute($match) + { + return str_replace(['>', '<', '\\'], ['>', '<', '\\\\'], $match[ 0 ]); + } + + // ------------------------------------------------------------------------ + + /** + * HTML Entity Decode Callback + * + * @used-by XSS::clean() + * + * @param array $match + * + * @return string + */ + protected static function decodeEntity($match) + { + // Protect GET variables in URLs + // 901119URL5918AMP18930PROTECT8198 + $match = preg_replace('|\&([a-z\_0-9\-]+)\=([a-z\_0-9\-/]+)|i', self::token . '\\1=\\2', $match[ 0 ]); + + $charset = 'UTF-8'; + if (function_exists('config')) { + $charset = config()->getItem('charset'); + } + + // Decode, then un-protect URL GET vars + return str_replace( + self::token, + '&', + self::entityDecode($match, $charset) + ); + } + + // -------------------------------------------------------------------- + + /** + * HTML Entities Decode + * + * A replacement for html_entity_decode() + * + * The reason we are not using html_entity_decode() by itself is because + * while it is not technically correct to leave out the semicolon + * at the end of an entity most browsers will still interpret the entity + * correctly. html_entity_decode() does not convert entities without + * semicolons, so we are left with our own little solution here. Bummer. + * + * @link http://php.net/html-entity-decode + * + * @param string $string Input + * @param string $charset Character set + * + * @return string + */ + protected static function entityDecode($string, $charset = null) + { + if (strpos($string, '&') === false) { + return $string; + } + + static $entities; + + isset($charset) || $charset = 'UTF-8'; + + if (function_exists('config')) { + $charset = config()->getItem('charset'); + } + + $flag = ENT_COMPAT | ENT_HTML5; + + do { + $comparissonString = $string; + + // Decode standard entities, avoiding false positives + if ($c = preg_match_all('/&[a-z]{2,}(?![a-z;])/i', $string, $matches)) { + if ( ! isset($entities)) { + $entities = array_map( + 'strtolower', + get_html_translation_table(HTML_ENTITIES, $flag) + ); + } + + $replace = []; + $matches = array_unique(array_map('strtolower', $matches[ 0 ])); + for ($i = 0; $i < $c; $i++) { + if (($char = array_search($matches[ $i ] . ';', $entities, true)) !== false) { + $replace[ $matches[ $i ] ] = $char; + } + } + + $string = str_ireplace(array_keys($replace), array_values($replace), $string); + } + + // Decode numeric & UTF16 two byte entities + $string = html_entity_decode( + preg_replace('/(&#(?:x0*[0-9a-f]{2,5}(?![0-9a-f;])|(?:0*\d{2,4}(?![0-9;]))))/iS', '$1;', $string), + $flag, + $charset + ); + } while ($comparissonString !== $string); + + return $string; + } + } \ No newline at end of file diff --git a/src/Form/Validation.php b/src/Form/Validation.php index 94ee819..5b89986 100644 --- a/src/Form/Validation.php +++ b/src/Form/Validation.php @@ -1,730 +1,730 @@ -= mb_strlen($string)); - } - - // -------------------------------------------------------------------- - - /** - * Validation::isExactLength - * - * Exact Length - * - * @param string - * @param string - * - * @return bool - */ - public static function isExactLength($string, $length) - { - if ( ! is_numeric($length)) { - return false; - } - - return (mb_strlen($string) === (int)$length); - } - - // ------------------------------------------------------------------------ - - /** - * Validation::isDimension - * - * @param $string - * @param string $format - * - * @return bool - */ - public static function isDimension($string, $format = 'W x H x L') - { - $string = strtolower($string); - $string = preg_replace('/\s+/', '', $string); - $x_string = explode('x', $string); - - $format = strtolower($format); - $format = preg_replace('/\s+/', '', $format); - $x_format = explode('x', $format); - - if (count($x_string) == count($x_format)) { - return true; - } - - return false; - } - - // ------------------------------------------------------------------------ - - /** - * Validation::isIpv4 - * - * @param $string - * - * @return mixed - */ - public static function isIpv4($string) - { - return filter_var($string, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4); - } - - // ------------------------------------------------------------------------ - - /** - * Validation::isIpv6 - * - * @param $string - * - * @return mixed - */ - public static function isIpv6($string) - { - return filter_var($string, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6); - } - - // ------------------------------------------------------------------------ - - /** - * Validation::isUrl - * - * @param $string - * - * @return bool|mixed - */ - public static function isUrl($string) - { - if (preg_match('/^(?:([^:]*)\:)?\/\/(.+)$/', $string, $matches)) { - if (empty($matches[ 2 ])) { - return false; - } elseif ( ! in_array($matches[ 1 ], ['http', 'https'], true)) { - return false; - } - - $string = $matches[ 2 ]; - } - - $string = 'http://' . $string; - - return filter_var($string, FILTER_VALIDATE_URL); - } - - // ------------------------------------------------------------------------ - - /** - * Validation::isEmail - * - * @param $string - * - * @return bool - */ - public static function isEmail($string) - { - return (bool)filter_var($string, FILTER_VALIDATE_EMAIL); - } - - // ------------------------------------------------------------------------ - - /** - * Validation::isDomain - * - * @param $string - * - * @return bool - */ - public static function isDomain($string) - { - return (preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $string) //valid chars check - && preg_match("/^.{1,253}$/", $string) //overall length check - && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $string)); //length of each label - } - - // ------------------------------------------------------------------------ - - /** - * Validation::isBool - * - * @param $string - * - * @return bool - */ - public static function isBool($string) - { - return (bool)filter_var($string, FILTER_VALIDATE_BOOLEAN); - } - - // -------------------------------------------------------------------- - - /** - * Validation::isAlpha - * - * @param string $string - * - * @return bool - */ - public static function isAlpha($string) - { - return (bool)ctype_alpha($string); - } - - // ------------------------------------------------------------------------ - - /** - * Validation::isAlphaSpaces - * - * @param string $string - * - * @return bool - */ - public static function isAlphaSpaces($string) - { - return (bool)preg_match('/^[A-Z ]+$/i', $string); - } - - // -------------------------------------------------------------------- - - /** - * Alpha-numeric - * - * @param string $string - * - * @return bool - */ - public static function isAlphaNumeric($string) - { - return (bool)ctype_alnum((string)$string); - } - - // -------------------------------------------------------------------- - - /** - * Validation::isAlphaNumericSpaces - * - * Alpha-numeric w/ spaces - * - * @param string $string - * - * @return bool - */ - public static function isAlphaNumericSpaces($string) - { - return (bool)preg_match('/^[A-Z0-9 ]+$/i', $string); - } - - /** - * Validation::isAlphaDash - * - * Alpha-numeric with underscores and dashes - * - * @param string - * - * @return bool - */ - public static function isAlphaDash($string) - { - return (bool)preg_match('/^[a-z0-9-]+$/i', $string); - } - - // ------------------------------------------------------------------------ - - /** - * Validation::isAlphaUnderscore - * - * Alpha-numeric with underscores and dashes - * - * @param string - * - * @return bool - */ - public static function isAlphaUnderscore($string) - { - return (bool)preg_match('/^[a-z0-9_]+$/i', $string); - } - - // ------------------------------------------------------------------------ - - /** - * Validation::isAlphaUnderscoreDash - * - * Alpha-numeric with underscores and dashes - * - * @param string - * - * @return bool - */ - public static function isAlphaUnderscoreDash($string) - { - return (bool)preg_match('/^[a-z0-9_-]+$/i', $string); - } - - // ------------------------------------------------------------------------ - - /** - * Validation::isNumeric - * - * @param string - * - * @return bool - */ - public static function isNumeric($str) - { - return (bool)preg_match('/^[\-+]?[0-9]*\.?[0-9]+$/', $str); - - } - - // ------------------------------------------------------------------------ - - /** - * Validation::isInteger - * - * @param string - * - * @return bool - */ - public static function isInteger($str) - { - return (bool)preg_match('/^[\-+]?[0-9]+$/', $str); - } - - // ------------------------------------------------------------------------ - - /** - * Validation::isDecimal - * - * Decimal number - * - * @param string - * - * @return bool - */ - public static function isDecimal($string) - { - return (bool)preg_match('/^[\-+]?[0-9]+\.[0-9]+$/', $string); - } - - // ------------------------------------------------------------------------ - - /** - * Validation::isGreater - * - * Greater than - * - * @param string - * @param int - * - * @return bool - */ - public static function isGreater($string, $min) - { - return is_numeric($string) ? ($string > $min) : false; - } - - // ------------------------------------------------------------------------ - - /** - * Validation::isGreaterEqual - * - * Equal to or Greater than - * - * @param string - * @param int - * - * @return bool - */ - public static function isGreaterEqual($string, $min) - { - return (bool)is_numeric($string) ? ($string >= $min) : false; - } - - // -------------------------------------------------------------------- - - /** - * Validation::isLess - * - * Less than - * - * @param string - * @param int - * - * @return bool - */ - public static function isLess($string, $max) - { - return (bool)is_numeric($string) ? ($string < $max) : false; - } - - // -------------------------------------------------------------------- - - /** - * Validation::isLessEqual - * - * Equal to or Less than - * - * @param string - * @param int - * - * @return bool - */ - public static function isLessEqual($string, $max) - { - return (bool)is_numeric($string) ? ($string <= $max) : false; - } - - // -------------------------------------------------------------------- - - /** - * Validation::isListed - * - * Value should be within an array of values - * - * @param string - * @param string - * - * @return bool - */ - public static function isListed($string, $list) - { - if (is_string($list)) { - $list = explode(',', $list); - $list = array_map('trim', $list); - } - - return (bool)in_array($string, $list, true); - } - - // -------------------------------------------------------------------- - - /** - * Validation::isNatural - * - * Is a Natural number (0,1,2,3, etc.) - * - * @param string - * - * @return bool - */ - public static function isNatural($string) - { - return (bool)ctype_digit((string)$string); - } - - // -------------------------------------------------------------------- - - /** - * Validation::isNaturalNoZero - * - * Is a Natural number, but not a zero (1,2,3, etc.) - * - * @param string - * - * @return bool - */ - public static function isNaturalNoZero($string) - { - return (bool)($string != 0 && ctype_digit((string)$string)); - } - - // -------------------------------------------------------------------- - - /** - * Validation::isMd5 - * - * @param $string - * - * @return int - */ - public static function isMd5($string) - { - return preg_match('/^[a-f0-9]{32}$/i', $string); - } - - // -------------------------------------------------------------------- - - /** - * Validation::isMsisdn - * - * @param $string - * @param string $leading - * - * @return bool - */ - public static function isMsisdn($string, $leading = '62') - { - return (bool)preg_match('/^(' . $leading . '[1-9]{1}[0-9]{1,2})[0-9]{6,8}$/', $string); - } - - // -------------------------------------------------------------------- - - /** - * Validation::isDate - * - * @param $string - * @param string $format - * - * @return bool - */ - public static function isDate($string, $format = 'Y-m-d') - { - $dateTime = \DateTime::createFromFormat($format, $string); - - return (bool)$dateTime !== false && ! array_sum($dateTime->getLastErrors()); - } - - // -------------------------------------------------------------------- - - /** - * Validation::isPassword - * - * @param string $string - * @param int $length - * @param string $format - * - * @return bool - */ - public static function isPassword($string, $length = 8, $format = 'uppercase, lowercase, number, special') - { - // Length - if (self::isMinLength($string, $length) === false) { - return false; - } - - $format = strtolower($format); - $format = explode(',', $format); - $format = array_map('trim', $format); - $valid = []; - - foreach ($format as $type) { - switch ($type) { - case 'uppercase': - if (preg_match_all('/[A-Z]/', $string, $uppercase)) { - $valid[ $type ] = count($uppercase[ 0 ]); - } - break; - case 'lowercase': - if (preg_match_all('/[a-z]/', $string, $lowercase)) { - $valid[ $type ] = count($lowercase[ 0 ]); - } - break; - case 'number': - case 'numbers': - if (preg_match_all('/[0-9]/', $string, $numbers)) { - $valid[ $type ] = count($numbers[ 0 ]); - } - break; - case 'special character': - case 'special-character': - case 'special': - // Special Characters - if (preg_match_all('/[!@#$%^&*()\-_=+{};:,<.>]/', $string, $special)) { - $valid[ $type ] = count($special[ 0 ]); - } - break; - } - } - - $diff = array_diff($format, array_keys($valid)); - - return empty($diff) ? true : false; - } - - // -------------------------------------------------------------------- - - /** - * Validation::isMinLength - * - * Minimum Length - * - * @param string - * @param string - * - * @return bool - */ - public static function isMinLength($string, $length) - { - if (isset($string)) { - if ( ! is_numeric($length) or $length == 0) { - return false; - } - - return ($length <= mb_strlen($string)); - } - - return false; - } - - // -------------------------------------------------------------------- - - /** - * Validation::isAscii - * - * Chceks if a string is an v4 or v6 ip address. - * - * @param string $string String to check - * @param string $which ipv4 | ipv6 - * - * @return bool - */ - public static function isValidIp($string, $which = null) - { - switch (strtolower($which)) { - case 'ipv4': - $which = FILTER_FLAG_IPV4; - break; - case 'ipv6': - $which = FILTER_FLAG_IPV6; - break; - default: - $which = null; - break; - } - - return (bool)filter_var($string, FILTER_VALIDATE_IP, $which); - } - - // -------------------------------------------------------------------- - - /** - * Validation::isAscii - * - * Tests if a string is standard 7-bit ASCII or not. - * - * @param string $string String to check - * - * @return bool - */ - public static function isAscii($string) - { - return (bool)(preg_match('/[^\x00-\x7F]/S', $string) === 0); - } - - // -------------------------------------------------------------------- - - /** - * Validation::isBase64 - * - * Tests a string for characters outside of the Base64 alphabet - * as defined by RFC 2045 http://www.faqs.org/rfcs/rfc2045 - * - * @param string - * - * @return bool - */ - public function isBase64($string) - { - return (bool)(base64_encode(base64_decode($string)) === $string); - } += mb_strlen($string)); + } + + // -------------------------------------------------------------------- + + /** + * Validation::isExactLength + * + * Exact Length + * + * @param string + * @param string + * + * @return bool + */ + public static function isExactLength($string, $length) + { + if ( ! is_numeric($length)) { + return false; + } + + return (mb_strlen($string) === (int)$length); + } + + // ------------------------------------------------------------------------ + + /** + * Validation::isDimension + * + * @param $string + * @param string $format + * + * @return bool + */ + public static function isDimension($string, $format = 'W x H x L') + { + $string = strtolower($string); + $string = preg_replace('/\s+/', '', $string); + $x_string = explode('x', $string); + + $format = strtolower($format); + $format = preg_replace('/\s+/', '', $format); + $x_format = explode('x', $format); + + if (count($x_string) == count($x_format)) { + return true; + } + + return false; + } + + // ------------------------------------------------------------------------ + + /** + * Validation::isIpv4 + * + * @param $string + * + * @return mixed + */ + public static function isIpv4($string) + { + return filter_var($string, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4); + } + + // ------------------------------------------------------------------------ + + /** + * Validation::isIpv6 + * + * @param $string + * + * @return mixed + */ + public static function isIpv6($string) + { + return filter_var($string, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6); + } + + // ------------------------------------------------------------------------ + + /** + * Validation::isUrl + * + * @param $string + * + * @return bool|mixed + */ + public static function isUrl($string) + { + if (preg_match('/^(?:([^:]*)\:)?\/\/(.+)$/', $string, $matches)) { + if (empty($matches[ 2 ])) { + return false; + } elseif ( ! in_array($matches[ 1 ], ['http', 'https'], true)) { + return false; + } + + $string = $matches[ 2 ]; + } + + $string = 'http://' . $string; + + return filter_var($string, FILTER_VALIDATE_URL); + } + + // ------------------------------------------------------------------------ + + /** + * Validation::isEmail + * + * @param $string + * + * @return bool + */ + public static function isEmail($string) + { + return (bool)filter_var($string, FILTER_VALIDATE_EMAIL); + } + + // ------------------------------------------------------------------------ + + /** + * Validation::isDomain + * + * @param $string + * + * @return bool + */ + public static function isDomain($string) + { + return (preg_match("/^([a-z\d](-*[a-z\d])*)(\.([a-z\d](-*[a-z\d])*))*$/i", $string) //valid chars check + && preg_match("/^.{1,253}$/", $string) //overall length check + && preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $string)); //length of each label + } + + // ------------------------------------------------------------------------ + + /** + * Validation::isBool + * + * @param $string + * + * @return bool + */ + public static function isBool($string) + { + return (bool)filter_var($string, FILTER_VALIDATE_BOOLEAN); + } + + // -------------------------------------------------------------------- + + /** + * Validation::isAlpha + * + * @param string $string + * + * @return bool + */ + public static function isAlpha($string) + { + return (bool)ctype_alpha($string); + } + + // ------------------------------------------------------------------------ + + /** + * Validation::isAlphaSpaces + * + * @param string $string + * + * @return bool + */ + public static function isAlphaSpaces($string) + { + return (bool)preg_match('/^[A-Z ]+$/i', $string); + } + + // -------------------------------------------------------------------- + + /** + * Alpha-numeric + * + * @param string $string + * + * @return bool + */ + public static function isAlphaNumeric($string) + { + return (bool)ctype_alnum((string)$string); + } + + // -------------------------------------------------------------------- + + /** + * Validation::isAlphaNumericSpaces + * + * Alpha-numeric w/ spaces + * + * @param string $string + * + * @return bool + */ + public static function isAlphaNumericSpaces($string) + { + return (bool)preg_match('/^[A-Z0-9 ]+$/i', $string); + } + + /** + * Validation::isAlphaDash + * + * Alpha-numeric with underscores and dashes + * + * @param string + * + * @return bool + */ + public static function isAlphaDash($string) + { + return (bool)preg_match('/^[a-z0-9-]+$/i', $string); + } + + // ------------------------------------------------------------------------ + + /** + * Validation::isAlphaUnderscore + * + * Alpha-numeric with underscores and dashes + * + * @param string + * + * @return bool + */ + public static function isAlphaUnderscore($string) + { + return (bool)preg_match('/^[a-z0-9_]+$/i', $string); + } + + // ------------------------------------------------------------------------ + + /** + * Validation::isAlphaUnderscoreDash + * + * Alpha-numeric with underscores and dashes + * + * @param string + * + * @return bool + */ + public static function isAlphaUnderscoreDash($string) + { + return (bool)preg_match('/^[a-z0-9_-]+$/i', $string); + } + + // ------------------------------------------------------------------------ + + /** + * Validation::isNumeric + * + * @param string + * + * @return bool + */ + public static function isNumeric($str) + { + return (bool)preg_match('/^[\-+]?[0-9]*\.?[0-9]+$/', $str); + + } + + // ------------------------------------------------------------------------ + + /** + * Validation::isInteger + * + * @param string + * + * @return bool + */ + public static function isInteger($str) + { + return (bool)preg_match('/^[\-+]?[0-9]+$/', $str); + } + + // ------------------------------------------------------------------------ + + /** + * Validation::isDecimal + * + * Decimal number + * + * @param string + * + * @return bool + */ + public static function isDecimal($string) + { + return (bool)preg_match('/^[\-+]?[0-9]+\.[0-9]+$/', $string); + } + + // ------------------------------------------------------------------------ + + /** + * Validation::isGreater + * + * Greater than + * + * @param string + * @param int + * + * @return bool + */ + public static function isGreater($string, $min) + { + return is_numeric($string) ? ($string > $min) : false; + } + + // ------------------------------------------------------------------------ + + /** + * Validation::isGreaterEqual + * + * Equal to or Greater than + * + * @param string + * @param int + * + * @return bool + */ + public static function isGreaterEqual($string, $min) + { + return (bool)is_numeric($string) ? ($string >= $min) : false; + } + + // -------------------------------------------------------------------- + + /** + * Validation::isLess + * + * Less than + * + * @param string + * @param int + * + * @return bool + */ + public static function isLess($string, $max) + { + return (bool)is_numeric($string) ? ($string < $max) : false; + } + + // -------------------------------------------------------------------- + + /** + * Validation::isLessEqual + * + * Equal to or Less than + * + * @param string + * @param int + * + * @return bool + */ + public static function isLessEqual($string, $max) + { + return (bool)is_numeric($string) ? ($string <= $max) : false; + } + + // -------------------------------------------------------------------- + + /** + * Validation::isListed + * + * Value should be within an array of values + * + * @param string + * @param string + * + * @return bool + */ + public static function isListed($string, $list) + { + if (is_string($list)) { + $list = explode(',', $list); + $list = array_map('trim', $list); + } + + return (bool)in_array($string, $list, true); + } + + // -------------------------------------------------------------------- + + /** + * Validation::isNatural + * + * Is a Natural number (0,1,2,3, etc.) + * + * @param string + * + * @return bool + */ + public static function isNatural($string) + { + return (bool)ctype_digit((string)$string); + } + + // -------------------------------------------------------------------- + + /** + * Validation::isNaturalNoZero + * + * Is a Natural number, but not a zero (1,2,3, etc.) + * + * @param string + * + * @return bool + */ + public static function isNaturalNoZero($string) + { + return (bool)($string != 0 && ctype_digit((string)$string)); + } + + // -------------------------------------------------------------------- + + /** + * Validation::isMd5 + * + * @param $string + * + * @return int + */ + public static function isMd5($string) + { + return preg_match('/^[a-f0-9]{32}$/i', $string); + } + + // -------------------------------------------------------------------- + + /** + * Validation::isMsisdn + * + * @param $string + * @param string $leading + * + * @return bool + */ + public static function isMsisdn($string, $leading = '62') + { + return (bool)preg_match('/^(' . $leading . '[1-9]{1}[0-9]{1,2})[0-9]{6,8}$/', $string); + } + + // -------------------------------------------------------------------- + + /** + * Validation::isDate + * + * @param $string + * @param string $format + * + * @return bool + */ + public static function isDate($string, $format = 'Y-m-d') + { + $dateTime = \DateTime::createFromFormat($format, $string); + + return (bool)$dateTime !== false && ! array_sum($dateTime->getLastErrors()); + } + + // -------------------------------------------------------------------- + + /** + * Validation::isPassword + * + * @param string $string + * @param int $length + * @param string $format + * + * @return bool + */ + public static function isPassword($string, $length = 8, $format = 'uppercase, lowercase, number, special') + { + // Length + if (self::isMinLength($string, $length) === false) { + return false; + } + + $format = strtolower($format); + $format = explode(',', $format); + $format = array_map('trim', $format); + $valid = []; + + foreach ($format as $type) { + switch ($type) { + case 'uppercase': + if (preg_match_all('/[A-Z]/', $string, $uppercase)) { + $valid[ $type ] = count($uppercase[ 0 ]); + } + break; + case 'lowercase': + if (preg_match_all('/[a-z]/', $string, $lowercase)) { + $valid[ $type ] = count($lowercase[ 0 ]); + } + break; + case 'number': + case 'numbers': + if (preg_match_all('/[0-9]/', $string, $numbers)) { + $valid[ $type ] = count($numbers[ 0 ]); + } + break; + case 'special character': + case 'special-character': + case 'special': + // Special Characters + if (preg_match_all('/[!@#$%^&*()\-_=+{};:,<.>]/', $string, $special)) { + $valid[ $type ] = count($special[ 0 ]); + } + break; + } + } + + $diff = array_diff($format, array_keys($valid)); + + return empty($diff) ? true : false; + } + + // -------------------------------------------------------------------- + + /** + * Validation::isMinLength + * + * Minimum Length + * + * @param string + * @param string + * + * @return bool + */ + public static function isMinLength($string, $length) + { + if (isset($string)) { + if ( ! is_numeric($length) or $length == 0) { + return false; + } + + return ($length <= mb_strlen($string)); + } + + return false; + } + + // -------------------------------------------------------------------- + + /** + * Validation::isAscii + * + * Chceks if a string is an v4 or v6 ip address. + * + * @param string $string String to check + * @param string $which ipv4 | ipv6 + * + * @return bool + */ + public static function isValidIp($string, $which = null) + { + switch (strtolower($which)) { + case 'ipv4': + $which = FILTER_FLAG_IPV4; + break; + case 'ipv6': + $which = FILTER_FLAG_IPV6; + break; + default: + $which = null; + break; + } + + return (bool)filter_var($string, FILTER_VALIDATE_IP, $which); + } + + // -------------------------------------------------------------------- + + /** + * Validation::isAscii + * + * Tests if a string is standard 7-bit ASCII or not. + * + * @param string $string String to check + * + * @return bool + */ + public static function isAscii($string) + { + return (bool)(preg_match('/[^\x00-\x7F]/S', $string) === 0); + } + + // -------------------------------------------------------------------- + + /** + * Validation::isBase64 + * + * Tests a string for characters outside of the Base64 alphabet + * as defined by RFC 2045 http://www.faqs.org/rfcs/rfc2045 + * + * @param string + * + * @return bool + */ + public function isBase64($string) + { + return (bool)(base64_encode(base64_decode($string)) === $string); + } } \ No newline at end of file diff --git a/src/Protections/Csrf.php b/src/Protections/Csrf.php index 7cbb5c0..bf768f8 100644 --- a/src/Protections/Csrf.php +++ b/src/Protections/Csrf.php @@ -1,101 +1,101 @@ -token = $this->getToken())) { - $this->regenerate(); - } - } - - // ------------------------------------------------------------------------ - - /** - * Csrf::getToken - * - * Gets session CSRF protection token. - * - * @return string|bool Returns FALSE if CSRF protection token is not set. - */ - public function getToken() - { - if (isset($_SESSION[ 'csrfToken' ])) { - return $_SESSION[ 'csrfToken' ]; - } - - return false; - } - - // ------------------------------------------------------------------------ - - /** - * Csrf::regenerate - * - * Regenerate CSRF protection token. - * - * @return void - */ - public function regenerate() - { - $_SESSION[ 'csrfToken' ] = $this->token = 'CSRF-' . bin2hex(random_bytes(32)); - } - - // ------------------------------------------------------------------------ - - /** - * Csrf::verify - * - * Checks if the posted CSRF protection token is valid. - * - * @param string $token - * - * @return bool - */ - public function verify($token = null) - { - $token = isset($token) - ? $token - : input()->postGet('csrf-token'); - - if (is_string($token)) { - return hash_equals($this->getToken(), $token); - } - - return false; - } +token = $this->getToken())) { + $this->regenerate(); + } + } + + // ------------------------------------------------------------------------ + + /** + * Csrf::getToken + * + * Gets session CSRF protection token. + * + * @return string|bool Returns FALSE if CSRF protection token is not set. + */ + public function getToken() + { + if (isset($_SESSION[ 'csrfToken' ])) { + return $_SESSION[ 'csrfToken' ]; + } + + return false; + } + + // ------------------------------------------------------------------------ + + /** + * Csrf::regenerate + * + * Regenerate CSRF protection token. + * + * @return void + */ + public function regenerate() + { + $_SESSION[ 'csrfToken' ] = $this->token = 'CSRF-' . bin2hex(random_bytes(32)); + } + + // ------------------------------------------------------------------------ + + /** + * Csrf::verify + * + * Checks if the posted CSRF protection token is valid. + * + * @param string $token + * + * @return bool + */ + public function verify($token = null) + { + $token = isset($token) + ? $token + : input()->postGet('csrf-token'); + + if (is_string($token)) { + return hash_equals($this->getToken(), $token); + } + + return false; + } } \ No newline at end of file diff --git a/src/Protections/Firewall.php b/src/Protections/Firewall.php index 22bd8e9..1e95cbc 100644 --- a/src/Protections/Firewall.php +++ b/src/Protections/Firewall.php @@ -1,235 +1,235 @@ -ipVersion = $ipVersion; - } - - return $this; - } - - // ------------------------------------------------------------------------ - - /** - * Firewall::setWhitelistIpAddresses - * - * Sets whitelist ip addresses. - * - * @param array $ipAddresses List of whitelist ip addresses. - * - * @return static - */ - public function setWhitelistIpAddresses(array $ipAddresses) - { - foreach ($ipAddresses as $ipAddress) { - if ($this->isValid($ipAddress)) { - $this->whitelistIpAddresses[] = $ipAddress; - } - } - - return $this; - } - - // ------------------------------------------------------------------------ - - /** - * Firewall::isValid - * - * Checks if the ip address is valid. - * - * @param string $ipAddress Ip Address. - * - * @return mixed - */ - protected function isValid($ipAddress) - { - return filter_var($ipAddress, FILTER_FLAG_IPV4); - } - - // ------------------------------------------------------------------------ - - /** - * Firewall::addWhitelistIpAddress - * - * Sets whitelist ip addresses. - * - * @param string $ipAddress Whitelist ip address. - * - * @return static - */ - public function addWhitelistIpAddress($ipAddress) - { - if ($this->isValid($ipAddress)) { - $this->whitelistIpAddresses[] = $ipAddress; - } - - return $this; - } - - // ------------------------------------------------------------------------ - - /** - * Firewall::setBlacklistIpAddresses - * - * Sets whitelist ip addresses. - * - * @param array $ipAddresses List of whitelist ip addresses. - * - * @return static - */ - public function setBlacklistIpAddresses(array $ipAddresses) - { - foreach ($ipAddresses as $ipAddress) { - if ($this->isValid($ipAddress)) { - $this->blacklistIpAddresses[] = $ipAddress; - } - } - - return $this; - } - - // ------------------------------------------------------------------------ - - /** - * Firewall::addBlacklistIpAddress - * - * Sets whitelist ip addresses. - * - * @param string $ipAddress Whitelist ip address. - * - * @return static - */ - public function addBlacklistIpAddress($ipAddress) - { - if ($this->isValid($ipAddress)) { - $this->whitelistIpAddresses[] = $ipAddress; - } - - return $this; - } - - // ------------------------------------------------------------------------ - - /** - * Firewall::verify - * - * @param string $ipAddress - * - * @return bool - */ - public function verify($ipAddress = null) - { - $ipAddress = isset($ipAddress) - ? $ipAddress - : input()->ipAddress(); - - if ($this->isWhitelisted($ipAddress) OR - $this->isBlacklisted($ipAddress) === false - ) { - return true; - } - - return false; - } - - // ------------------------------------------------------------------------ - - /** - * Firewall::isWhitelisted - * - * Checks if the client ip address is whitelisted. - * - * @param string $ipAddress Client ip address. - * - * @return bool - */ - public function isWhitelisted($ipAddress) - { - if ($this->isValid($ipAddress)) { - return (bool)in_array($ipAddress, $this->whitelistIpAddresses); - } - - return false; - } - - // ------------------------------------------------------------------------ - - /** - * Firewall::isBlacklisted - * - * Checks if the client ip address is blacklisted. - * - * @param string $ipAddress Client ip address. - * - * @return bool - */ - public function isBlacklisted($ipAddress) - { - if ($this->isValid($ipAddress)) { - return (bool)in_array($ipAddress, $this->whitelistIpAddresses); - } - - return false; - } +ipVersion = $ipVersion; + } + + return $this; + } + + // ------------------------------------------------------------------------ + + /** + * Firewall::setWhitelistIpAddresses + * + * Sets whitelist ip addresses. + * + * @param array $ipAddresses List of whitelist ip addresses. + * + * @return static + */ + public function setWhitelistIpAddresses(array $ipAddresses) + { + foreach ($ipAddresses as $ipAddress) { + if ($this->isValid($ipAddress)) { + $this->whitelistIpAddresses[] = $ipAddress; + } + } + + return $this; + } + + // ------------------------------------------------------------------------ + + /** + * Firewall::isValid + * + * Checks if the ip address is valid. + * + * @param string $ipAddress Ip Address. + * + * @return mixed + */ + protected function isValid($ipAddress) + { + return filter_var($ipAddress, FILTER_FLAG_IPV4); + } + + // ------------------------------------------------------------------------ + + /** + * Firewall::addWhitelistIpAddress + * + * Sets whitelist ip addresses. + * + * @param string $ipAddress Whitelist ip address. + * + * @return static + */ + public function addWhitelistIpAddress($ipAddress) + { + if ($this->isValid($ipAddress)) { + $this->whitelistIpAddresses[] = $ipAddress; + } + + return $this; + } + + // ------------------------------------------------------------------------ + + /** + * Firewall::setBlacklistIpAddresses + * + * Sets whitelist ip addresses. + * + * @param array $ipAddresses List of whitelist ip addresses. + * + * @return static + */ + public function setBlacklistIpAddresses(array $ipAddresses) + { + foreach ($ipAddresses as $ipAddress) { + if ($this->isValid($ipAddress)) { + $this->blacklistIpAddresses[] = $ipAddress; + } + } + + return $this; + } + + // ------------------------------------------------------------------------ + + /** + * Firewall::addBlacklistIpAddress + * + * Sets whitelist ip addresses. + * + * @param string $ipAddress Whitelist ip address. + * + * @return static + */ + public function addBlacklistIpAddress($ipAddress) + { + if ($this->isValid($ipAddress)) { + $this->whitelistIpAddresses[] = $ipAddress; + } + + return $this; + } + + // ------------------------------------------------------------------------ + + /** + * Firewall::verify + * + * @param string $ipAddress + * + * @return bool + */ + public function verify($ipAddress = null) + { + $ipAddress = isset($ipAddress) + ? $ipAddress + : input()->ipAddress(); + + if ($this->isWhitelisted($ipAddress) OR + $this->isBlacklisted($ipAddress) === false + ) { + return true; + } + + return false; + } + + // ------------------------------------------------------------------------ + + /** + * Firewall::isWhitelisted + * + * Checks if the client ip address is whitelisted. + * + * @param string $ipAddress Client ip address. + * + * @return bool + */ + public function isWhitelisted($ipAddress) + { + if ($this->isValid($ipAddress)) { + return (bool)in_array($ipAddress, $this->whitelistIpAddresses); + } + + return false; + } + + // ------------------------------------------------------------------------ + + /** + * Firewall::isBlacklisted + * + * Checks if the client ip address is blacklisted. + * + * @param string $ipAddress Client ip address. + * + * @return bool + */ + public function isBlacklisted($ipAddress) + { + if ($this->isValid($ipAddress)) { + return (bool)in_array($ipAddress, $this->whitelistIpAddresses); + } + + return false; + } } \ No newline at end of file diff --git a/src/Protections/Xss.php b/src/Protections/Xss.php index bde4202..f62fc2b 100644 --- a/src/Protections/Xss.php +++ b/src/Protections/Xss.php @@ -1,113 +1,113 @@ -token = $this->getToken())) { - $this->regenerate(); - } - } - - // ------------------------------------------------------------------------ - - /** - * Xss::getToken - * - * Gets session XSS protection token. - * - * @return string|bool Returns FALSE if XSS protection token is not set. - */ - public function getToken() - { - if (isset($_SESSION[ 'xssToken' ])) { - return $_SESSION[ 'xssToken' ]; - } - - return false; - } - - // ------------------------------------------------------------------------ - - /** - * Xss::regenerate - * - * Regenerate CSRF protection token. - * - * @return void - */ - public function regenerate() - { - $_SESSION[ 'xssToken' ] = $this->token = 'XSS-' . bin2hex(random_bytes(32)); - } - - // ------------------------------------------------------------------------ - - /** - * Xss::verify - * - * Checks if the posted XSS protection token is valid. - * - * @param string $token - * - * @return bool - */ - public function verify($token = null) - { - $token = isset($token) - ? $token - : input()->postGet('xssToken'); - - if (is_string($token)) { - return hash_equals($this->getToken(), $token); - } - - return false; - } - - // ------------------------------------------------------------------------ - - /** - * Xss::clean - * - * @return mixed - */ - public function clean($string) - { - return \O2System\Security\Filters\Xss::clean($string); - } +token = $this->getToken())) { + $this->regenerate(); + } + } + + // ------------------------------------------------------------------------ + + /** + * Xss::getToken + * + * Gets session XSS protection token. + * + * @return string|bool Returns FALSE if XSS protection token is not set. + */ + public function getToken() + { + if (isset($_SESSION[ 'xssToken' ])) { + return $_SESSION[ 'xssToken' ]; + } + + return false; + } + + // ------------------------------------------------------------------------ + + /** + * Xss::regenerate + * + * Regenerate CSRF protection token. + * + * @return void + */ + public function regenerate() + { + $_SESSION[ 'xssToken' ] = $this->token = 'XSS-' . bin2hex(random_bytes(32)); + } + + // ------------------------------------------------------------------------ + + /** + * Xss::verify + * + * Checks if the posted XSS protection token is valid. + * + * @param string $token + * + * @return bool + */ + public function verify($token = null) + { + $token = isset($token) + ? $token + : input()->postGet('xssToken'); + + if (is_string($token)) { + return hash_equals($this->getToken(), $token); + } + + return false; + } + + // ------------------------------------------------------------------------ + + /** + * Xss::clean + * + * @return mixed + */ + public function clean($string) + { + return \O2System\Security\Filters\Xss::clean($string); + } } \ No newline at end of file diff --git a/src/autoload.php b/src/autoload.php index 69b31a1..a2ae83f 100644 --- a/src/autoload.php +++ b/src/autoload.php @@ -1,46 +1,46 @@ -