我有一个PHP脚本,允许用户通过指定文件名来删除目录中的某些文件(通过下拉 - 但这对于恶意变更的人来说很容易)。我通过执行以下操作“清理”文件名
if(preg_match(/'/^[a-zA-Z0-9.]$/'/,$file)) {
# do stuff to this particular file
}
我很确定应该阻止任何人做出任何令人讨厌的事情,但是因为这里的人们拥有的知识比我多,我以为我会问 - 这里有个漏洞,还是这个让讨厌的人离开?
答案 0 :(得分:2)
我不确定你的正则表达式是否真的有用:在这个范围之外的有效字符你将无法以这种方式删除。
我要做的一件事是在完整的最终路径上执行realpath()
,并检查它是否仍然是您允许的文件路径的子项。这将阻止../../
目录遍历攻击,即使它们使用某些特殊字符。这应该已经提供了相当好的安全性。
您还可以使用glob()
扫描目录,并检查结果以查看所请求的文件是否实际存在(即使使用最偷偷摸摸的目录遍历也无法避开。)
如果你想要完全偏执,你可以完全使用不同的方法:不要传输文件名,而是列出你之前指定的列表的索引。例如,如果您向用户显示此列表并将其保存在临时文本文件或数据库记录中:
然后只传递文本文件或数据库记录的(随机)ID,以及要删除的文件的编号:
delete.php?list=xasdafdas&index=3
你应该有一个非常无懈可击的解决方案,以防止任何可能的注入和文件名篡改。
您必须为每个请求存储单独的列表,因为文件可能会更改。
答案 1 :(得分:0)
也许你应该改变你的正则表达式
if(preg_match(/'/^[^a-zA-Z0-9.]+$/'/,$file)) {
# do stuff to this particular file
}
答案 2 :(得分:0)
如果您的文件名不是绝对路径,并且您始终在目录路径前加上
chdir(...); // change directory to that directory
// make use the $file is not contains '/'
$file = basename($file);
// check $file is not in list of files that you don't allow for delete
if ($file=='index.php' ...)
{
// do nothing
return false;
}
if (is_file($file))
{
unlink($file); // or other actions
}
答案 3 :(得分:0)
这个正则表达式几乎可以匹配任何东西。你的意思是/^[a-zA-Z0-9.]/
吗?那仍然会像../../../etc/shadow
那样匹配。 /^[a-zA-Z0-9.]+$/
(或简称/^[\w\d.]+$/
)更好,或者您只需针对您创建下拉列表的数组检查文件名。