提问人:Aaron 提问时间:8/30/2008 最后编辑:Script47Aaron 更新时间:7/11/2022 访问量:25792
何时最好清理用户输入?
When is it best to sanitize user input?
问:
用户等于不可信。永远不要相信不可信用户的输入。我明白了。但是,我想知道什么时候是清理输入的最佳时间。例如,您是盲目地存储用户输入,然后在访问/使用时对其进行清理,还是立即清理输入,然后存储此“清理”版本?也许除了这些之外,还有一些其他方法我没有。我更倾向于第一种方法,因为来自用户输入的任何数据仍然必须谨慎处理,其中“清理”的数据仍然可能在不知不觉中或意外地是危险的。无论哪种方式,人们认为哪种方法是最好的,出于什么原因?
答:
我发现立即清洁它有两个好处。首先,您可以对其进行验证并向用户提供反馈。第二,您不必担心在其他地方使用数据。
我喜欢尽早对其进行清理,这意味着当用户尝试输入无效数据时,就会进行清理。如果他们的年龄有一个文本框,并且他们输入了数字以外的任何内容,我不会让字母的按键通过。
然后,无论读取数据(通常是服务器),当我读取数据时,我都会进行健全性检查,以确保不会因为更坚定的用户(例如手动编辑文件,甚至修改数据包)而溜进来
编辑:总体而言,请尽早进行消毒,并在您看不到数据的任何时候进行消毒,哪怕是一秒钟(例如文件保存 - >文件打开)
评论
在将用户输入下放到应用程序的较低层之前,应始终将其视为恶意输入。始终尽快处理清理输入,在检查恶意意图之前,不应出于任何原因将其存储在数据库中。
在存储数据之前清理数据。通常,您不应该在没有首先清理输入的情况下执行任何 SQL 操作。您不想让自己遭受 SQL 注入攻击。
我遵循这些基本规则。
- 仅通过 POST 修改 SQL 操作,例如 INSERT、UPDATE、DELETE。 永远不要 GET。
- 逃避一切。
- 如果您期望用户输入是某种东西,请确保检查它是否是某种东西。例如,您正在请求一个号码,然后确保它是一个号码。使用验证。
- 使用过滤器。清理不需要的字符。
用户是邪恶的!
好吧,也许并非总是如此,但我的方法是始终立即进行消毒,以确保我的后端附近没有任何风险。
额外的好处是,如果在输入点进行清理,则可以向用户提供反馈。
评论
假设所有用户都是恶意的。 尽快对所有输入进行消毒。 句点。
在对数据进行任何处理之前,我会对其进行清理。我可能需要获取“名字”和“姓氏”字段,并将它们连接到插入到数据库中的第三个字段。我打算在进行串联之前对输入进行清理,这样我就不会出现任何处理或插入错误。越快越好。即使在前端(在 Web 设置中)使用 Javascript 也是理想的,因为这将在没有任何数据进入服务器的情况下发生。
可怕的是,您甚至可能还想开始清理来自数据库的数据。最近激增的 ASPRox SQL 注入攻击是双重致命的,因为它会感染给定数据库中的所有数据库表。如果您的数据库托管在同一数据库中托管了多个帐户,则您的数据会因其他人的错误而损坏,但现在您已经加入了向访问者托管恶意软件的行列,因为您自己的初始错误。
当然,这需要大量的前期工作,但如果数据至关重要,那么这是一项值得的投资。
尽早是好的,绝对在你尝试解析它之前。您稍后要输出的任何内容,尤其是传递给其他组件(即 shell、SQL 等)的任何内容都必须进行清理。
但不要太过分 - 例如,密码在存储之前会进行哈希处理(对吗?哈希函数可以接受任意二进制数据。而且您永远不会打印出密码(对吗?因此,不要解析密码 - 也不要对它们进行清理。
此外,请确保您是从受信任的进程进行清理的 - JavaScript/任何客户端都比无用的安全性/完整性更糟糕。(不过,尽早失败可能会提供更好的用户体验 - 只需在两个地方都这样做。
Perl 有一个 taint 选项,它认为所有用户输入都是“污点”,直到用正则表达式检查它。受污染的数据可以被使用和传递,但它会污染它所接触的任何数据,直到未被污染。例如,如果将用户输入附加到另一个字符串,则新字符串也会受到污染。基本上,任何包含受污染值的表达式都会输出受污染的结果。
被污染的数据可以随意抛出(污染数据),但是一旦它被对外部世界有影响的命令使用,perl脚本就会失败。因此,如果我使用受污染的数据来创建文件、构造 shell 命令、更改工作目录等,Perl 将失败并出现安全错误。
我不知道还有另一种语言有类似“污点”的东西,但使用它非常令人大开眼界。令人惊讶的是,如果您不立即取消污染,受污染的数据会以如此快的速度传播。对于程序员来说,自然而正常的事情,比如根据用户数据设置变量或打开文件,在打开污点的情况下似乎是危险和冒险的。因此,完成工作的最佳策略是在从外部获得一些数据后立即取消污染。
我怀疑这也是其他语言中最好的方法:立即验证用户数据,这样错误和安全漏洞就不会传播得太远。此外,如果潜在的漏洞位于一个地方,则审核代码中的安全漏洞应该更容易。而且,您永远无法预测哪些数据以后将用于什么目的。
评论
最重要的是在逃跑时始终保持一致。意外的双重消毒是蹩脚的,不消毒是危险的。
对于 SQL,只需确保数据库访问库支持自动转义值的绑定变量即可。任何手动将用户输入连接到 SQL 字符串的人都应该更清楚。
对于 HTML,我更喜欢在最后一刻逃脱。如果你破坏了用户输入,你就永远无法找回它,如果他们犯了错误,他们可以在以后编辑和修复。如果你破坏了他们的原始输入,它就永远消失了。
这取决于您正在进行什么样的消毒。
为了防止 SQL 注入,不要对数据本身执行任何操作。只需使用准备好的语句,这样,您就不必担心弄乱用户输入的数据,并使其对您的逻辑产生负面影响。你必须稍微清理一下,以确保数字是数字,日期是日期,因为一切都是来自请求的字符串,但不要尝试做任何检查来做一些事情,比如阻止关键字或任何东西。
为了防止 XSS 攻击,在存储数据之前修复数据可能会更容易。然而,正如其他人所提到的,有时拥有用户输入内容的原始副本是件好事,因为一旦你改变了它,它就会永远丢失。这几乎是太糟糕了,没有一种万无一失的方法来确保您的应用程序只发布经过清理的 HTML,就像您可以确保您不会通过使用准备好的查询被 SQL 注入捕获一样。
我的意见是尽快清理用户输入的客户端和服务器端,我就是这样做的
- (客户端),允许用户 在字段中仅输入特定键。
- (客户端),当用户使用 onblur 转到下一个字段时,测试他输入的输入 针对正则表达式,如果有什么不好,请通知用户。
- (服务器端),再次测试输入, if 字段应该是 INTEGER 检查(在 PHP 中您可以使用 is_numeric() ), IF 字段具有众所周知的格式 根据正则表达式检查它,所有 其他(如文字评论),只是 逃避他们。如果有任何可疑情况,请停止脚本执行,并向用户返回通知,告知用户他输入的数据无效。
如果某些事情看起来确实是可能的攻击,脚本会向我发送邮件和短信,这样我就可以尽快检查并阻止它,我只需要检查我登录所有用户输入的日志,以及脚本在接受输入或拒绝输入之前所做的步骤。
我像 Radu 一样清理我的用户数据......
第一个同时使用正则表达式并控制允许字符的客户端 使用绑定到事件的 javascript 或 jQuery 输入到给定的表单字段中,例如 onChange 或 OnBlur,它会在输入之前删除任何不允许的输入 提交。然而,要意识到,这真的只有让那些 用户知道,数据也将在服务器端进行检查。它 与其说是任何实际的保护,不如说是警告。
其次,这些天我很少看到这样做了,第一次检查是 完成服务器端是检查提交表单的位置。 仅允许从您指定为有效页面提交表单 位置,您甚至可以在读取任何数据之前杀死脚本。授予 这本身是不够的,因为拥有自己服务器的优秀黑客可以“欺骗” 域和 IP 地址,使脚本显示它即将到来 从有效的表单位置。
接下来,我什至不必这么说,但总是,我的意思是总是,运行 您的脚本处于污点模式。这迫使你不要偷懒,要勤奋 第 4 步。
使用格式正确的正则表达式尽快清理用户数据,以适应 表单上任何给定字段的预期数据。不要走捷径 臭名昭著的“独角兽的魔法号角”,吹过你的污点检查...... 或者,您还不如首先关闭污点检查,以获得所有好处 这将为您的安全做出贡献。这就像给精神病患者一把锋利的刀,承受 你的喉咙,并说'你真的不会用那个伤害我,对吧'。
在第四步中,这是我与大多数人的不同之处,因为我只消毒 我将以可能提供安全性的方式实际使用的用户数据 风险,例如任何系统调用、对其他变量的赋值或对 存储数据。如果我只使用用户输入的数据来与数据进行比较 我自己存储在系统上(因此知道我自己的数据是安全的), 那么我就懒得清理用户数据了,因为我永远不会去找我们 这本身就是一个安全问题。例如,将用户名输入为 一个例子。我仅使用用户输入的用户名来检查它是否匹配 我的数据库,如果为 true,则使用数据库中的数据来执行 我可能会在脚本中调用它的所有其他函数,知道它是安全的,并且永远不会 之后再次使用用户数据。
最后,是过滤掉这些天机器人尝试自动提交的所有内容,并使用 “人工身份验证”系统,例如验证码。如今,这已经足够重要了 我花时间编写了我自己使用照片的“人工身份验证”模式 以及“人类”输入他们在图片中看到的内容的输入。我这样做是因为 我发现验证码类型的系统确实惹恼了用户(你可以通过他们的 眯起眼睛试图破译扭曲的字母......通常超过 和 一遍)。这对于使用 SendMail 或 SMTP 的脚本尤其重要 对于电子邮件,因为这些是您饥饿的垃圾邮件机器人的最爱。
简而言之,我会像对我妻子一样解释它......你的服务器就像一个受欢迎的夜总会,你拥有的保镖越多,你可能遇到的麻烦就越少 在夜总会。我在门外有两个保镖(客户端验证和人工身份验证),一个保镖就在门内(检查有效的表单提交位置......“这真的是你在这个身份证上吗”),还有几个保镖 靠近门(运行污点模式并使用良好的正则表达式来检查 用户数据)。
我知道这是一篇较旧的帖子,但我觉得它足够重要,任何可能在我访问这里后阅读它的人都会意识到在安全性方面没有“灵丹妙药”,并且需要所有这些相互结合才能使您的用户提供的数据安全。仅仅使用其中的一两种方法实际上毫无价值,因为它们的力量只有在它们齐心协力时才存在。
或者总而言之,正如我妈妈经常说的那样......“安全总比后悔好”。
更新:
这些天我正在做的另一件事是对我的所有数据进行 Base64 编码,然后对将驻留在我的 SQL 数据库上的 Base64 数据进行加密。以这种方式存储它需要大约三分之一的总字节,但在我看来,安全优势超过了数据的额外大小。
评论
不幸的是,几乎没有一个参与者清楚地理解他们在说什么。按照字面。只有 Kibbee 设法直截了当地走。
本主题是关于消毒的。但事实是,像每个人都如此渴望谈论的广义“通用消毒”这样的事情根本不存在。
有无数种不同的媒介,每种媒介都需要自己独特的数据格式。此外,即使是单一的特定介质,其部分也需要不同的格式。比如说,HTML 格式对于嵌入在 HTML 页面中的 javascript 是无用的。或者,字符串格式对 SQL 查询中的数字毫无用处。
事实上,正如大多数赞成的答案所建议的那样,这种“尽早消毒”是不可能的。因为人们无法分辨数据将用于哪个特定介质或介质部分。比如说,我们正准备防御“sql-injection”,逃避一切移动的东西。但是哎呀!- 一些必填字段没有填写,我们必须将数据填回表单而不是数据库......添加了所有斜杠。
另一方面,我们努力逃避了所有的“用户输入”......但是在SQL查询中,我们没有引号,因为它是一个数字或标识符。而且没有“消毒”对我们有所帮助。
第三 - 好吧,我们尽最大努力净化可怕、不可信和不屑一顾的“用户输入”......但是在一些内部过程中,我们使用了这些数据,没有任何格式(因为我们已经尽力了!) - 哎呀!已经得到了二阶注入的所有荣耀。
因此,从现实生活使用的角度来看,唯一正确的方法是
- 格式化,而不是任何“消毒”
- 使用前
- 根据一定的介质规则
- 甚至遵循该媒体不同部分所需的子规则。
评论
上一个:将安全漏洞告知潜在客户?
评论