什么时候最好消毒用户输入?

时间:2008-08-29 18:07:05

标签: xss sql-injection user-input sanitization

用户等于不值得信任。永远不要相信不值得信任的用户输入。我明白了。但是,我想知道什么时候消毒输入的最佳时间是。例如,您是否盲目存储用户输入,然后在访问/使用它时对其进行清理,或者您是否立即清理输入然后存储此“已清理”的版本?也许除了这些之外我还有其他一些方法。我更倾向于第一种方法,因为仍然必须谨慎地处理来自用户输入的任何数据,其中“清理的”数据可能仍然在不知不觉中或意外地变得危险。无论哪种方式,人们认为哪种方法最好,原因是什么?

14 个答案:

答案 0 :(得分:21)

不幸的是,几乎没有一个参与者清楚地了解他们在谈论什么。从字面上看。只有@Kibbee设法直截了当。

这个主题是关于消毒的。但事实是,像每个人都非常渴望谈论的广泛的“通用消毒”这样的事情是就是不存在。

数十种不同的媒介,每种都需要它自己的,不同的数据格式。此外 - 即使单一某些媒体也需要不同的格式化部分。比方说,HTML格式对于HTML页面中嵌入的javascript是无用的。或者,字符串格式对SQL查询中的数字没用。

事实上,正如大多数提出的答案中所建议的那样,“尽可能早地进行消毒”只是不可能。由于人们无法确定哪些媒介或中等部分将使用数据。比如说,我们正在准备防范“sql-injection”,逃避一切动作。但是哎呀! - 一些必填字段未填写,我们必须将数据填回表单而不是数据库...添加所有斜杠。

另一方面,我们努力转义所有“用户输入”...但是在sql查询中我们没有引号,因为它是一个数字或标识符。并没有“消毒”对我们有所帮助。

第三方面 - 好吧,我们尽力消除那些可怕,不值得信赖和鄙视的“用户输入”......但是在一些内部过程中我们使用了这些数据而没有任何格式化(因为我们已经做到了最好! ) - 和哎呀!在它的荣耀中获得了二阶注射。

因此,从现实生活使用的角度来看,唯一正确的方法是

  • 格式化,而不是“消毒”
  • 使用前
  • 根据某些媒介规则
  • 甚至遵循该媒体不同部分所需的子规则。

答案 1 :(得分:18)

我喜欢尽早清理它,这意味着当用户尝试输入无效数据时会进行清理。如果有一个TextBox适合他们的年龄,并且他们输入其他任何数字,我不会让这封信的按键通过。

然后,无论是读取数据(通常是服务器),我都会在读取数据时进行完整性检查,以确保没有任何内容因为更确定的用户(例如手动编辑文件,或者甚至修改数据包!)

编辑:总体而言,每当您在一秒钟内看不到数据时,请尽早清理并消毒(例如文件保存 - >文件打开)

答案 2 :(得分:17)

