使用面向Web的应用程序防止目录遍历 - 正则表达式是否万无一失?

4
我是一名有用的助手,可以为您翻译文本。
我处于这样一种情况:需要允许用户从URL动态确定下载文件。在下载开始之前,我需要进行一些身份验证,因此下载必须先通过脚本运行。所有文件都将存储在Web根目录之外,以防止手动下载。
例如,以下任何一个都可以作为下载链接: 基本上,文件夹深度可能会有所不同。
为了防止目录遍历,比如说: http://example.com/downloads/../../../../etc/passwd 我需要在URI上做一些检查。(注意:我没有将此信息存储在数据库中的选项,必须使用URI)
以下正则表达式是否足够强大,以确保用户不输入任何可疑内容?
preg_match('/^\/([-_\w]+\/)*[-_\w]+\.(zip|gif|jpg|png|pdf|ppt|png)$/iD', $path)

我还有什么其他选项来确保URI的合理性?可能可以在PHP中使用realpath吗?
6个回答

7

我建议使用realpath()将路径转换为绝对路径。然后,您可以将结果与允许的目录路径进行比较。


是的,我认为这样做并进行正则表达式检查可能就可以解决问题了。 - John B
如果整个应用程序都是符号链接(例如/var/www/spline_reticulator -> /opt/apps/app_47244),并且您允许的路径为/var/www/spline_reticulator/downloads,则如果尝试使用realpath()来清理路径,则无法下载任何内容。 - AndreKR

3

我虽然不是PHP开发人员,但我可以告诉你,在这种情况下使用基于正则表达式的保护就像穿着T恤迎战飓风。

在安全术语中,这种问题被称为规范化漏洞(即您的应用在操作系统有机会将其转换为绝对文件路径之前解析给定的文件名)。攻击者可以想出任意数量的文件名排列组合,几乎肯定无法与您的正则表达式匹配。

如果您必须使用正则表达式,则请尽可能悲观(仅匹配有效的文件名,拒绝其他所有内容)。我建议您在PHP中进行规范化方法研究。


也要了解你的服务器:如果你在 Windows 上运行 PHP,尝试访问像“com.txt”这样保留给设备的文件名可能会失败。 - bobince

1

我认为你可以使用htaccess来实现这个。


1

我认为以下3个检查可以是一个理想的解决方案

  • 确保文件与通常接受的正则表达式匹配,以确定文件路径的可能性
  • 使用realpath(在PHP中)获取用户请求文件的规范形式,并进行比较,以确保它在基本目录内
  • 从PHP v5.3开始,您可以使用ini_set将open_basedir限制为特定文件夹,以便无法读取该文件夹外的文件(使用fopen,include,fread等)

0

我的解决方案

$filesPath = realpath(".");
$reqPath = realpath($_GET["file"]);
$pat = "%^".preg_quote($filesPath)."%";

if(preg_match($pat,$reqPath)){
    echo "File found";
}else{
    echo "Access denied"
}
?>


从您博客的日期戳和内容来看,您显然是针对这个问题创建了该博客文章。为什么您不在这里发布回复呢? - Bryan
好的,谢谢。已经取消了踩票。关于这个问题,在 Meta 上有很多讨论。你可以链接到博客上提供额外的细节来补充你的答案,但是你不应该只在博客上发布你的答案并提供一个链接。 - Bryan

0
您的文件名中会包含哪些字符?如果只包含[a-zA-Z0-9]、单个点、破折号和斜杠,那么可以随意去除其他内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接