验证签名用拦截器还是过滤器
I’d like to start off this article by thanking you for making it even this far. I’m fully aware that “Input Validation Using Filter Functions” isn’t exactly the sexiest article title in the world!
在此开始,我要感谢您到目前为止所做的一切。 我完全意识到,“使用过滤器功能进行输入验证”并不是世界上最性感的文章标题!
Filter functions in PHP might not be sexy, but they can improve the stability, security, and even maintainability of your code if you learn how to use them correctly.
PHP中的过滤器功能可能并不吸引人,但是如果您学习如何正确使用它们,它们可以提高代码的稳定性,安全性甚至可维护性。
In this article I’ll explain why input validation is important, why using PHPs built-in functions for performing input validation is important, and then throw together some examples (namely using filter_input()
and filter_var()
), discuss some potential pitfalls, and finish with a nice, juicy call to action. Sound good? Let’s go!
在本文中,我将解释为什么输入验证很重要,为什么使用PHP的内置函数执行输入验证很重要,然后汇总一些示例(即使用filter_input()
和filter_var()
),讨论一些潜在的陷阱,并以优美,多汁的号召性用语结束。 听起来不错? 我们走吧!
为什么输入验证很重要 (Why Input Validation is Important)
Input validation is one of the most important things you can do to ensure code security because input is often times the one thing about your application you cannot directly control. Because you cannot control it, you cannot trust it.
输入验证是确保代码安全性最重要的事情之一,因为输入通常是您无法直接控制的一件事。 因为您无法控制它,所以您不能信任它。
Unfortunately, as programmers we often write things thinking only of how we want them to work. We don’t consider how someone else might want to make them work – either out of curiosity, ignorance, or malice.
不幸的是,作为程序员,我们经常只考虑我们希望他们如何工作而编写东西。 我们不考虑出于好奇,无知或恶意,别人可能希望他们如何工作。
I am not going to go into too much detail about the trouble you can get into if you do not validate user input; there’s a really good article on this very site called PHP Security: Cross-Site Scripting Attacks if you want to read up on it. But I will say that validating your input is the first step to ensuring that the code you have written will be executed as intended.
如果您不验证用户输入,将不会遇到太多麻烦,我将不做过多介绍。 如果您想阅读该站点上的一篇非常好的文章,名为《 PHP安全性:跨站点脚本攻击》 。 但是我要说的是,验证输入是确保所编写的代码将按预期执行的第一步。
Maybe you are coming to PHP from another language and you might be thinking, “this was never an issue before so why should I care?” The reason validation is an issue is because PHP is loosely typed. This makes PHP great for some things, but it can make things like data validation a little bit trickier because you can pretty much pass anything to anything.
也许您是从另一种语言来学习PHP的,并且您可能在想:“这以前从来都不是问题,所以我为什么要关心呢?” 验证是一个问题的原因是因为PHP是松散类型的。 这使PHP在某些方面非常有用,但是它会使诸如数据验证之类的事情变得有些棘手,因为您几乎可以将任何东西传递给任何东西。
为什么使用内置方法很重要 (Why Using Built-in Methods is Important)
In order to try and make validation a little bit easier, from PHP 5.2.0 onward we can now use the filter_input()
and filter_var()
functions. I’ll talk about them in more detail soon, but first I want to talk about why we should be using PHP provided functionality instead of relying our own methods or third-party tools.
为了使验证更容易一些,从PHP 5.2.0开始,我们现在可以使用filter_input()
和filter_var()
函数。 我将在稍后详细讨论它们,但首先,我想谈论为什么我们应该使用PHP提供的功能,而不是依赖我们自己的方法或第三方工具。
When you roll your own validation methods, you generally fall into the same trap that you can fall into when designing other functionality: you think about the edge cases you want to think about, not necessarily all of the different vectors that could be used to disguise certain input. Another issue is, if you are anything like me, the first 10 minutes of any code review dealing with hand-rolled validation code is spent tutting because the programmer didn’t do exactly what you would have done. This can lead to programmers spending more time learning the codebase and reading internal documentation that could instead be spent coding.
当您使用自己的验证方法时,通常会陷入与设计其他功能时可能会陷入的陷阱:您考虑要考虑的边缘情况,而不必考虑所有可能用于伪装的向量某些输入。 另一个问题是,如果您像我一样,则在处理手动滚动验证代码的任何代码审查的前10分钟都花在了学习上,因为程序员没有完全按照您的意愿去做。 这可能导致程序员花费更多时间来学习代码库和阅读可能用于编码的内部文档。
Some people don’t roll their own, but instead opt for a third-party solution. There are some good ones out there, and in the past I have used OWASP ESAPI for some extra validation. These are better than perhaps the hand-rolled solutions because more eyes have looked over them, but then you have the issue of introducing third-party code into your project. Again, this increases time spent learning a codebase and reading additional documentation instead of coding.
有些人不会自己动手,而是选择第三方解决方案。 有一些不错的选择,过去我使用OWASP ESAPI进行了一些额外的验证。 这些方法比手动解决方案要好,因为它们吸引了更多的目光,但是您遇到了将第三方代码引入项目的问题。 同样,这会增加花费在学习代码库和阅读其他文档而不是编码上的时间。
For these reasons, using native functions are better; moreover, because such functions are baked into the language, it means we have one place to go for all PHP documentation. New developers will have a greater chance of knowing what the code is and how best to use it. It will be easier to support as a result of this.
由于这些原因,使用本机函数会更好。 而且,由于这些函数已嵌入到语言中,因此这意味着所有PHP文档都只有一个地方。 新的开发人员将有更多的机会了解代码是什么以及如何最好地使用它。 因此,将更易于支持。
Hopefully by now I have you convinced that validation is important, and that it would be a good idea to use PHP functions to help you achieve your validation needs. If you are not convinced, leave a comment and let’s discuss it.
希望到目前为止,我已经使您确信验证很重要,并且使用PHP函数来帮助您满足验证需求将是一个好主意。 如果您不满意,请发表评论并进行讨论。
一些例子 (Some Examples)
The filter_input() function was introduced in PHP 5.2.0 and allows you to get an external variable by name and filter it. This is incredibly useful when dealing with $_GET
and $_POST
data.
filter_input()函数是PHP 5.2.0引入的,它允许您通过名称获取外部变量并对其进行过滤。 在处理$_GET
和$_POST
数据时,这非常有用。
Let’s take as an example a simple page that reads a value passed in from the URL and handles it. We know this value should be an integer between 15 and 20. One way of doing would be something like:
让我们以一个简单的页面为例,该页面读取从URL传入的值并进行处理。 我们知道该值应该是15到20之间的整数。一种处理方式是:
<?php
if (isset($_GET["value"])) {
$value = $_GET["value"];
}
else {
$value = false;
}
if (is_numeric($value) && ($value >= 15 && $value <= 20)) {
// run my code
}
else {
// handle the issue
}
This is a really basic example and already we are writing more lines that I would like to see.
这是一个非常基本的示例,并且我们已经在编写更多我希望看到的行。
First, because we can’t be sure $_GET
is set, the code performs an appropriate check so that the script doesn’t fall over.
首先,由于我们不确定是否设置了$_GET
,因此代码将执行适当的检查,以使脚本不会掉下来。
Next is the fact that $value
is now a “dirty” variable because it has been directly assigned from a $_GET
value. We would need to take care not to use $value
anywhere else in the code in case we break anything.
接下来的事实是, $value
现在是一个“脏”变量,因为它是直接从$_GET
值分配的。 我们需要注意不要在代码的其他任何地方使用$value
,以防我们破坏任何东西。
Then there is the issue that 16.0 is valid because is_numeric()
okays it.
然后存在一个问题,即16.0有效,因为is_numeric()
可以。
And finally, we have an issue with the fact that the if
statement is a bit of a mouthful to take in and is an extra bit of logic to work through when you are tracing through the code.
最后,我们有一个问题,那就是if
语句有点麻烦,并且在您遍历代码时需要额外的逻辑。
Compare the above example now to this:
现在比较上面的示例:
<?php
$value = filter_input(INPUT_GET, "value", FILTER_VALIDATE_INT,
array("options" => array("min_range" => 15, "max_range" => 20)));
if ($value) {
// run my code
}
else {
// handle the issue
}
Doesn’t that make you feel warm and fuzzy?
那不是让你感到温暖和模糊吗?
filter_input()
handles the $_GET
value not being set, so you don’t have to stress over whether the script is receiving the correct information or not.
filter_input()
处理未设置的$_GET
值,因此您不必强调脚本是否正在接收正确的信息。
You also don’t have to worry about $value
being dirty because it has been validated before it has been assigned.
您也不必担心$value
变脏,因为在赋值之前已经对其进行了验证。
Note now that 16.0 is no longer valid.
现在注意16.0不再有效。
And finally, our logic is no longer complicated. It’s just a quick check for a truthy value (filter_input()
will return false if the validation fails and null if $_GET["value"]
wasn’t set).
最后,我们的逻辑不再复杂。 这只是对真实值的快速检查(如果验证失败, filter_input()
将返回false;如果未设置$_GET["value"]
,则返回null)。
Obviously in a real world setting you could extract the array out into a variable stored in a configuration file somewhere so things can get changed without even needing to go into business logic. Gorgeous!
显然,在现实世界中,您可以将阵列提取到存储在配置文件中某个位置的变量中,从而无需更改业务逻辑即可进行更改。 华丽!
Now you might be thinking that this might be useful for simple scripts that grab a couple of $_GET
or $_POST
variables, but what about for use inside of functions or classes? Luckily we have filter_var() for that.
现在您可能会认为,这对于捕获几个$_GET
或$_POST
变量的简单脚本可能很有用,但是在函数或类内部使用呢? 幸运的是我们有filter_var() 。
The filter_var()
function was introduced at the same time as filter_input()
and does much the same thing.
filter_var()
函数是与filter_input()
同时引入的,其作用大致相同。
<?php
// This is a sample function, do not use this to actually email,
// that would be silly.
function emailUser($email) {
mail($email, "Here is my email", "Some Content");
}
The danger here is that is there nothing to stop the mail()
function from attempting to send an email to literally any value that could be stored in $email
. This could lead to emails not getting sent, or something getting in that can potentially use the function for malicious intent in a worst case scenario.
这里的危险在于,没有什么可以阻止mail()
函数尝试将电子邮件发送给实际上可以存储在$email
任何值。 在最坏的情况下,这可能导致电子邮件无法发送,或者进入某些内容可能会将该功能用于恶意目的。
I have seen people do a check on the result of mail()
, which is fine to see if the function completed successfully, but by the time a value is returned the damage is done.
我见过人们检查mail()
的结果,可以很好地查看函数是否成功完成,但是到返回值时损坏已经完成。
Something like this is much more sane:
这样的事情更加理智:
<?php
// This is a sample function, do not use this to actually email,
// that would be silly.
function emailUser($email) {
$email = filter_var($email, FILTER_VALIDATE_EMAIL);
if ($email !== false) {
mail($email, "Here is my email", "Some Content");
}
else {
// handle the issue invalid email address
}
}
The problem with a lot of examples, the above included, is that they are basic. You might be thinking that filter_var()
or filter_input()
can’t be used for anything other than basic checking. The fine folks who introduced these functions considered that and allow you to pass in a filter to these functions called FILTER_CALLBACK
.
上面包含的许多示例的问题在于它们是基本的。 您可能会认为filter_var()
或filter_input()
只能用于基本检查。 介绍了这些功能的高级人员认为这是允许您将过滤器传递给称为FILTER_CALLBACK
这些功能。
FILTER_CALLBACK
allows you to pass in a function you have created that will accept as the input the variable being filtered – this is where you can start to have a lot of fun because you can start applying your own business logic to your filtering.
FILTER_CALLBACK
允许您传入一个已创建的函数,该函数将接受要过滤的变量作为输入–在这里,您可以开始玩得很开心,因为您可以开始将自己的业务逻辑应用于过滤。
一些潜在的陷阱 (Some Potential Pitfalls)
These functions are pretty great, and they allow you to do some really powerful filtering, which as we have discussed can help improve the security and reliability of your code. There are some potential drawbacks however and I would feel that I was remiss if I didn’t point them out.
这些功能非常好,它们使您可以执行一些真正强大的过滤,正如我们所讨论的,这些过滤可以帮助提高代码的安全性和可靠性。 但是,存在一些潜在的缺点,如果我不指出这些缺点,我会感到很失落。
The main pitfall is that the functions are only as good as the filter you apply to it. Take the last example using email validation – how FILTER_VALIDATE_EMAIL
handles email addresses has changed between 5.2.14 and 5.3.3, and even assuming all your applications run on the same version of PHP there are email addresses that are technically valid that you might not expect. Be sure you know about the filters you are using.
主要的陷阱是这些功能仅与应用于它的过滤器一样好。 以使用电子邮件验证的最后一个示例为例, FILTER_VALIDATE_EMAIL
处理电子邮件地址的方式在5.2.14和5.3.3之间发生了变化,即使假设您所有的应用程序都在相同版本PHP上运行,在技术上也可能没有您期望的电子邮件地址。 确保您了解所使用的过滤器。
The second pitfall is that people think that if they put in some filters then their code is secure. Filtering your variables goes some way to helping, but it doesn’t make your code 100% safe from abuse. I would love to talk more about this, but that is out of the scope of this article and my word count is already pretty high!
第二个陷阱是人们认为,如果放入一些过滤器,则其代码是安全的。 过滤变量可以起到一定的帮助作用,但是并不能使您的代码100%免受滥用。 我想谈谈更多这一点,但这超出了本文的范围,我的字数已经很高!
结论 (Conclusion)
Hopefully you have found this introduction to input validation in PHP useful. And now, time for a call to action!
希望您发现PHP的输入验证入门非常有用。 现在,是时候采取行动了!
I want you to take one function in your code, just one, and see what happens to it when you pass in different data types and different values. Then I want you to apply some of the filtering methods discussed here and see if there is a difference in how your code performs. I would love to know how you got on in the comments.
我希望您在代码中只使用一个函数,然后看看当您传入不同的数据类型和不同的值时会发生什么。 然后,我希望您应用这里讨论的一些过滤方法,看看代码的执行方式是否有所不同。 我很想知道您在评论中的情况。
Image via Chance Agrella / Freerangestock.com
图片来自Chance Agrella / Freerangestock.com
翻译自: https://www.sitepoint.com/input-validation-using-filter-functions/
验证签名用拦截器还是过滤器