我像Radu一样清理用户数据......

  1. 第一个客户端使用正则表达式并控制允许的字符  使用绑定到事件的javascript或jQuery输入到给定的表单字段,例如  onChange或OnBlur,它甚至可以删除任何不允许的输入  提交。但要意识到,这实际上只会让那些人产生影响  用户知道,数据也将在服务器端进行检查。它的  比任何实际保护更多的警告。

  2. 其次,我现在很少看到这样做,第一次检查是  完成服务器端是检查表单提交的位置。  只允许从您指定为有效的页面提交表单  在您读取任何数据之前,您可以杀死脚本。当然,  这本身是不够的,作为一个拥有自己的服务器的好黑客可以'恶搞'  域和IP地址使您的脚本看起来它即将到来  从有效的表格位置。

  3. 接下来,我甚至不应该这样说,但总是,我的意思是始终,运行  您的脚本处于污点模式。这迫使你不要变得懒惰,并且要勤奋  第4步。

  4. 使用适合的格式正确的regex尽快清理用户数据  表单上任何给定字段的预期数据。不要走捷径  臭名昭着的'独角兽的魔角'吹过你的污点检查......  或者你也可以在第一时间关闭所有商品的污点检查  它会为你的安全做。这就像是给精神病患者一把锋利的刀子  你的喉咙,说'你真的不会伤害我,那将是你。'

    这是我在第四步中与大多数人不同的地方,因为我只是消毒  我将以可能提供安全性的方式实际使用的用户数据  风险,例如任何系统调用,对其他变量的分配或任何写入  存储数据。如果我只使用用户输入的数据来进行数据比较  我自己存储在系统上(因此知道我自己的数据是安全的),  然后我不打算清理用户数据,因为我永远不会以某种方式告诉我们  这表明自己是一个安全问题。例如,将用户名输入为  一个例子。我只使用用户输入的用户名来检查匹配  我的数据库,如果是,我之后使用数据库中的数据来执行  我可能在脚本中调用的所有其他函数,知道它是安全的,而且从不  之后再次使用用户数据。

  5. 最后,现在过滤掉所有机器人尝试的自动提交,用a  '人类认证'系统,如Captcha。这些日子这很重要  我花时间编写了自己的“人工认证”模式,使用照片  并且输入“人”进入他们在图片中看到的内容。我这样做是因为  我发现Captcha类型的系统真的让用户烦恼(你可以通过他们的  眯起眼睛试图破译扭曲的字母...通常在和  再次)。这对使用SendMail或SMTP的脚本尤为重要  对于电子邮件,因为这些是您饥饿的垃圾邮件机器人的最爱。

  6. 简而言之,我会像对待我的妻子一样解释它...你的服务器就像一个受欢迎的夜总会,你拥有的保镖越多,你可能遇到的麻烦越少 在夜总会。我在门外有两个保镖(客户端验证和人工认证),一个保镖就在门内(检查有效的表单提交位置......'这真的是你在这个ID'),还有几个保镖在 靠近门(运行污点模式和使用良好的正则表达检查 用户数据)。

    我知道这是一篇较老的帖子,但我认为对于那些可能在我访问之后阅读它的人来说,重要的是在安全方面意识到他们不是'魔术子弹',并且它需要所有这些相互配合才能使用户提供的数据安全。仅仅使用这些方法中的一种或两种实际上是毫无价值的,因为它们的力量只有在它们全部团结在一起时才存在。

    或者总之,正如我的妈妈经常说的那样......“比抱歉更安全”。

    更新:

    目前我正在做的另一件事是Base64编码我的所有数据,然后加密将驻留在我的SQL数据库上的Base64数据。以这种方式存储它需要大约三分之一的总字节数,但在我看来,安全性好处超过了数据的额外大小。

答案 3 :(得分:11)

这取决于你正在做什么样的消毒。

为了防止SQL注入,请不要对数据本身做任何事情。只需使用准备好的语句,这样,您就不必担心弄乱用户输入的数据,并使其对您的逻辑产生负面影响。你必须消毒一点,以确保数字是数字,日期是日期,因为一切都是来自请求的字符串,但不要尝试做任何检查来做阻止关键字或任何东西。

为了防止XSS攻击,在存储数据之前修复数据可能会更容易。然而,正如其他人所提到的,有时候拥有一个确切的用户输入的原始副本是很好的,因为一旦你改变它,它就会永远丢失。这几乎太糟糕了,没有一种简单的方法可以确保您的应用程序只会以确保您不会被使用准备好的查询的SQL注入捕获的方式发布已清理的HTML。

答案 4 :(得分:4)

最重要的是在逃跑时始终保持一致。意外的双重消毒是跛脚的,不消毒是危险的。

对于SQL,只需确保数据库访问库支持自动转义值的绑定变量。任何手动将用户输入连接到SQL字符串的人应该知道的更好。

对于HTML,我宁愿在最后一刻逃脱。如果您销毁用户输入,则永远无法将其恢复,如果他们犯了错误,他们可以稍后进行编辑和修复。如果你破坏他们的原始输入,那就永远消失了。

答案 5 :(得分:3)

早期很好,绝对是在您尝试解析它之前。您之后要输出的任何内容,或者特别是传递给其他组件(即shell,SQL等)的内容都必须进行清理。

但是不要过分 - 例如,在存储密码之前对密码进行哈希处理(对吗?)。散列函数可以接受任意二进制数据。你永远不会打印出密码(对吧?)。所以不要解析密码 - 也不要对它们进行消毒。

此外,请确保您正在从受信任的进程进行清理 - JavaScript /任何客户端都比无用的安全性/完整性更糟糕。 (尽管如此,它可能会提供更好的用户体验以便尽早失败 - 只需这两个地方。)

答案 6 :(得分:2)

