VirtualPath
库可规范路径并防止目录遍历攻击,而无需查询文件系统。
建议使用依赖管理器 Composer 安装rayne/virtual-path
。
composer require rayne/virtual-path
VirtualPath
类将输入规范化为绝对virtual path ,而无需查询任何文件系统。它还检测并标记目录遍历攻击。
JailedPath
类利用VirtualPath
构建可用于处理真实文件的安全路径。规范化是相对于名为 path 的jail
完成的,该监狱用作用户输入的任何路径的虚拟根。由于JailedPath
不查询文件系统,因此它适合使用本地、远程或虚构路径。
请阅读“实施细节”部分以了解更多详细信息。
TL;DR如有疑问,请使用JailedPath
类。
JailedPath
在此示例中,网站访问者可以通过指定相对路径作为GET
参数来从本地目录/test
下载任何文件。为了防止用户通过目录遍历攻击离开目录,使用JailedPath
和/test
作为虚拟根目录。
<?php
use Rayne VirtualPath JailedPath ;
$ jailedPath = new JailedPath ( ' /test ' , $ _GET [ ' path ' ] ?? '' );
if ( $ jailedPath -> hasJailbreakAttempt ()) {
// Log jailbreak attempt, ban user, …
return ;
}
if ( is_file ( $ jailedPath -> getAbsolutePath ())) {
@ readfile ( $ jailedPath -> getAbsolutePath ());
}
下表显示了如何规范化用户定义的路径以及如何相对于虚拟根解释它们。
用户输入 | hasJailbreakAttempt() | getAbsolutePath() | getRelativePath() |
---|---|---|---|
空字符串 | false | /test | 空字符串 |
. | false | /test | 空字符串 |
a.png/../b.png | false | /test/b.png | b.png |
/a/./b | false | /test/a/b | a/b |
.. | true | /test | 空字符串 |
../example | true | /test/example | example |
../etc/passwd | true | /test/etc/passwd | etc/passwd |
大批 | true | /test | 空字符串 |
VirtualPath
如果不需要固定前缀或JailedPath
的糖衣,那么VirtualPath
就足够了,因为它是用于规范化路径的类。 VirtualPath
对输入进行规范化,并提供可信(规范化,带有前导/
)和不可信(可能是恶意用户输入的字符串表示形式)路径。
当VirtualPath
实例(可(string)
强制转换)附加到虚拟根目录时,可以使用VirtualPath
轻松重新创建前面的示例。
<?php
use Rayne VirtualPath VirtualPath ;
$ path = new VirtualPath ( $ _GET [ ' path ' ] ?? '' );
$ absolutePath = ' /test ' . $ path ;
根据使用场景,即使原始输入不可信,有时使用标准化可信路径也很有用,例如,当明确支持相对路径并在意外尝试访问virtual path之外的文件时给用户带来怀疑的好处。
注意: VirtualPath
返回带有前导/
规范化路径。处理文件时,建议添加受信任路径作为前缀(请参阅当前部分中的代码示例),否则将引用相对于文件系统根目录的文件。为了不忘记添加前缀,请在处理实际文件时使用JailedPath
类。
输入 | isTrusted() | getTrustedPath() | getUntrustedPath() |
---|---|---|---|
大批 | false | / | 空字符串 |
空字符串 | true | / | 空字符串 |
../articles | false | /articles | ../articles |
tags/../../articles | false | /articles | tags/../../articles |
tags/../articles | true | /articles | tags/../articles |
../etc/passwd | false | /etc/passwd | ../etc/passwd |
/etc/passwd | true | /etc/passwd | /etc/passwd |
etc/passwd | true | /etc/passwd | etc/passwd |
使用纯虚拟标准化路径有不同的好处:
路径规范化无需查询文件系统即可完成
不可能对virtual path范围之外的文件进行定时攻击
不需要复杂的比较来将目录遍历限制为特定目录及其子目录
仅有的.
、 ..
、 (标准化为
/
)和/
被解释为路径标准化
没有意外和信息泄露~
其他库中看到的扩展
VirtualPath
的实现不会解释、更改或删除控制字符和 Unicode:
某些系统上允许目录和文件路径包含控制字符
删除控制字符超出了库的范围
克隆存储库
git clone https://github.com/rayne/virtual-path.git
安装开发依赖项
composer install --dev
运行测试
composer test