diff --git a/PhpSecInfo/PhpSecInfo.php b/PhpSecInfo/PhpSecInfo.php index e12a057..0e9bbc7 100644 --- a/PhpSecInfo/PhpSecInfo.php +++ b/PhpSecInfo/PhpSecInfo.php @@ -198,7 +198,7 @@ function PhpSecInfo($opts = null) { if (isset($opts['format'])) { $this->setFormat($opts['format']); } else { - if (strtolower(php_sapi_name()) == 'cli' ) { + if (!strcasecmp(PHP_SAPI, 'cli')) { $this->setFormat('Cli'); } else { $this->setFormat(PHPSECINFO_FORMAT_DEFAULT); @@ -207,7 +207,7 @@ function PhpSecInfo($opts = null) { } else { /* Use defaults */ $this->setViewDirectory(dirname(__FILE__).DIRECTORY_SEPARATOR . PHPSECINFO_VIEW_DIR_DEFAULT); - if (strtolower(php_sapi_name()) == 'cli' ) { + if (!strcasecmp(PHP_SAPI, 'cli')) { $this->setFormat('Cli'); } else { $this->setFormat(PHPSECINFO_FORMAT_DEFAULT); @@ -228,7 +228,7 @@ function loadTests() { //echo "
"; echo print_r($test_root, true); echo "
"; while (false !== ($entry = $test_root->read())) { - if ( is_dir($test_root->path.DIRECTORY_SEPARATOR.$entry) && !preg_match('|^\.(.*)$|', $entry) ) { + if ( is_dir($test_root->path.DIRECTORY_SEPARATOR.$entry) && !preg_match('~^(\.|_vti)(.*)$~', $entry) ) { $test_dirs[] = $entry; } } diff --git a/PhpSecInfo/Test/CGI/force_redirect.php b/PhpSecInfo/Test/CGI/force_redirect.php index 9822cbf..d84d709 100644 --- a/PhpSecInfo/Test/CGI/force_redirect.php +++ b/PhpSecInfo/Test/CGI/force_redirect.php @@ -41,16 +41,41 @@ function _retrieveCurrentValue() { } + + private function skipTest() { + if (strpos(PHP_SAPI, 'cgi') === false) { + return PHP_SAPI . ' SAPI for php'; + } + + // these web servers require cgi.force_redirect = 0 + $webServers = array('Microsoft-IIS', 'OmniHTTPd', 'Xitami'); + if (isset($_SERVER['SERVER_SOFTWARE'])) { + foreach ($webServers as $webServer) { + if (strpos($_SERVER['SERVER_SOFTWARE'], $webServer) === 0) { + return $_SERVER['SERVER_SOFTWARE']; + } + } + } + + return false; + } + + + /** * Checks to see if cgi.force_redirect is enabled * */ function _execTest() { - if ($this->current_value == $this->recommended_value) { return PHPSECINFO_TEST_RESULT_OK; } + if ($this->skipTest()) + { + return PHPSECINFO_TEST_RESULT_NOTICE; + } + return PHPSECINFO_TEST_RESULT_WARN; } @@ -64,8 +89,13 @@ function _setMessages() { parent::_setMessages(); $this->setMessageForResult(PHPSECINFO_TEST_RESULT_OK, 'en', "force_redirect is enabled, which is the recommended setting"); - $this->setMessageForResult(PHPSECINFO_TEST_RESULT_WARN, 'en', "force_redirect is disabled. In most cases, this is a serious security vulnerability. Unless you are absolutely sure this is not needed, enable this setting"); - + $ini = ini_get_all(); + if (isset($ini['cgi.force_redirect'])) { + $this->setMessageForResult(PHPSECINFO_TEST_RESULT_NOTICE, 'en', "force_redirect is disabled. In most cases, this is a security vulnerability, but it appears this is not needed because you are running " . $this->skipTest()); + $this->setMessageForResult(PHPSECINFO_TEST_RESULT_WARN, 'en', "force_redirect is disabled. In most cases, this is a serious security vulnerability. Unless you are absolutely sure this is not needed, enable this setting"); + } else { + $this->setMessageForResult(PHPSECINFO_TEST_RESULT_NOTICE, 'en', "force_redirect is disabled because php was not compiled with --enable-force-cgi-redirect. In most cases, this is a security vulnerability, but it appears this is not needed because you are running " . $this->skipTest()); + $this->setMessageForResult(PHPSECINFO_TEST_RESULT_WARN, 'en', "force_redirect is disabled because php was not compiled with --enable-force-cgi-redirect. In most cases, this is a serious security vulnerability. Unless you are absolutely sure this is not needed, recompile php with --enable-force-cgi-redirect and enable cgi.force_redirect"); + } } - -} \ No newline at end of file +} diff --git a/PhpSecInfo/Test/Core/allow_url_include.php b/PhpSecInfo/Test/Core/allow_url_include.php index 59bedca..c9bea4d 100644 --- a/PhpSecInfo/Test/Core/allow_url_include.php +++ b/PhpSecInfo/Test/Core/allow_url_include.php @@ -56,12 +56,7 @@ function _execTest() { * @return boolean */ function isTestable() { - - if ( version_compare(PHP_VERSION, '5.2', '<') ) { - return false; - } else { - return true; - } + return version_compare(PHP_VERSION, '5.2', '>='); } diff --git a/PhpSecInfo/Test/Core/upload_tmp_dir.php b/PhpSecInfo/Test/Core/upload_tmp_dir.php index 729c702..e0b173d 100644 --- a/PhpSecInfo/Test/Core/upload_tmp_dir.php +++ b/PhpSecInfo/Test/Core/upload_tmp_dir.php @@ -64,9 +64,10 @@ function isTestable() { */ function _execTest() { - $perms = fileperms($this->current_value); - - if ($this->current_value + $perms = @fileperms($this->current_value); + if ($perms === false) { + return PHPSECINFO_TEST_RESULT_WARN; + } else if ($this->current_value && !preg_match("|".PHPSECINFO_TEST_COMMON_TMPDIR."/?|", $this->current_value) && ! ($perms & 0x0004) && ! ($perms & 0x0002) ) { @@ -79,7 +80,6 @@ function _execTest() { return PHPSECINFO_TEST_RESULT_NOTICE; } - /** * Set the messages specific to this test * @@ -90,6 +90,7 @@ function _setMessages() { $this->setMessageForResult(PHPSECINFO_TEST_RESULT_NOTRUN, 'en', 'Test not run -- currently disabled on Windows OSes'); $this->setMessageForResult(PHPSECINFO_TEST_RESULT_OK, 'en', 'upload_tmp_dir is enabled, which is the recommended setting. Make sure your upload_tmp_dir path is not world-readable'); + $this->setMessageForResult(PHPSECINFO_TEST_RESULT_WARN, 'en', 'unable to retrieve file permissions on upload_tmp_dir'); $this->setMessageForResult(PHPSECINFO_TEST_RESULT_NOTICE, 'en', 'upload_tmp_dir is disabled, or is set to a common world-writable directory. This typically allows other users on this server to access temporary copies of files uploaded via your PHP scripts. You should set diff --git a/PhpSecInfo/Test/Session/save_path.php b/PhpSecInfo/Test/Session/save_path.php index 904a6a1..910e5c7 100644 --- a/PhpSecInfo/Test/Session/save_path.php +++ b/PhpSecInfo/Test/Session/save_path.php @@ -39,6 +39,9 @@ function _retrieveCurrentValue() { } } + if( preg_match('/^[0-9]+;(.+)/', $this->current_value, $matches) ) { + $this->current_value = $matches[1]; + } } @@ -67,9 +70,10 @@ function isTestable() { */ function _execTest() { - $perms = fileperms($this->current_value); - - if ($this->current_value + $perms = @fileperms($this->current_value); + if ($perms === false) { + return PHPSECINFO_TEST_RESULT_WARN; + } else if ($this->current_value && !preg_match("|".PHPSECINFO_TEST_COMMON_TMPDIR."/?|", $this->current_value) && ! ($perms & 0x0004) && ! ($perms & 0x0002) ) { @@ -92,6 +96,7 @@ function _setMessages() { $this->setMessageForResult(PHPSECINFO_TEST_RESULT_NOTRUN, 'en', 'Test not run -- currently disabled on Windows OSes'); $this->setMessageForResult(PHPSECINFO_TEST_RESULT_OK, 'en', 'save_path is enabled, which is the recommended setting. Make sure your save_path path is not world-readable'); + $this->setMessageForResult(PHPSECINFO_TEST_RESULT_WARN, 'en', 'unable to retrieve file permissions on save_path'); $this->setMessageForResult(PHPSECINFO_TEST_RESULT_NOTICE, 'en', 'save_path is disabled, or is set to a common world-writable directory. This typically allows other users on this server to access session files. You should set save_path to a non-world-readable directory'); diff --git a/PhpSecInfo/Test/Suhosin/extension.php b/PhpSecInfo/Test/Suhosin/extension.php new file mode 100644 index 0000000..50e4d05 --- /dev/null +++ b/PhpSecInfo/Test/Suhosin/extension.php @@ -0,0 +1,46 @@ +current_value = extension_loaded('suhosin'); + } + + function _execTest() { + if ( $this->current_value === true ) { + return PHPSECINFO_TEST_RESULT_OK; + } else { + return PHPSECINFO_TEST_RESULT_NOTICE; + } + } + + function _setMessages() { + parent::_setMessages(); + + $this->setMessageForResult(PHPSECINFO_TEST_RESULT_OK, 'en', "You are running PHP with the Suhosin extension loaded. This extension provides high-level runtime protections, and additional filtering and logging features."); + $this->setMessageForResult(PHPSECINFO_TEST_RESULT_NOTICE, 'en', "You are not running PHP with the Suhosin extension loaded. We recommend both the patch and extension for low- and high-level protections including transparent cookie encryption and remote inclusion vulnerabilities."); + } +} diff --git a/PhpSecInfo/Test/Suhosin/patch.php b/PhpSecInfo/Test/Suhosin/patch.php new file mode 100644 index 0000000..6e982ed --- /dev/null +++ b/PhpSecInfo/Test/Suhosin/patch.php @@ -0,0 +1,55 @@ +current_value = true; + } else { + $this->current_value = false; + + $constants = get_defined_constants(); + if(isset($constants['SUHOSIN_PATCH']) && $constants['SUHOSIN_PATCH'] == 1) { + $this->current_value = true; + } + } + } + + function _execTest() { + if ( $this->current_value === true ) { + return PHPSECINFO_TEST_RESULT_OK; + } else { + return PHPSECINFO_TEST_RESULT_NOTICE; + } + } + + function _setMessages() { + parent::_setMessages(); + + $this->setMessageForResult(PHPSECINFO_TEST_RESULT_OK, 'en', "You are running PHP with the Suhosin patch applied against the PHP core. This patch implements various low-level protections against (for example) buffer overflows and format string vulnerabilities."); + $this->setMessageForResult(PHPSECINFO_TEST_RESULT_NOTICE, 'en', "You are not running PHP with the Suhosin patch applied. We recommend both the patch and extension for low- and high-level protections against (for example) buffer overflows and format string vulnerabilities."); + } +} diff --git a/PhpSecInfo/Test/Test.php b/PhpSecInfo/Test/Test.php index 5b577df..b4902a7 100644 --- a/PhpSecInfo/Test/Test.php +++ b/PhpSecInfo/Test/Test.php @@ -463,15 +463,14 @@ function getBooleanIniValue($ini_key) { */ function sys_get_temp_dir() { // Try to get from environment variable - if ( !empty($_ENV['TMP']) ) { - return realpath( $_ENV['TMP'] ); - } else if ( !empty($_ENV['TMPDIR']) ) { - return realpath( $_ENV['TMPDIR'] ); - } else if ( !empty($_ENV['TEMP']) ) { - return realpath( $_ENV['TEMP'] ); - } else { - return NULL; + $vars = array('TMP', 'TMPDIR', 'TEMP'); + foreach($vars as $var) { + $tmp = getenv($var); + if ( !empty($tmp) ) { + return realpath( $tmp ); + } } + return NULL; } @@ -530,16 +529,20 @@ function getUnixId() { 'gid'=>$matches[3], 'group'=>$matches[4] ); + $groups = array(); if ($matches[5]) { $gs = $matches[5]; $gs = explode(',', $gs); foreach ($gs as $groupstr) { - preg_match("/(\d+)\(([^\)]+)\)/", $groupstr, $subs); - $groups[$subs[1]] = $subs[2]; + if (preg_match("/(\d+)\(([^\)]+)\)/", $groupstr, $subs)) { + $groups[$subs[1]] = $subs[2]; + } else { + $groups[$groupstr] = ''; + } } ksort($groups); - $id_data['groups'] = $groups; } + $id_data['groups'] = $groups; $success = true; } @@ -553,6 +556,7 @@ function getUnixId() { $id_data['gid'] = $data['gid']; //$group_data = posix_getgrgid( posix_getegid() ); //$id_data['group'] = $group_data['name']; + $id_data['groups'] = array(); $groups = posix_getgroups(); foreach ( $groups as $gid ) { //$group_data = posix_getgrgid(posix_getgid()); diff --git a/PhpSecInfo/Test/Test_Cgi.php b/PhpSecInfo/Test/Test_Cgi.php index 6843a59..1a4156a 100644 --- a/PhpSecInfo/Test/Test_Cgi.php +++ b/PhpSecInfo/Test/Test_Cgi.php @@ -38,12 +38,12 @@ class PhpSecInfo_Test_Cgi extends PhpSecInfo_Test * @return boolean */ function isTestable() { - /*if ( preg_match('/^cgi.*$/', php_sapi_name()) ) { + /*if ( preg_match('/^cgi.*$/', PHP_SAPI) ) { return true; } else { return false; }*/ - return strpos(php_sapi_name(), 'cgi') === 0; + return !strncmp(PHP_SAPI, 'cgi', 3); } diff --git a/PhpSecInfo/Test/Test_Suhosin.php b/PhpSecInfo/Test/Test_Suhosin.php new file mode 100644 index 0000000..c9a9b3a --- /dev/null +++ b/PhpSecInfo/Test/Test_Suhosin.php @@ -0,0 +1,50 @@ +getTestName()) { + return 'http://www.hardened-php.net/suhosin/index.html'; + } else { + return false; + } + } +}