Perl有一个污点选项,它会将所有用户输入视为“污染”,直到用正则表达式检查它为止。受污染的数据可以被使用和传播,但它会污染它接触到的任何数据,直到没有污染。例如,如果用户输入附加到另一个字符串,则新字符串也会受到污染。基本上,任何包含污染值的表达式都会输出污染的结果。

可以随意抛出受污染的数据(随着数据的发生而污染数据),但是一旦对外部世界产生影响的命令使用它,perl脚本就会失败。因此,如果我使用污染数据来创建文件,构造shell命令,更改工作目录等,Perl将失败并出现安全性错误。

我不知道另一种语言有类似“污点”的东西,但使用它一直非常开放。令人惊讶的是,如果你不立即解开它,很快就会有污染的数据传播开来。程序员自然而正常的事情,比如根据用户数据设置变量或打开文件,看起来很危险,并且在打开污点时会带来风险。因此,完成工作的最佳策略是在从外部获取一些数据后立即解开。

我怀疑这也是其他语言的最佳方式:立即验证用户数据,以免错误和安全漏洞传播得太远。此外,如果潜在的漏洞位于一个地方,则应该更容易审核安全漏洞的代码。而且您永远无法预测哪些数据将在以后用于何种目的。

答案 7 :(得分:2)

我的意见是尽可能在客户端和服务器端清理用户输入,我就是这样做的

  1. (客户端),允许用户 只输入字段中的特定键。
  2. (客户端),当用户使用onblur转到下一个字段时,测试他输入的输入 反对正则表达式,并注意用户是否有不好的事情。
  3. (服务器端),再次测试输入, 如果字段应该是INTEGER检查(在PHP中你可以使用is_numeric()), 如果字段具有众所周知的格式 全部检查它与正则表达式 其他人(如文字评论),只是 逃避他们。如果有任何可疑的情况,请停止脚本执行,并向用户返回通知,表明他所进入的数据无效。
  4. 如果某些东西看起来像是一个可靠的攻击,那么脚本会向我发送邮件和短信,所以我可以检查和maibe尽快阻止它,我只需要检查日志我在哪里登录所有用户输入,以及脚本在接受输入或拒绝输入之前所做的步骤。

答案 8 :(得分:1)

在存储数据之前清理数据。通常,在没有首先清理输入的情况下,您不应该执行任何 SQL操作。您不希望自己受到SQL注入攻击。

我有点遵循这些基本规则。

  1. 仅通过POST修改SQL操作,例如INSERT,UPDATE,DELETE。永远不要去。
  2. 逃避一切。
  3. 如果您希望用户输入成为某些东西,请确保检查是否是那种东西。例如,您正在请求一个号码,然后确保它是一个号码。使用验证。
  4. 使用过滤器。清理不需要的字符。

答案 9 :(得分:1)

用户是邪恶的!

也许并非总是如此,但我的方法是立即进行全面清理以确保在我的后端附近没有任何风险。

额外的好处是,如果您在输入点清理,可以向用户提供反馈。

答案 10 :(得分:1)

假设所有用户都是恶意的。 尽快消除所有输入。 完全停止。

答案 11 :(得分:1)

在我对其进行任何处理之前,我会清理我的数据。我可能需要使用First和Last名称字段并将它们连接到第三个字段,该字段将插入到数据库中。我甚至在进行连接之前要对输入进行消毒,这样我就不会遇到任何处理或插入错误。越快越好。即使在前端使用Javascript(在Web设置中)也是理想的,因为这样就可以在没有任何数据进入服务器的情况下开始。

可怕的部分是你甚至可能想要开始清理数据库中出现的数据。最近出现的ASPRox SQL Injection攻击激增是双重致命的,因为它会感染给定数据库中的所有数据库表。如果您的数据库托管在同一数据库中托管多个帐户的某个地方,那么由于其他人的错误,您的数据会被破坏,但现在您已经加入了向您的访问者托管恶意软件的行列,因为您没有自己的初始错误

这确实可以提前完成大量的工作,但如果数据很关键,那么这是值得的投资。

答案 12 :(得分:0)

我发现立即清洁它有两个好处。一,您可以对其进行验证并向用户提供反馈。第二,你不必担心在其他地方消费数据。

答案 13 :(得分:0)

在将用户输入下放到应用程序的较低层之前,应始终将其视为恶意用户。始终尽快处理清理输入,并且在检查恶意意图之前,不应出于任何原因将其存储在数据库中。