写入文件的输入是否会被恶意篡改?

时间:2013-01-28 04:23:18

标签: php file security validation

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>

6 个答案:

答案 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读/写函数。关注实际解析或分析输入的步骤。一些可能的例子:

  • 如果文件将显示在基本日志阅读器中,您可能需要确保每个输入都限制在一定长度,并且不包含换行符或您选择的字段分隔符,并且每行的开头是有效的时间戳。
  • 如果文件将在网络浏览器中显示,您可能需要确保输入不包含脚本或指向其他资源的链接(如IMG标记)。
  • Excel文件对行长度,时间戳和分隔符有类似的顾虑。只要Excel将文件解析为文本,您就不必担心包含可执行代码的人。 (另外,现代Excel版本在运行之前会为您提供有关包含宏的警告。)

答案 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。应使用自己的规则验证文件,以确保数据符合预期。如果脚本直接输出任何内容,那么应该进行消毒以匹配输出的上下文。因此,总结一下您的申请的验证和消毒程序将是:

  1. 创建日志:网络浏览器--- POST ---&gt; get_message.php ---&gt;验证message是否有效--- fwrite() - &gt; log.txt

  2. 处理日志: log.txt --- fopen() ---&gt; process.php ---&gt;验证该文件是否有效---&gt;什么输出?然后在这个阶段消毒。

  3. 以上假设在脚本处理之前进行了正确的授权(即当前用户在您的应用程序中具有记录message或处理日志的权限。)

答案 3 :(得分:0)

我会对它进行消毒。当涉及到日志时,只需确保将其放入预留空间 - 例如,如果日志是每行一条记录,则删除新行和其他内容从用户的输入,所以他不能欺骗你。

查看Attack Named Log Injection

在显示日志文件时也要非常小心。确保没有输出会损害您的读者。

答案 4 :(得分:0)

  • 您附加到当前目录中的文件 - 这似乎可以通过浏览器下载,因此您可以创建安全漏洞。将文件放在文档根目录之外(最好),或通过.htaccess保护它。
  • 您应该清理所有用户输入。总是。这意味着什么取决于您如何使用这些数据。您似乎写入文本日志文件,因此您只想让可打印和空白类字符通过。防御性消除:不要指定错误的字符并让其他所有内容通过,但要定义一个列表/类别&#34; good&#34; chars,让这些好的角色通过。
  • 根据您的使用案例,您可能希望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行。

说:发布的数据需要如何消毒,完全取决于您的应用程序。

相关问题