理清php伪协议与文件包含

allow_url_fopen

先看看文档:

allow_url_fopen boolean

本选项激活了 URL 形式的 fopen 封装协议使得可以访问 URL 对象例如文件。默认的封装协议提供用 ftp 和 http 协议来访问远程文件,一些扩展库例如 zlib 可能会注册更多的封装协议。

Note:

出于安全性考虑,此选项只能在 php.ini 中设置。

Note:

此选项是紧接着版本 4.0.3 发布后引进的。版本 4.0.3 以及之前的版本只能在编译时通过配置项 --disable-url-fopen-wrapper 来取消此特性。

Warning

Windows 版在 PHP 4.3.0 之前,以下函数不支持远程文件访问:includeinclude_once, requirerequire_onceGD 和图像处理 函数中的 imagecreatefromXXX 函数。

从文档得出一些信息:

allow_url_fopen选项是为了配置远程对象访问的权限,一切本地对象的访问权限其实不受这个配置选项的影响。本地是相对于服务器来说的,对服务器来说服务器的文件是属于本地文件。所以此选项影响的是RFI,即远程文件包含。包括HTTP(S)协议和FTP协议。

对于data://协议来说,官方文档说不受allow_url_fopen影响,但实践发现,其实是需要allow_url_fopen=On才生效的。

所以allow_url_fopen影响如下协议(即需要allow_url_fopen=On才生效):

http://

https://

ftp://

data://

allow_url_include

先看看文档:

allow_url_include boolean

This option allows the use of URL-aware fopen wrappers with the following functions: include, include_once, require, require_once.

Note:

This setting requires allow_url_fopen to be on.

从文档可以知道:

allow_url_include 配置是为了让include, include_once, require, require_once 四个函数可以包含远程对象而设置的。并且需要allow_url_fopen=On 才可以包含远程文件。所以远程文件包含需要allow_url_fopen和allow_url_include同时为On才可以。

其实allow_url_include还约束一些其他协议:

php://input

php://stdin

php://memory

php://temp

总结:

allow_url_fopen是为了约束fopen、file_get_contents等函数访问远程对象而设置的,当include、include_once、require、require_once函数要访问远程对象时,还需要allow_url_include=On。

只需要allow_url_include=On就生效的协议:

php://input

php://stdin

php://memory

php://temp

只需要allow_url_fopen=On就生效的协议:

http(s)://

ftp://

这里注意,当作为include类函数的参数传入时,还需要allow_url_include=On, 但对于协议本身来说并不需要allow_url_include=On

需要allow_url_fopen=On、allow_url_include=On同时才生效的协议:

data://

不依赖于两者的协议:

php://filter等

file://

zlib://

etc.

部分验证代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* http:// https:// ftp://
allow_url_include=Off
allow_url_fopen=On
*/
echo file_get_contents('http://your_host/test.html'); // Can read properly.
include('http://your_host/test.html'); // Error: Need allow_url_include to be on.
/* php://input
allow_url_include=On
allow_url_fopen=Off
*/
echo file_get_contents('php://input');
include('php://input');
/* data://
allow_url_include=On
allow_url_fopen=On
*/
echo file_get_contents('data://text/plain;base64,SSBsb3ZlIFBIUAo=');
include('data://text/plain;base64,SSBsb3ZlIFBIUAo=');