9

i have a field in my registration form that contains for instance a name field,it will be stored in database in a field called user_name varchar(20). it's clear that i should validate the user input if i validate this field frist with code below:

<?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;}
?>

if a user insert a name like <i> some one </i> the string length is 17 so the else part will performe and name will be &lt;i&gt some one &lt;/i&gt; which the length is 28 that will produce an error while inserting to db.in this time if i send an error to user that his/her input is too longe he will got confused. what should i do? what is the best approach?

4

2 回答 2

8

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

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

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

其次,也是为了防止bug。

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

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

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

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

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

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

于 2013-10-18T14:57:09.273 回答
3

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

于 2014-12-25T08:31:04.887 回答