diff --git a/README.md b/README.md index 1de2310..d8c8aaf 100644 --- a/README.md +++ b/README.md @@ -288,6 +288,8 @@ use function ezsql\functions\{ /// to_string, clean_string, + is_traversal, + sanitize_path, create_certificate, /// column, diff --git a/lib/Constants.php b/lib/Constants.php index 959f1e4..789a63e 100644 --- a/lib/Constants.php +++ b/lib/Constants.php @@ -5,7 +5,7 @@ /** * ezsqlModel Constants */ - \defined('EZSQL_VERSION') or \define('EZSQL_VERSION', '5.1.0'); + \defined('EZSQL_VERSION') or \define('EZSQL_VERSION', '5.1.1'); \defined('OBJECT') or \define('OBJECT', 'OBJECT'); \defined('ARRAY_A') or \define('ARRAY_A', 'ARRAY_A'); \defined('ARRAY_N') or \define('ARRAY_N', 'ARRAY_N'); diff --git a/lib/ezFunctions.php b/lib/ezFunctions.php index 56c2d7f..4a10aaf 100644 --- a/lib/ezFunctions.php +++ b/lib/ezFunctions.php @@ -215,40 +215,6 @@ function changingColumn(string $columnName, ...$datatype) return column(\CHANGER, $columnName, ...$datatype); } - /** - * Creates self signed certificate - * - * @param string $privatekeyFile - * @param string $certificateFile - * @param string $signingFile - * // param string $caCertificate - * @param string $ssl_path - * @param array $details - certificate details - * - * Example: - * array $details = [ - * "countryName" => '', - * "stateOrProvinceName" => '', - * "localityName" => '', - * "organizationName" => '', - * "organizationalUnitName" => '', - * "commonName" => '', - * "emailAddress" => '' - * ]; - * - * @return string certificate path - */ - function create_certificate( - string $privatekeyFile = 'certificate.key', - string $certificateFile = 'certificate.crt', - string $signingFile = 'certificate.csr', - // string $caCertificate = null, - string $ssl_path = null, - array $details = ["commonName" => "localhost"] - ) { - return ezQuery::createCertificate($privatekeyFile, $certificateFile, $signingFile, $ssl_path, $details); - } - /** * Creates an equality comparison expression with the given arguments. * @@ -600,7 +566,119 @@ function clearInstance() */ function clean_string(string $string) { - return ezQuery::clean($string); + $patterns = array( // strip out: + '@]*?>.*?@si', // Strip out javascript + '@<[\/\!]*?[^<>]*?>@si', // HTML tags + '@]*?>.*?@siU', // Strip style tags properly + '@@' // Strip multi-line comments + ); + + $string = \preg_replace($patterns, '', $string); + $string = \trim($string); + $string = \stripslashes($string); + + return \htmlentities($string); + } + + /** + * Check if path/filename is directory traversal attack. + * + * @param string $basePath base directory to check against + * @param string $filename will be preprocess with `sanitize_path()` + * @return boolean + */ + function is_traversal(string $basePath, string $filename) + { + if (\strpos(\urldecode($filename), '..') !== false) + return true; + + $realBase = \rtrim(\realpath($basePath), _DS); + $userPath = $realBase . _DS . sanitize_path($filename); + $realUserPath = \realpath($userPath); + // Reassign with un-sanitized if file does not exits + if ($realUserPath === false) + $realUserPath = $filename; + + return (\strpos($realUserPath, $realBase) !== 0); + } + + /** + * Sanitize path to prevent directory traversal. + * + * Example: + * + * `sanitize_path("../../../../config.php");` + * + * Returns `config.php` without the path traversal + * @param string $path + * @return string + */ + function sanitize_path(string $path) + { + $file = \preg_replace("/\.[\.]+/", "", $path); + $file = \preg_replace("/^[\/]+/", "", $file); + $file = \preg_replace("/^[A-Za-z][:\|][\/]?/", "", $file); + return ($file); + } + + /** + * Creates self signed certificate + * + * @param string $privatekeyFile + * @param string $certificateFile + * @param string $signingFile + * // param string $caCertificate + * @param string $ssl_path + * @param array $details - certificate details + * + * Example: + * array $details = [ + * "countryName" => '', + * "stateOrProvinceName" => '', + * "localityName" => '', + * "organizationName" => '', + * "organizationalUnitName" => '', + * "commonName" => '', + * "emailAddress" => '' + * ]; + * + * @return string certificate path + */ + function create_certificate( + string $privatekeyFile = 'certificate.key', + string $certificateFile = 'certificate.crt', + string $signingFile = 'certificate.csr', + // string $caCertificate = null, + string $ssl_path = null, + array $details = ["commonName" => "localhost"] + ) { + if (empty($ssl_path)) { + $ssl_path = \getcwd(); + $ssl_path = \preg_replace('/\\\/', \_DS, $ssl_path) . \_DS; + } else + $ssl_path = $ssl_path . \_DS; + + $opensslConfig = array("config" => $ssl_path . 'openssl.cnf'); + + // Generate a new private (and public) key pair + $privatekey = \openssl_pkey_new($opensslConfig); + + // Generate a certificate signing request + $csr = \openssl_csr_new($details, $privatekey, $opensslConfig); + + // Create a self-signed certificate valid for 365 days + $sslcert = \openssl_csr_sign($csr, null, $privatekey, 365, $opensslConfig); + + // Create key file. Note no passphrase + \openssl_pkey_export_to_file($privatekey, $ssl_path . $privatekeyFile, null, $opensslConfig); + + // Create server certificate + \openssl_x509_export_to_file($sslcert, $ssl_path . $certificateFile, false); + + // Create a signing request file + \openssl_csr_export_to_file($csr, $ssl_path . $signingFile); + + return $ssl_path; } /** diff --git a/lib/ezQuery.php b/lib/ezQuery.php index 51bba4b..cbc413c 100644 --- a/lib/ezQuery.php +++ b/lib/ezQuery.php @@ -44,82 +44,6 @@ public function __construct() { } - public static function clean($string) - { - $patterns = array( // strip out: - '@]*?>.*?@si', // Strip out javascript - '@<[\/\!]*?[^<>]*?>@si', // HTML tags - '@]*?>.*?@siU', // Strip style tags properly - '@@' // Strip multi-line comments - ); - - $string = \preg_replace($patterns, '', $string); - $string = \trim($string); - $string = \stripslashes($string); - - return \htmlentities($string); - } - - /** - * Creates self signed certificate - * - * @param string $privatekeyFile - * @param string $certificateFile - * @param string $signingFile - * // param string $caCertificate - * @param string $ssl_path - * @param array $details - certificate details - * - * Example: - * array $details = [ - * "countryName" => '', - * "stateOrProvinceName" => '', - * "localityName" => '', - * "organizationName" => '', - * "organizationalUnitName" => '', - * "commonName" => '', - * "emailAddress" => '' - * ]; - * - * @return string certificate path - */ - public static function createCertificate( - string $privatekeyFile = 'certificate.key', - string $certificateFile = 'certificate.crt', - string $signingFile = 'certificate.csr', - // string $caCertificate = null, - string $ssl_path = null, - array $details = ["commonName" => "localhost"] - ) { - if (empty($ssl_path)) { - $ssl_path = \getcwd(); - $ssl_path = \preg_replace('/\\\/', \_DS, $ssl_path) . \_DS; - } else - $ssl_path = $ssl_path . \_DS; - - $opensslConfig = array("config" => $ssl_path . 'openssl.cnf'); - - // Generate a new private (and public) key pair - $privatekey = \openssl_pkey_new($opensslConfig); - - // Generate a certificate signing request - $csr = \openssl_csr_new($details, $privatekey, $opensslConfig); - - // Create a self-signed certificate valid for 365 days - $sslcert = \openssl_csr_sign($csr, null, $privatekey, 365, $opensslConfig); - - // Create key file. Note no passphrase - \openssl_pkey_export_to_file($privatekey, $ssl_path . $privatekeyFile, null, $opensslConfig); - - // Create server certificate - \openssl_x509_export_to_file($sslcert, $ssl_path . $certificateFile, false); - - // Create a signing request file - \openssl_csr_export_to_file($csr, $ssl_path . $signingFile); - - return $ssl_path; - } - /** * Return status of prepare function availability in shortcut method calls */ diff --git a/lib/ezQueryInterface.php b/lib/ezQueryInterface.php index 37abdba..2fc422a 100644 --- a/lib/ezQueryInterface.php +++ b/lib/ezQueryInterface.php @@ -29,13 +29,6 @@ */ interface ezQueryInterface { - /** - * Clean input of XSS, html, javascript, etc... - * @param string $string - * @return string cleaned string - */ - public static function clean($string); - /** * Turn on prepare function availability in ezQuery shortcut method calls */ diff --git a/tests/ezFunctionsTest.php b/tests/ezFunctionsTest.php index 32c3b27..a8c374a 100644 --- a/tests/ezFunctionsTest.php +++ b/tests/ezFunctionsTest.php @@ -50,7 +50,10 @@ get_results, table_setup, set_table, - set_prefix + set_prefix, + clean_string, + is_traversal, + sanitize_path }; class ezFunctionsTest extends EZTestCase @@ -60,6 +63,23 @@ protected function setUp(): void clearInstance(); } + public function testClean_string() + { + $this->assertEquals("' help", clean_string("' help")); + } + + public function testSanitize_path() + { + $this->assertEquals("config.php", sanitize_path("../../../../config.php")); + } + + public function testis_traversal() + { + $this->assertEquals(true, is_traversal('/home', "../../../../config.php")); + $this->assertEquals(true, is_traversal(__DIR__, dirname(__DIR__), 8)); + $this->assertEquals(false, is_traversal(__DIR__, 'Foo.php')); + } + public function testGetInstance() { $this->assertNull(getInstance()); diff --git a/tests/ezQueryTest.php b/tests/ezQueryTest.php index b79833c..c23db97 100644 --- a/tests/ezQueryTest.php +++ b/tests/ezQueryTest.php @@ -9,8 +9,7 @@ eq, neq, like, - in, - clean_string + in }; class ezQueryTest extends EZTestCase @@ -27,11 +26,6 @@ protected function tearDown(): void $this->object = null; } - public function testClean_string() - { - $this->assertEquals("' help", clean_string("' help")); - } - public function testHaving() { $this->assertFalse($this->object->having(''));