这两种功能是否过度杀菌?

时间:2010-05-30 19:47:42

标签: php mysql security xss

function sanitizeString($var)
{
    $var = stripslashes($var);
    $var = htmlentities($var);
    $var = strip_tags($var);
    return $var;
}

function sanitizeMySQL($var)
{
    $var = mysql_real_escape_string($var);
    $var = sanitizeString($var);
    return $var;
}

我从书中得到了这两个函数,作者说通过使用这两个函数,我可以更加安全地对抗XSS(第一个函数)和sql注入(第二个函数)。 这些都是必要的吗?

另外,对于清理,我使用预准备语句来防止sql注入。

我会像这样使用它:

$variable = sanitizeString($_POST['user_input']);
$variable = sanitizeMySQL($_POST['user_input']);

编辑:为第一个功能摆脱strip_tags,因为它没有做任何事情。 使用这两个功能是否足以阻止大多数攻击并且对公共站点没问题?

7 个答案:

答案 0 :(得分:10)

老实说,我认为这些函数的作者要么不知道XSS和SQL注入是什么,或者使用的函数到底是什么。

仅举两个奇怪之处:<​​/ p>

此外:通常,再次保护XSS的功能不适合再次保护SQL注入,反之亦然。因为每种语言和语境都有自己需要处理的特殊字符。

我的建议是了解代码注入的原因和方式,以及如何防范它。了解您正在使用的语言,尤其是特殊字符以及如何逃避这些语言。


