preg_match在输入清理方面是否足够安全?

时间:2010-04-12 14:38:15

标签: php validation sanitization input-sanitization

我正在构建一个新的web-app,LAMP环境...我想知道preg_match是否可以信任用户的输入验证(当然+准备好的stmt)用于所有基于文本的字段(也就是HTML字段;电话,姓名,姓氏等。)。

例如,对于经典的“电子邮件字段”,如果我检查输入如下:

$email_pattern = "/^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)" .
    "|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}" .
    "|[0-9]{1,3})(\]?)$/";

$email = $_POST['email'];
if(preg_match($email_pattern, $email)){
    //go on, prepare stmt, execute, etc...
}else{
    //email not valid! do nothing except warn the user
}

我可以轻松地对抗SQL / XXS注入吗?

我认为正则表达式更具限制性。

编辑:如上所述,我确实使用了预备语句,这种行为仅适​​用于基于文本的字段(如电话,电子邮件,姓名,姓氏,等等..),所以不允许包含HTML(对于HTML字段,我使用HTMLpurifier)。

实际上,我的任务是只有在匹配我的regexp-white-list时才传递输入值;否则,将其返回给用户。

p.s::我正在寻找没有mysql_real_escape_strings的东西;可能该项目将在未来切换到Postgresql,因此需要一个跨数据库的验证方法;)

7 个答案:

答案 0 :(得分:8)

正则表达式是否足以进行过滤取决于正则表达式。如果您要在SQL语句中使用该值,则正则表达式必须以某种方式禁止'"。如果您想使用HTML输出中的值并且害怕XSS,则必须确保您的正则表达式不允许<>"

尽管如此,已经反复说过,你做想依靠正则表达式,并且请亲爱的神,请不要!在HTML上下文中打印时,使用 mysql_real_escape_string() prepared statements表示您的SQL语句, htmlspecialchars() 表示您的值。

根据其背景选择消毒功能。作为一般的经验法则,它比你更了解什么是什么,什么不危险。


编辑,以适应您的编辑:

数据库

准备好的语句== mysql_real_escape_string()关于要放入的每个值。基本上完全相同的事情,没有在准备好的语句变体中提升性能,并且无法意外忘记使用对其中一个值起作用。准备好的语句可以保护你免受SQL注入,而不是正则表达式。你的正则表达式可以是任何东西,它对准备好的陈述没有任何影响。

您不能也不应该尝试使用正则表达式来构建“跨数据库”架构。同样,通常系统比你更了解它的危险性和危害性。准备好的陈述是好的,如果这些陈述与变化兼容,那么你可以轻松入睡。没有正则表达式。

如果他们不是,你必须使用抽象层到你的数据库,比如自定义 $ db-&gt; escape(),你的MySQL体系结构映射到 mysql_real_escape_string ()并在你的PostgreSQL架构中映射到PostgreSQL的相应方法(我不知道哪个是副手,抱歉,我没有使用PostgreSQL)。

HTML

HTML Purifier是一种清理HTML输出的好方法(假设你在白名单模式下使用它,这是它附带的设置),但你应该只在你绝对需要保留HTML的东西上使用它,因为调用 purify()是非常昂贵的,因为它解析整个事物并以旨在彻底性和通过强大的规则集的方式操纵它。因此,如果您不需要保留HTML,则需要使用 htmlspecialchars()。但是,在这一点上,你的正则表达式与你的逃避无关,可能是任何事情。

安全旁注

  

实际上,我的任务是通过   仅当输入值与我的匹配时才输入   正则表达式,白名单;否则,退货吧   回到用户。

这可能不适用于您的场景,但仅作为一般信息:“将错误输入返回给用户”的理念可能会导致您受到reflected XSS攻击。用户并不总是攻击者,因此在将内容返回给用户时,请确保将其全部撤销。请记住一些事情。

答案 1 :(得分:5)

对于SQL注入,您应该始终使用mysql_real_escape_string之类的正确转义。最好的方法是使用prepared statements(甚至是ORM)来防止遗漏。  你已经做过了。

其余的取决于您的应用程序的逻辑。您可以过滤HTML以及验证,因为您需要正确的信息,但我不进行验证以防止XSS,我只进行业务验证*。

一般规则是“过滤/验证输入,转义输出”。所以我逃避了我显示的内容(或传输给第三方)以防止HTML标记,而不是我记录的内容。

*但是,某个人的姓名或电子邮件地址不应包含< >

答案 2 :(得分:3)

验证与使输入数据符合特定应用程序的预期值有关。

注射与获取原始文本字符串并将其放入不同的上下文而没有合适的 Escaping

它们是两个完全独立的问题,需要在不同的阶段单独查看。读取输入时(通常在脚本开头),需要进行验证;在将文本插入到诸如SQL字符串文字,HTML页面或任何其他某些字符具有带外含义的上下文的上下文中时,需要进行转义。

您不应该混淆这两个过程,并且不能同时处理这两个问题。 “消毒”这个词意味着两者的混合,因此本身就是立即怀疑的。输入不应“消毒”,应根据应用的特定需求进行验证。稍后,如果将它们转储到HTML页面中,它们应该在出路时进行HTML转义。

在脚本开头的所有用户输入中运行SQL或HTML转义是一个常见的错误。即使是以“安全”为重点的教程(由傻瓜编写)也经常建议这样做。结果总是一团糟 - 有时候仍然很脆弱。

以电话号码字段为例,虽然确保字符串只包含数字,但肯定也能保证它不能用于HTML注入,这是一个你不应该依赖的副作用。输入阶段应该只需要知道电话号码,而不是HTML中的特殊字符。 HTML模板输出阶段应该只知道它有一个字符串(因此应该始终在其上调用htmlspecialchars()),而不必知道它只包含数字。

顺便说一下,这是一个非常糟糕的电子邮件验证正则表达式。无论如何,正则表达式不是一个很好的电子邮件验证工具;要正确执行absurdly difficult,但是这个地址会拒绝许多完全有效的地址,包括用户名中+的任何地址,.museum.travel中的任何地址IDNA域名。最好是通过电子邮件地址自由。

答案 3 :(得分:2)

NO。

NOOOO。

NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO。

DO。不。使用。正则表达式。对于。这个。 EVER。

RegEx to Detect SQL Injection

Java - escape string to prevent SQL injection

答案 4 :(得分:1)

在将数据插入数据库之前,您仍希望转义数据。虽然验证用户输入是一件很聪明的事情,但是针对SQL注入的最佳保护是使用数据库的本机转义功能准备语句(自动转义数据)或转义它。

答案 5 :(得分:1)

有php函数mysql_real_escape_string(),我相信你应该在提交到mysql数据库之前使用它才能安全。 (此外,它更容易阅读。)

答案 6 :(得分:1)

如果你对正则表达式有好处:是的。 但是阅读你的电子邮件验证regexp,我必须回答否。

最好的方法是使用filter函数来相对安全地获取用户输入,并在这些函数中找到损坏的情况下让您的PHP更新。 当您有原始输入时,您必须添加一些内容,具体取决于您对这些数据的处理方式:删除电子邮件和http标头的\ n和\ r \ n,删除要显示给用户的html标记,使用参数化查询将其与数据库中。