【问题标题】:which one should performe first ? sanitizing or validation应该先执行哪一个?消毒或验证
【发布时间】:2013-10-27 11:05:18
【问题描述】:

我的注册表单中有一个字段,例如包含name 字段,它将存储在数据库中名为user_name varchar(20) 的字段中。很明显,我应该验证用户输入 如果我首先使用以下代码验证此字段:

<?php
 if(emptiy($_pos['name']) || strlen($_post['name'])>20)
 //send an not valid input error
 else{
 $name=htmlspcialchars($_post['name']);
 //check for sql injection;
 //insert name into database;}
?>

如果用户插入像&lt;i&gt; some one &lt;/i&gt; 这样的名称,则字符串长度为17,因此else 部分将执行,名称将为&amp;lt;i&amp;gt some one &amp;lt;/i&amp;gt;,长度为28,此时插入db.in 时会产生错误如果我向用户发送一个错误,说他/她的输入太长了,他会感到困惑。我该怎么办?最好的方法是什么?

【问题讨论】:

  • 您不应该在存储数据之前对其进行编码。将其原始存储(使用正确的转义,如mysqli_real_escape_string 或类似的)并在输出之前对其进行编码。这是因为如果您将其输出为 HTML 或 JSON 或其他任何内容,它需要不同的编码。
  • 停止sql注入的最佳方法是使用mysqli或PDO准备语句将数据插入数据库。@Niet the Dark Absol是正确的,但不推荐使用mysqli_real_escape_string()函数。
  • 出于安全原因,我永远不会使用像 mysqli_real escape_string() 这样的函数,我使用 pdo 更安全。
  • 我一直遵循sanitize first, then validate的方法。
  • 如果有人插入'some one',我应该将'some one'插入数据库还是先去除空格然后存储在数据库中?

标签: php validation sanitize


【解决方案1】:

一般来说,首先应该进行消毒 - “为了您和他们的保护。”这包括删除任何无效字符(当然,字符编码敏感)。如果一个字段应该只包含字符和空格,那么首先去掉所有不是的。

完成后,您可以验证结果 - 名称是否已使用(用于唯一字段)、大小是否正确、是否为空白?

您给出的原因恰恰是正确的——最大化用户体验。如果可以避免,请不要混淆用户。这有助于防止愚蠢的复制和粘贴行为,但您必须小心 - 如果我希望将我的名字记录为“Ke$h@”,我可能会也可能不会将其更改为“Keh”。

其次,也是为了防止bug。

当您想要创建不允许特殊字符的用户名时会发生什么?如果我输入“Brian”,而您的系统拒绝将其作为我们已在使用的名称,那么我提交“Brian$”?首先你验证它,它没有被使用,然后你去掉特殊字符,剩下的是“Brian”。哦,现在您要么必须再次验证,要么会收到一个奇怪的错误,即帐户创建失败(例如,如果您的数据库设置为需要唯一的用户名),或者更糟的是它会成功并覆盖/损坏发生在用户用户帐户上。

另一个例子是最小字段长度:如果你要求一个名字至少有 3 个字母长并且只接受字母,而我输入“no”你会拒绝它;但如果我输入“no@#$%”,您可能会说它是有效的(足够长),对其进行清理,现在它不再有效,等等。

避免这种情况的简单方法是先进行消毒,然后您就不必再三考虑验证了。

然而,Niet 关于在存储之前不对数据进行编码是正确的;通常,在适当的时候将输出设置为 HTML 编码要容易得多,然后记住在您只需要纯文本(输入文本框、JSON 字符串等)时对其进行解码。您将使用的大多数测试用例不会包含 HTML 实体的数据,因此很容易引入不易发现的愚蠢错误。

最大的问题是,当引入这样的错误时,它会很快导致数据损坏,不容易解决。示例:您有纯文本,将其错误地作为 html 实体输出到文本字段,表单被提交回来并重新编码……每次打开/重新提交时,它都会重新编码。对于繁忙的站点/表单,您最终可能会得到数千个不同编码的条目,而没有明确的方法来确定哪些应该和哪些不应该进行 HTML 编码。

防止注入是好的,但 HTML 编码的设计目的不是(也不能依赖)来做到这一点。

【讨论】:

  • 好的,假设您已经输入了 Brian$,首先对其进行清理,结果将是 Brian,然后验证它并且它是唯一的,好的,您知道已注册并且想要登录,您输入 Brian,然后再次在登录表单中我应该清理输入?所以如果你我应该打招呼布赖恩,你会因为你输入了布赖恩而感到困惑$
  • 您应该让用户知道您必须对输入进行清理 - 我什至会建议在这种情况下,当用户输入错误时,您会给用户一个错误无效。
  • @naazanin 我同意 gdscei,但通常我会将这些细节保存在发布客户端表单验证之前。在那里我更温和地提示用户无效输出,在服务器端我更有可能选择以下两种模型之一:1)让它工作并且如果他们不需要就不要打扰用户知道,或者 2) 拒绝无效输入并让用户弄清楚该怎么做。这将取决于您的用例,我无法提供全局建议。你的应用越国际化,你就越需要小心禁止潜在的有效字符。
  • "如果我想将我的名字记录为“Ke$h@”,我可能会也可能不会同意将其更改为“Keh”。”这就是为什么我喜欢先清理、验证,如果一切正常,我还会检查原始未修改的版本是否等于清理后的版本。如果不一样,那么我将经过清理的输入返回到表单,并带有适当的错误消息。
【解决方案2】:

不,您应该先验证。执行清理以处理作为最后一步的数据存储级别。如果业务规则没有通过验证阶段,那么接近数据存储级别是没有意义的。如果您需要一个数字并且给您一个字符串,那是一个错误,因此您将它们发送回表单。 如果您将 SQL 与准备好的语句一起使用,并且实际上会破坏输入,则不需要在需要时(从 5.4 起不需要)进行除条斜线之外的清理。

【讨论】:

    猜你喜欢
    • 2013-08-06
    • 2013-04-29
    • 1970-01-01
    • 2023-03-21
    • 1970-01-01
    • 2021-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多