我的注册表单中有一个字段,其中包含一个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;}
?>
如果用户插入类似<i> some one </i>
的名称,则字符串长度为17,因此else部分将执行,名称将为<i> some one </i>
,其长度为28,在插入db时将产生错误。在这个时候,如果我向用户发送错误,他/她的输入太长,他会感到困惑。我该怎么办?什么是最好的方法?
答案 0 :(得分:6)
一般来说,人们应首先消毒 - “为了你的保护,还有他们的保护。”这包括剥离任何无效字符(当然,字符编码敏感)。如果一个字段应该只包含字符和空格,那么就去掉那些不是第一个字段和空格。
完成后,然后验证结果 - 是否已使用的名称(对于唯一字段),是否为正确的大小,是否为空白?
您提供的原因恰恰是正确的 - 最大化用户体验。如果可以避免,请不要混淆用户。这有助于防止哑巴副本和粘贴行为,但你必须小心 - 如果我希望我的名字记录为“Ke $ h @”,我可能会或可能不会将其更改为“Keh”。
其次,它也是为了防止错误。
当您想要创建不允许使用特殊字符的用户名时会发生什么?如果我输入“Brian”,并且您的系统拒绝它作为我们已经使用的名称,那么我提交“Brian $”?首先你验证它,它没有被使用,然后你删除特殊字符,你留下“布莱恩”。哦哦 - 现在你要么必须验证AGAIN,否则你会得到一个奇怪的错误:帐户创建失败(例如,如果你的数据库设置为需要唯一的用户名),或者更糟糕的是它会成功并覆盖/腐败用户用户帐户。
另一个例子是最小字段长度:如果你要求一个名字长至少3个字母并且只接受字母,我输入“否”你就拒绝它;但如果我输入“no @#$%”,你可能会说它有效(足够长),消毒它,现在它已经无效了等等。
避免这种情况的简单方法是首先进行消毒,然后您不必再考虑验证。
但是,Niet在存储之前不对数据进行编码是正确的;在适当的时候将输出设置为HTML通常要容易得多,然后在你只想要纯文本(进入文本框,JSON字符串等)时记住解码它。您将使用的大多数测试用例都不包含HTML实体的数据,因此很容易引入不易被捕获的愚蠢错误。
最大的问题是,当引入这样的错误时,它很快就会导致数据损坏,而且不容易解决。示例:您有纯文本,将其作为html实体错误地输出到文本字段,表单被提交回来并重新编码...每次打开/重新提交时,它都会被重新编码。使用繁忙的站点/表单,您最终可能会有数千个不同编码的条目,而没有明确的方法来确定哪些应该是什么以及哪些不是HTML编码。
保护注入是好的,但HTML编码并非设计(并且不得依赖)。
答案 1 :(得分:2)
不,你应该先验证。执行清理以处理数据存储级别,这是最后一步。如果业务规则未通过验证阶段,则无法接近数据存储级别。如果您需要一个数字并且您有一个字符串,那就是错误,因此您将它们发送回表单。 如果您将SQL与预处理语句一起使用,并且实际上会损坏输入,则在必要时进行除垢(如果需要,除了5.4之外不需要)。