rfc:allow_url_include

PHP RFC: Precise URL include control

Introduction

When allow_url_include was introduced, it was good enough protection against “remote script inclusion”. However, it causes problem for “local script inclusion” protections. This RFC addresses the issue and make "local script inclusion" protection more effective.

allow_url_include is INI_SYSTEM, therefore include/require simply ignore the setting for certain stream wrappers always. allow_url_include does not actually disallow URL form includes. It allows “phar://” regardless of allow_url_include setting and helps attackers obfuscate attack scripts. e.g. include(“phar://evil_phar_file/evil_script.php”) is allowed at anytime. Current behavior may allow to bypass certain types of security filters and allow attacker's script to be executed.

Current allow_url_include behavior is wrong for 3 reasons.

  1. Implicit allowance of URL formed filename is problematic. It's “caller” responsibility to set this setting as intended. (Or “callee” must have API for overriding it to do the job)
  2. It does not make “include/require” behave as INI setting name implies.
  3. Being INI_SYSTEM increases risk of security filter bypass.

allow_url_include being INI_SYSTEM is false sense of security. It also violates simple API principle that

  • “caller” must have responsibility to set correct setting for conditions.

or

  • “callee” must have API/parameter to set correct conditions for the API.

Current allow_url_include and related API does not satisfy none of them.

We need more precise URL include control.

Proposal

  • Remove allow_url_include INI setting and introduce more precise URL include control.

Option #1

  • Introduce 2nd parameter that specifies the prefix of URL (wrapper)
  include('phar://phar_file/script.php', 'phar://');

Pros:

  1. Requires a lot less code modifications = less BC.
  2. Simple string comparison is enough.
  3. More specific which wrapper is used. (Only specified wrapper may be used)
  4. More flexible when new wrapper is added. (No additional code is needed for this)

Cons:

  1. 'phar://' looks redundant
  2. 2nd parameter is used solely for specifying wrapper. i.e. Cannot use it for no embedded mode flag, etc. There may be pseudo wrapper like "noembed://".

Option #2

  • Introduce “inlcude_type” flags to include*/require*() as 2nd parameter.
  include 'script.php' [, $include_type=0 ];

where $include_type (bitwise) is

  • PHP_STREAM_LOCAL = 1 - allow local wrappers. phar://, zip://, etc
  • PHP_STREAM_REMOTE = 2 - allow remote wrappers. http://, https://, ftp://, etc
  • PHP_STREAM_ALL = 3 (PHP_STREAM_LOCAL | PHP_STREAM_REMOTE)

Add getType() method to stream wrapper class returns PHP_STREAM_LOCAL, PHP_STREAM_REMOTE or PHP_STREAM_ALL.

Pros:

  1. API looks more systematic/clean

Cons:

  1. More complex and needs lots of modifications than option #1 (More BC)
  2. Not precise as option #1

Backward Incompatible Changes

  • Some include/require that use implicit URL include need 2nd parameter.
  • Option #2: If stream wrapper class does not have getType() method, it treated as PHP_STREAM_REMOTE.

Proposed PHP Version(s)

PHP 7.0

RFC Impact

To SAPIs

CLI - loading phar as main script is allowed by default.

php://input and php://stdin handling

php://input and php://stdin must be handled differently. These are “remote” input under Web SAPI while these are “local” input under CLI. Therefore, these “php” wrappers are handled according to SAPI type.

To Existing Extensions

Modules have stream wrappers.

  • phar
  • zip
  • zlib
  • php

Wrappers defined by PHP source distribution. (There may be others)

$ php -r "var_dump(stream_get_wrappers());"
array(12) {
  [0]=>
  string(5) "https"
  [1]=>
  string(4) "ftps"
  [2]=>
  string(13) "compress.zlib"
  [3]=>
  string(3) "php"
  [4]=>
  string(4) "file"
  [5]=>
  string(4) "glob"
  [6]=>
  string(4) "data"
  [7]=>
  string(4) "http"
  [8]=>
  string(3) "ftp"
  [9]=>
  string(14) "compress.bzip2"
  [10]=>
  string(4) "phar"
  [11]=>
  string(3) "zip"
}

To Opcache

None

New Constants

There will be constants for stream wrapper. TBD

php.ini Defaults

allow_url_include ini is removed.

Open Issues

Unaffected PHP Functionality

allow_url_fopen

Future Scope

allow_url_fopen has same issues. However, allow_url_fopen has less issue because it does not parse and execute script.

Proposed Voting Choices

Requires 2/3 majority

Patches and Tests

TBD

Implementation

After the project is implemented, this section should contain

  1. the version(s) it was merged to
  2. a link to the git commit(s)
  3. a link to the PHP manual entry for the feature

References

Links to external references, discussions or RFCs

Rejected Features

Keep this updated with features that were discussed on the mail lists.

rfc/allow_url_include.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1