13

我在用于人名的正则表达式中遇到了一些问题。

$rexName = '/^[a-z' -]$/i';

假设一个名为 Jürgen 的用户想要注册?还是鲍勃?这在欧洲很常见。这有什么特殊的符号吗?

编辑:,只是将 Jürgen 的名字扔给了一个正则表达式的创建者,它在 ü 字母处拆分了这个词......

http://www.txt2re.com/index.php3?s=J%FCrgen+Blalock&submit=Show+Matches

EDIT2:好吧,既然检查这些特定的东西很困难,为什么不使用一个简单地检查非法字符的正则表达式呢?

$rexSafety = "/^[^<,\"@/{}()*$%?=>:|;#]*$/i";

(现在哪些实际上可以用于任何黑客攻击?)

例如。这允许 ' 和 - 符号,但你需要一个 ; 使其在 SQL 中工作,并且那些将被停止。我缺少的通常用于 HTML 注入 SQL 攻击的任何其他字符?

4

4 回答 4

20

我真的想说:不要尝试验证名称:总有一天,你的代码会遇到一个它认为“错误”的名称......当应用程序告诉他“你的名字”时,你认为人们会如何反应无效“?

根据您真正想要实现的目标,您可能会考虑使用某种黑名单/过滤器,以排除您想到的“非名字”:它可能会让一些“坏名字”通过,但至少,它不应阻止任何现有名称访问您的应用程序。

以下是一些想到的规则示例:

  • 没有号码
  • 没有特殊字符,比如"~{()}@^$%?;:/*§£ø可能还有其他一些
  • 没有更多的3个空格?
  • 没有“管理员”、“支持”、“版主”、“测试”以及人们在不想输入真实姓名时倾向于使用的其他一些明显的非名称......
    • (但是,如果他们不想给你他们的名字,他们仍然不会,即使你禁止他们输入一些随机字母,他们也可以使用真实姓名......这不是他们的)

是的,这并不完美;是的,它会让一些非名字通过......但是对于你的应用程序来说,这可能比说某人“你的名字错了”要好得多(是的,我坚持 ^^)


而且,要回答您在另一个答案下留下的评论:

我可以禁止大多数命令字符用于 SQL 注入和 XSS 攻击,

关于 SQL 注入,您必须先对数据进行转义,然后再将其发送到数据库;而且,如果您总是转义这些数据(您应该!),您不必关心用户可能输入或不输入的内容:因为它被转义,所以始终对您没有风险。

XSS 也是如此:因为您在输出数据时总是会转义数据(您应该!),因此没有注入风险;-)


编辑:如果你只是像那样使用那个正则表达式,它就不会很好地工作:

以下代码:

$rexSafety = "/^[^<,\"@/{}()*$%?=>:|;#]*$/i";
if (preg_match($rexSafety, 'martin')) {
    var_dump('bad name');
} else {
    var_dump('ok');
}

至少会给你一个警告:

Warning: preg_match() [function.preg-match]: Unknown modifier '{'

您必须至少逃脱其中一些特殊字符;我会让你深入了解PCRE 模式以获取更多信息(关于 PCRE / regex 真的有很多要了解的;我无法解释这一切)

如果您真的想检查这些字符是否在给定的数据中,您可能会得到类似的结果:

$rexSafety = "/[\^<,\"@\/\{\}\(\)\*\$%\?=>:\|;#]+/i";
if (preg_match($rexSafety, 'martin')) {
    var_dump('bad name');
} else {
    var_dump('ok');
}

(这是一个快速而肮脏的命题,必须精炼!)

这个说“OK” (好吧,我绝对希望我自己的名字没问题!)
还有一些特殊字符的相同示例,如下所示:

$rexSafety = "/[\^<,\"@\/\{\}\(\)\*\$%\?=>:\|;#]+/i";
if (preg_match($rexSafety, 'ma{rtin')) {
    var_dump('bad name');
} else {
    var_dump('ok');
}

会说“坏名声”

但请注意,我还没有完全测试这个,它可能需要更多的工作!除非您非常仔细地测试过,否则不要在您的网站上使用它!


另请注意,在尝试执行 SQL 注入时,单引号可能会有所帮助...但它可能是在某些名称中合法的字符...因此,仅排除某些字符可能还不够 ;-)

于 2009-08-11T16:24:19.573 回答
7

PHP 的 PCRE 实现支持跨越更大字符集的Unicode 字符属性。所以你可以使用\p{L}(字母字符)、\p{P}(标点符号)和\p{Zs}(空格分隔符)的组合:

/^[\p{L}\p{P}\p{Zs}]+$/

但是这些字符类别可能未涵盖某些字符,而可能包含一些您不希望被允许的字符。

因此,我建议您不要在具有如此模糊的值范围(例如真实人名)的数据上使用正则表达式。


编辑   当您编辑您的问题时,现在看到您只想阻止某些代码注入攻击:您应该更好地转义这些字符,而不是将它们作为潜在的攻击尝试而拒绝。

为 SQL 查询、HTML 输出和其他语言的其他适当功能使用mysql_real_escape_string准备语句。htmlspecialchars

于 2009-08-11T16:17:24.593 回答
4

这是一个没有简单通用解决方案的问题。问题是您真的无法预测名称可能包含哪些字符。可能最好的解决方案是定义一个否定字符掩码,以排除一些您真的不想以名称结尾的特殊字符。

您可以使用以下方法执行此操作:

$regexp = "/^[ ^ <把不需要的字符放在这里> ]+$/

于 2009-08-11T16:06:48.233 回答
2

If you're trying to parse apart a human name in PHP, I recomment Keith Beckman's nameparse.php script.

于 2009-11-01T02:28:56.897 回答