Uber简单的例子说明了这一点:
$message = $_POST['message'];
$fp = fopen("log.txt", "a");
fwrite($fp, $message);
fclose($fp);
我应该清理$_POST['message']
变量的用户输入吗?
我理解准备好的语句(用于数据库清理)和htmlentities
(如果我在某个时间将POST
消息输出回屏幕)但在这种情况下,输入只是坐在一个将由小PHP脚本(via fopen()
)
答案取决于如何阅读?例如,如果我通过fopen()打开日志文件,它应该是htmlentities
,如果我打算下载日志文件并用Excel读取(用于过滤目的),那么没有什么可做的? / p>
答案 0 :(得分:6)
你的代码基本上是无辜的。唯一的“明显”攻击是重复将数据上传到服务器,最终耗尽磁盘空间。
“消毒”是一种情境化的东西。这不是你可以撒上代码来使它变得更好的东西,就像你可以在食物上加盐一样。也许你会清理$ _POST数据以防止SQL注入攻击,但随后在HTML上下文中使用数据 - 现在你很容易受到XSS攻击。也许这是一个图片上传,你做了基本的MIME类型确定,以确保它是一个图像。这一切都很好,但是有人上传了小鬼色情片,它会通过“这是一个形象”测试,现在你有一个更大的问题。由于您接受用户数据并将其写入文件,因此无法使用此代码(磁盘空间问题除外)来滥用您的系统。您不能将某些数据序列嵌入到导致PHP或底层操作系统的数据中,以突然停止将该数据写入磁盘并开始执行它。如果数据被上传则无关紧要,因为它永远不会在可用于影响脚本执行的上下文中使用。你只是从网络服务器中吸取一些数据,并将其吐出到磁盘上。您不允许用户影响写入哪个文件(除非您的用户具有对服务器的shell级别访问权限,并且可以创建一个名为“log.txt”的符号链接指向某个其他更重要的文件)。 / p>
真正的问题出现了......在你写完这个文件之后你怎么办?如果你以后的代码做了一些愚蠢的事情
include('log.txt');
然后现在你遇到了问题 - 你现在把这个“无辜”的数据放在磁盘上的一个文件中,并把它变成潜在的可执行代码。只需在该文件中的任何位置使用简单<?php exec('rm -rf /') ?>
即可废弃您的服务器。
同样,考虑一下像PHP magic_quotes
这样天生愚蠢的“安全”措施。 PHP开发人员(错误和 STUPIDLY )假设从外部世界提交的任何数据只会在SQL上下文中使用,并且对所有数据执行SQL转义,无论如何它的最终目的。更糟糕的是,他们只是假设所有数据库都使用反斜杠来表示它们的转义序列。如果你从来没有使用过MySQL以外的任何东西,这一切都很好,但是,如果你在SQL Server上,那该怎么办?现在你必须将PHP提供的Miles O\'Brien
翻译成Miles O''Brien
,基本上不得不自动解决PHP为你做的事情。
TL; DR:不要使用猎枪'消毒'方法,它们几乎总是无用/无意义,只是涉及到之前和之后的更多工作。只需在使用数据时使用特定于上下文的方法。
答案 1 :(得分:3)
您应该清理用户输入,但 完全取决于输入的内容。 “消毒”指的是确保输入对于特定用途是安全的或理智的。在您确定用例之前,该术语不能更具体。
您不必担心像fopen()这样的PHP读/写函数。关注实际解析或分析输入的步骤。一些可能的例子:
答案 2 :(得分:1)
一般规则是validate input and sanitize output。
如果可以以任何方式validate输入,那么你应该这样做。如果没有,那么您应该在输出时对其进行清理,以确保它对于使用它的上下文是安全的。
e.g。如果你知道每个message
应该少于100个字符而不管它是如何使用的,那么读取POST数据的脚本可以验证并拒绝其POST数据包含输入的任何请求。 100个字符或以上。
验证是一种“全有或全无”的方法,拒绝任何不遵循某些规则的内容,无论输出背景如何,而卫生处理是根据上下文“制造安全的东西”的过程。我认为做出这种区分非常重要。
在您的情况下,您提供的示例代码不会输出(除了另一个脚本处理的目的)。它更像是存储操作而不是输出操作,因为message
可以像文件系统一样容易地写入数据库。在这种情况下需要锁定的主要攻击面似乎是文件权限,并确保除了您打算执行此操作的脚本以及正确的上下文之外,没有任何内容可以读取或写入文件。例如,我意识到您的示例已经简化,但在特定情况下,您应确保将文件写入Web根目录上方的位置,或者写入适当设置了文件夹权限的位置。否则,您可能无意中允许网络上的任何人阅读http://www.example.com/log.txt,如果他们也可以写信,那么如果他们可以欺骗浏览器,可能会利用某种XSS攻击将文件作为HTML读取。旧版Internet Explorer try and detect the MIME type而不是依赖text/plain
的服务器标头值(另请参阅here)。这些漏洞可能稍微偏离主题,我只是提到它们是彻底的,并作为确保文件本身被适当锁定的一个例子。
回到你的问题:在你的情况下,你的验证应该由处理log.txt
的脚本进行。这应该验证文件。请注意,它正在验证此处的文件,而不是原始message
。应使用自己的规则验证文件,以确保数据符合预期。如果脚本直接输出任何内容,那么应该进行消毒以匹配输出的上下文。因此,总结一下您的申请的验证和消毒程序将是:
创建日志:网络浏览器--- POST ---&gt; get_message.php
---&gt;验证message
是否有效--- fwrite()
- &gt; log.txt
处理日志: log.txt
--- fopen()
---&gt; process.php
---&gt;验证该文件是否有效---&gt;什么输出?然后在这个阶段消毒。
以上假设在脚本处理之前进行了正确的授权(即当前用户在您的应用程序中具有记录message
或处理日志的权限。)
答案 3 :(得分:0)
我会对它进行消毒。当涉及到日志时,只需确保将其放入预留空间 - 例如,如果日志是每行一条记录,则删除新行和其他内容从用户的输入,所以他不能欺骗你。
在显示日志文件时也要非常小心。确保没有输出会损害您的读者。
答案 4 :(得分:0)
根据您的使用案例,您可能希望flock()日志文件,以防止多个并行请求混淆在您的文件中:
$ logtext = sanitizeLog($ _ POST [Message&#39;]); $ fd = fopen(&#34; /path/to/log.txt" ;,&#34; a&#34;); if(flock($ fd,LOCK_EX)){ fseek($ fd,0,SEEK_END); fwrite($ fd,$ logtext); flock($ fd,LOCK_UN); } FCLOSE($ FD);
我省略了对fopen()结果的检查......
答案 5 :(得分:0)
关于PHP的fwrite()函数,无需清理:fwrite()只是将其写入传递的文件中。
关于日志文件,可能希望清理。原因如下:
假设攻击者将多行值发布为消息。如果您的日志在帖子之前
line 1
line 2
然后是在帖子之后
line 1
line 2
line 3
remainder of line 3
very remainder of line 3
因为攻击者发布了这个:
line 3\nremainder of line 3\nvery remainder of line 3
注意:已发布一次,添加了3行。
说:发布的数据需要如何消毒,完全取决于您的应用程序。