5

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

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

$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 匹配时才让其传递;否则,将其返回给用户。

ps: : 我正在寻找没有 mysql_real_escape_strings 的东西;可能该项目将来会切换到Postgresql,所以需要一个跨数据库的验证方法;)

4

7 回答 7

8

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

尽管如此,正如反复说过的那样,您不想依赖正则表达式,请看在 $deity 的份上,不要!在 HTML 上下文中打印时,对 SQL 语句使用mysql_real_escape_string()准备好的语句,对值使用htmlspecialchars()

根据上下文选择消毒功能。作为一般的经验法则,它比你更清楚什么是危险的,什么不是危险的。


编辑,以适应您的编辑:

数据库

准备好的语句 == mysql_real_escape_string()在要输入的每个值上。本质上完全相同,只是在准备好的语句变体中没有性能提升,并且不会意外忘记在其中一个值上使用该函数。准备好的语句是保护你免受 SQL 注入的东西,而不是正则表达式。你的正则表达式可以是任何东西,它对准备好的语句没有任何影响。

您不能也不应该尝试使用正则表达式来适应“跨数据库”架构。同样,通常系统比您更清楚什么是危险的,什么不危险。准备好的陈述很好,如果这些与更改兼容,那么您可以高枕无忧。没有正则表达式。

如果它们不是并且您必须使用抽象层到您的数据库,类似于自定义$db->e​​scape(),它在您的 MySQL 架构中映射到mysql_real_escape_string()并且在您的 PostgreSQL 架构中映射到 PostgreSQL 的相应方法(我不知道哪个会是临时的,抱歉,我没有使用过 PostgreSQL)。

HTML

HTML Purifier 是清理 HTML 输出的好方法(前提是您在白名单模式下使用它,这是它附带的设置),但您应该只在绝对需要保留 HTML 的地方使用它,因为调用purify( )是相当昂贵的,因为它解析整个事物并以旨在彻底性和通过一组强大的规则的方式对其进行操作。因此,如果您不需要保留 HTML,则需要使用htmlspecialchars()。但是,再次,在这一点上,您的正则表达式与您的转义无关,并且可以是任何东西。

安全旁注

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

这可能不适用于您的场景,但就像一般信息一样:“将错误输入返回给用户”的理念可能会使您面临反射 XSS攻击的风险。用户并不总是攻击者,因此在将东西返回给用户时,请确保您完全逃脱它。只是要记住的事情。

于 2010-04-12T14:45:03.073 回答
5

对于 SQL 注入,您应该始终使用正确的转义符,例如mysql_real_escape_string. 最好的办法是使用准备好的语句(甚至是 ORM)来防止遗漏。 你已经做了那些。

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

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

* 尽管如此,一个人的姓名或电子邮件地址不应包含< >

于 2010-04-12T14:42:31.523 回答
3

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

注入与获取原始文本字符串并将其放入不同的上下文有关,而无需适当的Escaping

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

你不应该把这两个过程混为一谈,你不能同时处理这两个问题。“消毒”一词意味着两者的混合,因此本身就很可疑。输入不应被“净化”,它们应根据应用程序的特定需求进行验证。稍后,如果它们被转储到 HTML 页面中,它们应该在退出时进行 HTML 转义。

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

以电话号码字段为例,在确保字符串仅包含数字的同时,当然也可以保证它不能用于 HTML 注入,这是您不应该依赖的副作用。输入阶段应该只需要知道电话号码,而不需要知道 HTML 中的特殊字符。HTML 模板输出阶段应该只知道它有一个字符串(因此应该总是调用htmlspecialchars()它),而不必知道它只包含数字。

顺便说一句,这是一个非常糟糕的电子邮件验证正则表达式。无论如何,Regex 并不是一个很好的电子邮件验证工具。正确地做到这一点是非常困难的,但是这个会拒绝很多完全有效的地址,包括+用户名中的任何地址,任何IDNA 域中的任何一个或任何一个.museum.travel最好是自由地使用电子邮件地址。

于 2010-04-12T14:57:25.763 回答
2

不。

不。

不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不不!

做。不是。采用。正则表达式。为了。这。曾经。

正则表达式检测 SQL 注入

Java - 转义字符串以防止 SQL 注入

于 2010-04-12T14:42:11.317 回答
1

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

于 2010-04-12T14:39:53.787 回答
1

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

于 2010-04-12T14:42:11.660 回答
1

如果你擅长正则表达式:是的。但是阅读您的电子邮件验证正则表达式,我不得不回答否。

最好的方法是使用过滤器函数来相对安全地获取用户输入,并让您的 php 更新,以防在这些函数中发现有问题。当您有原始输入时,您必须根据您对这些数据所做的操作添加一些内容:删除电子邮件和 http 标头的 \n 和 \r,删除要显示给用户的 html 标签,使用参数化查询将其与数据库。

于 2010-04-12T15:02:56.850 回答