php.ini scanner

October 2017

Introduction

PHP-based web applications are still very popular and widely used in many organization. Once you have decided to install new application, the administrator must deploy new server or environment to be used. During this process basic (default) options are usually set, in order to achieve as soon as possible “OK, it works” state (which often not equals to it’s secure state).

Sometimes an administrator google for ‘php server tutorial’ and copy-paste provided commands. That’s security risk!

In this article we would like to present you iniscan tool - a php.ini scanner for best security practices. It’s designed to scan the given php.ini file for common security practices and report back results (console, html, xml, json). Let’s prepare test environment. It should not take much time thanks to docker and composer:

$ docker run –-rm -it php:5.6 bash
# apt-get update && apt-get install -y zip git ## install composer prerequisites
# curl --silent --show-error https://getcomposer.org/installer | php ## install composer
# php composer.phar require psecio/iniscan ## install iniscan package

Usage

Let’s go for default php.ini of PHP 5.6:

== Executing INI Scan [10.27.2017 12:36:28] ==

Results for /usr/local/etc/php/php.ini:
============
Status | Severity | PHP Version | Current Value | Key                           | Description
------------------------------------------------------------------------------------------
PASS   | ERROR    |             | 1             | session.use_cookies           | Accepts cookies to manage sessions
PASS   | ERROR    | 4.3.0       | 1             | session.use_only_cookies      | Must use cookies to manage sessions, don't accept session-ids in a link
FAIL   | WARNING  |             |               | session.cookie_domain         | It is recommended that you set the default domain for cookies.
FAIL   | ERROR    | 5.2.0       | 1             | session.cookie_httponly       | Setting session cookies to 'http only' makes them only readable by the browser
PASS   | ERROR    | 4.3.0       | 0             | session.bug_compat_42         | An undocumented feature/bug that allows initialize of a session in the global scope even if register_globals is disabled for PHP up to 5.3.22
PASS   | WARNING  | 4.3.0       | 0             | session.bug_compat_warn       | Disable warnings for session.bug_compat_42
FAIL   | WARNING  |             |               | session.hash_function         | Weak hashing algorithms in use. Rather use one of these: sha224, sha256, sha384, sha512, ripemd128, ripemd160, ripemd256, ripemd320, whirlpool, tiger128,3, tiger160,3, tiger192,3, tiger128,4, tiger160,4, tiger192,4, snefru256, gost-crypto, adler32, crc32, crc32b, fnv132, fnv1a32, fnv164, fnv1a64, joaat, haval128,3, haval160,3, haval192,3, haval224,3, haval256,3, haval128,4, haval160,4, haval192,4, haval224,4, haval256,4, haval128,5, haval160,5, haval192,5, haval224,5, haval256,5
PASS   | WARNING  |             |               | session.save_path             | Session save path should be set and writeable by only the web user
PASS   | ERROR    | 4.0.3       | 0             | session.use_trans_sid         | If used 'use_trans_sid' setting puts the session ID on the URL, making it easier to hijack
FAIL   | ERROR    | 4.0.4       | 1             | session.cookie_secure         | Cookie secure specifies whether cookies should only be sent over secure connections.
PASS   | WARNING  |             |               | session.entropy_file          | A file should be provided to help provide session entropy
FAIL   | WARNING  | 5.5.2       | 1             | session.use_strict_mode       | Strict mode prevents uninitialized session IDs in the built-in session handling.
N/A    | WARNING  | 7.0.0       | 1             | session.lazy_write            | Lazy session writes only when the session data has been modified. This should be enabled to prevent potential information exposure.
FAIL   | INFO     |             | PHPSESSID     | session.name                  | Renaming the session cookie to something other than the default can make it more difficult to detect if a user's cookies are hijacked
FAIL   | ERROR    | 4.0.3       | 0             | allow_url_fopen               | Do not allow the opening of remote file resources ('Off' recommended)
PASS   | ERROR    | 5.2.0       | 0             | allow_url_include             | Do not allow the inclusion of remote file resources ('Off' recommended)
FAIL   | WARNING  |             | 0             | display_errors                | Don't show errors in production ('Off' recommended)
FAIL   | WARNING  |             | 1             | log_errors                    | Log errors in production ('On' recommended)
FAIL   | WARNING  |             | 1             | expose_php                    | Showing the PHP signature exposes additional information
PASS   | ERROR    |             | 1             | register_globals              | The register globals setting is dangerous and has been deprecated ('Off' recommended)
PASS   | ERROR    |             | 0             | magic_quotes_gpc              | Magic quotes automatically adds quotes to incoming data ('Off' recommended)
PASS   | ERROR    |             | 0             | magic_quotes_runtime          | Magic quotes should be disabled at runtime in addition to being off for incoming data
PASS   | WARNING  |             |               | post_max_size                 | A too large value for the maximum post size could allow for DoS against your application
PASS   | ERROR    |             | 0             | safe_mode                     | It's not actually 'safe' ('Off' recommended)
PASS   | WARNING  |             | 0             | register_long_arrays          | Registering long arrays turns on the HTTP_*_VARS (Recommended Off)
PASS   | WARNING  |             |               | max_input_vars                | A maximum number of input variables should be defined to prevent performance issues
PASS   | WARNING  |             | 0             | display_startup_errors        | Showing startup errors could provide extra information to potential attackers
FAIL   | WARNING  |             |               | open_basedir                  | Restricting PHP's access to the file system to a certain directory prevents file-based attacks in unauthorized areas.
PASS   | WARNING  |             | 0             | error_reporting               | Error reporting should be different based on context, off in production
PASS   | WARNING  |             |               | upload_max_filesize           | A maximum upload size should be defined to prevent server overload from large requests
PASS   | WARNING  |             | 2M            | upload_max_filesize           | The max upload size should not be too high, to prevent server overload from large requests
PASS   | WARNING  |             |               | post_max_size                 | A maximum post size should be defined to prevent server overload from large requests
PASS   | WARNING  |             | 8M            | post_max_size                 | The max upload size should not be too high, to prevent server overload from large requests
PASS   | WARNING  |             |               | memory_limit                  | A memory limit should be defined to prevent server overload from large processes
PASS   | WARNING  |             | 128M          | memory_limit                  | The standard memory limit should not be too high, if you need more memory for a single script you can adjust that during runtime using ini_set()
PASS   | WARNING  |             | 0             | asp_tags                      | Old versions of PHP allowed for ASP-style tags (<% %>) instead of <?php. This should be disabled.
PASS   | WARNING  |             | UTF-8         | default_charset               | Ensure that a default character set is defined, UTF-8 is preferred
PASS   | ERROR    |             | 0             | zend.ze1_compatibility_mode   | The Zend Engine PHP 4 compatibility mode should be disabled to prevent object-related functional issues.
PASS   | WARNING  |             | 0             | xdebug.default_enable         | Xdebug should be disabled in production
PASS   | WARNING  |             | 0             | xdebug.remote_enable          | Xdebug should not be trying to contact debug clients
FAIL   | WARNING  |             |               | disable_functions             | Methods still enabled - exec, passthru, shell_exec, system, proc_open, popen, curl_exec, curl_multi_exec
PASS   | WARNING  |             |               | soap.wsdl_cache_dir           | Security checks for CVE-2013-1635 and CVE-2013-6501
PASS   | WARNING  |             |               | upload_tmp_dir                | Checks to see if the upload_tmp_dir is inside the open_basedir folder

30 passing
4 failure(s) and 8 warnings

In the report you will find two statuses: PASS and FAIL. In the beginning you will focus on all statues of failures. “Description” column contains hints on possible values, what is the risk to leave the current setting. E.g:

session.cookie_domain - It is recommended that you set the default domain for cookies.
session.hash_function - Weak hashing algorithms in use. Rather use one of these: sha224...
session.cookie_httponly - Setting session cookies to 'http only' makes them only readable...

Remember not to apply new settings at once, without checking what they are responsible for, especially on production servers. We advice to follow documentation (http://php.net/manual/en/ini.list.php for example)

Command line usage:

If the path is omitted, iniscan will try to find it based off the current configuration ('php -i'). By default, this report will include both PASS and FAIL results of the checks. If you’d like to only return the failures, use the 'fail-only' argument:

# iniscan scan --path=<path/to/php.ini> --fail-only

Various formats can be used for output. By default 'scan' command will generate console output and will return exit code based on the results:

  • 0: No errors
  • 1: Failures found

For HTML output use --format=html and --output option to point output directory:

# iniscan scan --format=html --output=/var/www/output

The results will be written to a file named iniscan-output-date.html

Read more