超级简单的例子来说明这一点:
$message = $_POST['message'];
$fp = fopen("log.txt", "a");
fwrite($fp, $message);
fclose($fp);
我应该消毒用户输入为$_POST['message']
变量?
我明白预处理语句(用于数据库消毒)和htmlentities
(如果我输出的POST
信息返回到在一段时间内屏幕),但在这种情况下,输入简单地坐在将由一个小的PHP脚本读取日志文件( via fopen()
)
答案是依赖于将如何看? 例如,如果我不通过打开日志文件fopen()函数应该是htmlentities
,如果我打算用Excel(用于过滤目的)下载日志文件和读取它,有什么工作要做?
您的代码基本上是无辜的。 唯一的“明显的”攻击是重复数据上传到服务器,最终耗尽你的磁盘空间。
“消毒”的东西,就是情境。 这是不是你可以只是洒在代码,使之更好,像您可以与食用盐。 也许你会消毒$ _ POST数据,以防止SQL注入攻击,但随后在HTML上下文中使用的数据 - 现在你容易受到XSS攻击。 也许这是一个图片上传,你做基本的MIME类型确定,以确保它是一个图像。 这是所有罚款和花花公子,但后来有人上传小孩子的色情,这将通过“是一个形象”的考验,现在你已经有了一个更大的问题。
既然你接受用户数据和写出来的文件,没有什么东西是可以用这个代码来完成(除了磁盘空间的问题)滥用您的系统。 你不能嵌入一些数据序列分割为会导致PHP的数据,或者底层操作系统,突然停止写入数据到磁盘,并开始执行它。 不要紧,什么样的,如果数据被上传,因为它从来没有被在那里它可以被用来影响脚本的执行的情况下使用。 你只是吸吮从网络服务器的一些数据,和它吐到磁盘。 你不是让用户来影响该文件进行写入(除非你的用户对服务器外壳级别的访问和可能,比如,创建一个名为“log.txt的”在其他一些更重要的文件指向符号链接)。
真正的问题就来了后发......你怎么用这个文件来执行它已经写入后? 如果你以后的代码做一些愚蠢的像
include('log.txt');
那么现在你有一个问题 - 现在你已经采取了这种“无辜”的数据坐在磁盘上的文件,并把它变成了潜在的可执行代码。 它所需要的是一个简单的<?php exec('rm -rf /') ?>
在该文件移到回收站您的服务器的任何地方。
同时,考虑像固有的愚蠢的“安全”措施,这是PHP的magic_quotes
。 PHP开发( 错误和愚蠢 )假设从外界提交的任何数据将永远只能在SQL上下文中使用,并没有逃脱SQL上的所有数据,无论其最终目的。 而为了让情况变得更糟,他们简单地认为所有的数据库使用反斜线为他们转义序列。 这是所有罚款和花花公子,如果你从来不使用任何东西,但MySQL的,但如果你是,比如说,SQL Server上的是什么? 现在你有翻译的PHP提供的Miles O\'Brien
到Miles O''Brien
,基本上无需重做什么PHP自动为你做。
TL; DR:不要使用猎枪“消毒”的方法,他们几乎总是无用的/没有意义的,前后只涉及更多的工作。 只要使用在特定时间范围内的方法,你正在使用的数据。
你应该过滤用户输入,但如何完全取决于输入的是什么。 “消毒”是指确保输入是安全的或理智的特定用途的想法。 直到您解决在使用情况下,期限不能更具体。
您不必担心类似的fopen PHP的读/写功能()。 担心与实际分析或分析输入的步骤。 一些可能的例子:
- 如果一个文件将在基本日志读取器显示,您可能需要确保每个输入被限制为一定的长度,并且不包含换行符或者你选择的领域分隔符,每行的开始是一个有效时间邮票。
- 如果一个文件将在Web浏览器中显示的,则可能需要确保投入不包括脚本或其他资源的链接(像IMG标记)。
- Excel文件将有关于类似的担忧线的长度,时间戳,和分隔符。 你不必担心有人包含可执行代码,只要Excel将被解析文件为文本。 (另外,现代的Excel版本要给大家介绍的宏包括警告运行之前。)
一般的规则是,以验证输入和消毒输出 。
如果可能的话,以验证您的输入以任何方式,那么你应该。 如果没有,那么你应该清理它的时候输出,以确保它是因为它使用的语境是安全的。
例如,如果你知道,每个message
应该是,无论它是如何使用少于100个字符,读取POST数据可以验证并拒绝其POST数据包含输入是100个字符以上的任何请求脚本。
验证是一个“全有或全无”的办法,拒绝任何不遵循一定的规则,无论输出上下文,而环境卫生是“使一些安全”根据上下文的过程。 我认为作出这样的区分是很重要的。
在你的情况,你所提供的示例代码不输出(除了处理的另一个脚本puposes)。 这比该输出操作更多存储操作的message
,可以很容易地写入到数据库文件系统。 主要的攻击面将在此情况下需要锁定下来似乎是文件的权限,并确保没有任何东西可以读取或写入比你打算做这个脚本和正确的上下文下的其他文件。 例如,我知道你的榜样进行了简化,但在特定情况下,你应该确保该文件被写入上述Web根的位置,或到具有适当文件夹权限设置的位置。 否则,你可能在不经意间给任何人访问网络上阅读http://www.example.com/log.txt ,如果他们可以写入也有可能利用某种形式的XSS攻击,如果他们能欺骗浏览器进入读取文件的HTML。 Internet Explorer中的旧版本试图发现MIME类型 ,而不是依赖于服务器头值text/plain
(见这里也)。 这些漏洞可能会稍微偏离主题,虽然,我只是提到他们是彻底的和为确保文件的例子本身适当地锁定。
回到你的问题:你的情况,您的验证应该由处理脚本发生log.txt
。 这应该验证文件。 请注意,在这里验证文件,而不是原始message
。 该文件应该使用它自己的规则,以确保数据为预期进行验证。 如果脚本直接输出任何东西,这是那里的环境卫生,应采取地方匹配输出的情况下。 因此,要总结验证和环境卫生,为您的应用会的过程:
创建日志:Web浏览器--- POST ---> get_message.php
--->验证message
是否有效--- fwrite()
- > log.txt
流程日志: log.txt
--- fopen()
---> process.php
--->验证文件是有效的--->什么输出? 然后消毒在这个阶段。
上述假定处理由脚本发生之前正确的授权的情况下(即,当前用户具有权限的应用程序中的登录message
S或处理日志。)
我会清理它。 当涉及到日志,只要确保你把它放到预留空间 - 例如,如果日志是每行一个记录,剥去用户输入新线和其他的东西,所以他不能欺骗你。
看看攻击命名日志注入
另外要非常小心,当谈到显示日志文件。 确保无输出可能会损害你的读者。
关于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行补充说。
这就是说: 需要如何发布的数据将被拆除,完全取决于你的应用。