编辑以下是一些(可能是奇怪的)示例:想象一下,您允许您的用户输入一些值,这些值应该用作您在{{{{{}中的某些JavaScript代码中使用的URI中的路径段1}}属性值。因此语言上下文如下所示:

  • HTML属性值
    • JavaScript字符串
      • URI路径段

并使其更有趣:您将此输入值存储在数据库中。

现在要将此输入值正确地存储到数据库中,您只需要对要将该值插入数据库语言(即SQL)的上下文使用正确的编码;其余的并不重要(还)。由于您要将其插入到SQL字符串声明中,因此上下文特殊字符是允许您更改该上下文的字符。至于字符串声明,这些字符(特别是)需要转义的onclick"'字符。但正如已经说过的那样,准备好的语句可以帮助您完成所有工作,所以请使用它们。

现在您拥有数据库中的值,我们希望正确输出它们。在这里,我们从最内层到最外层的上下文,并在每个上下文中应用适当的编码:

  • 对于 URI路径段上下文,我们需要转义(至少)所有允许我们更改该上下文的字符;在这种情况下\(保留当前路径段),/?(都保留URI路径上下文)。我们可以使用rawurlencode
  • 对于 JavaScript字符串上下文,我们需要处理#"'。我们可以使用json_encode(如果有)。
  • 对于 HTML属性值,我们需要处理\&"'。我们可以使用htmlspecialchars

现在一切都在一起:

<

如果'… onclick="'.htmlspecialchars('window.open("http://example.com/'.json_encode(rawurlencode($row['user-input'])).'")').'" …' $row['user-input'],则输出为:

"bar/baz"

但是在这些背景下使用所有这些功能并不是一种矫枉过正。因为虽然上下文可能具有相似的特殊字符,但它们具有不同的转义序列。 URI具有所谓的百分比编码,JavaScript具有… onclick="window.open(&quot;http://example.com/&quot;%22bar%2Fbaz%22&quot;&quot;)" … 之类的转义序列,HTML具有\"之类的字符引用。并且不仅仅使用其中一个函数就可以打破上下文。

答案 1 :(得分:5)

确实如此,但这种逃避水平可能不适合所有情况。如果要将HTML存储在数据库中该怎么办?

最佳实践要求,不要在接收值时转义,而应在显示它们时将其转义。这允许您考虑显示来自数据库的HTML和来自数据库的非HTML,并且它确实是这种代码在逻辑上属于的地方。

清理传出HTML的另一个优点是可以发现新的攻击媒介,在这种情况下,对传入的HTML进行清理将不会对数据库中已有的值执行任何操作,而传出的清理将追溯应用而无需执行任何操作特别

另请注意,如果strip_tags<已成为>&lt;,则第一个函数中的&gt;可能无效

答案 2 :(得分:3)

您正在执行htmlentities(将所有>转换为&gt;)然后调用strip_tags,此时此操作将无法完成,因为没有标签。

答案 3 :(得分:2)

如果您正在使用预准备语句和SQL占位符,并且从不直接将用户输入插入到SQL字符串中,则可以完全跳过SQL清理。

使用占位符时,SQL语句(SELECT foo, bar, baz FROM my_table WHERE id = ?)的结构将与(最终)绑定到占位符的数据值分开发送到数据库引擎。这意味着,除非数据库引擎中存在重大错误,否则绝对没有办法将数据值误解为SQL指令,因此这提供了对SQL注入攻击的完全保护,而不需要你破坏你的存储数据。

答案 4 :(得分:2)

不,这不是一种过度杀伤。

此代码完全容易受到SQL注入攻击。你正在做一个mysql_real_escape_string()然后你正在做一个stripslashes()。因此"将在mysql_real_escape_string()之后变为\",然后在stripslashes()之后返回"。单独使用mysql_real_escape_string()最好是停止sql注入。参数化查询库(如PDO和ADODB)使用它,参数化查询使得完全停止sql注入非常容易。

继续测试您的代码:

$variable = sanitizeString($_POST['user_input']);
$variable = sanitizeMySQL($_POST['user_input']);
mysql_query("select * from mysql.user where Host='".$variable."'");

如果:

$_POST['user_input'] = 1' or 1=1 /*

修补:

mysql_query("select * from mysql.user where Host='".mysql_real_escape_string($variable)."'");

此代码也容易受到某些类型 XSS:

的攻击
$variable = sanitizeString($_POST['user_input']);
$variable = sanitizeMySQL($_POST['user_input']);
print("<body background='http://localhost/image.php?".$variable."' >");

如果:

$_POST['user_input']="' onload=alert(/xss/)";

修补:

$variable=htmlspecialchars($variable,ENT_QUOTES);
print("<body background='http://localhost/image.php?".$variable."' >");

htmlspeicalchars编码单引号和双引号,确保您打印的变量也被引号括起来,这使得无法“分解”并执行代码。

答案 5 :(得分:0)

好吧,如果您不想重新发明轮子,可以使用HTMLPurifier。它允许您准确地决定您想要什么以及您不想要什么,并防止XSS攻击等

答案 6 :(得分:-1)

我想知道消毒的概念。您告诉Mysql完全按照您的意愿执行操作:运行部分由网站用户编写的查询语句。您已经使用用户输入动态构造句子 - 将字符串与用户提供的数据连接起来。你得到了你所要求的。

无论如何,这里有更多的消毒方法......

1)对于数值,始终在构建查询字符串之前或之时至少手动转换:“SELECT field1 FROM tblTest WHERE(id =”。(int)$ val。“)”;

2)对于日期,首先将变量转换为unix时间戳。然后,使用Mysql FROM_UNIXTIME()函数将其转换回日期。 “SELECT field1 FROM tblTest WHERE(date_field&gt; = FROM_UNIXTIME(”。strtotime($ val)。“)”;。有时无论如何都需要处理Mysql如何解释和存储与脚本或OS层不同的日期。< / p>

3)对于必须遵循特定标准(用户名,电子邮件,电话号码等)的简短且可预测的字符串,您可以a)做好准备好的陈述;或b)正则表达式或其他数据验证。

4)对于不遵循任何真正标准的字符串,可能会或可能不会在整个地方(文本,备忘录,维基标记,链接等)都有或者双重转义和可执行代码,您可以a)做好准备陈述;或b)存储并转换为二进制/ blob格式 - 在将值传递给查询字符串之前将每个字符转换为二进制,十六进制或十进制表示,并在提取时转换回来。这样,当你将存储的值吐出来时,你可以更专注于html验证。