阻止XSS和SQL注入就像这样容易

时间:2010-01-03 21:15:55

标签: php html xss sql-injection

问题:在任何已保存的输入字段上使用strip_tags并在任何已保存的输入字段上运行htmlspecialchars时,阻止 XSS (跨站点脚本编写)变得简单显示输出...并使用PHP PDO预处理语句阻止 SQL注入

以下是一个例子:

// INPUT: Input a persons favorite color and save to database
// this should prevent SQL injection ( by using prepared statement)
// and help prevent XSS  (by using strip_tags)
$sql = 'INSERT INTO TABLE favorite (person_name, color) VALUES (?,?)';
$sth = $conn->prepare($sql);
$sth->execute(array(strip_tags($_POST['person_name']), strip_tags($_POST['color'])));


// OUTPUT: Output a persons favorite color from the database
// this should prevent XSS (by using htmlspecialchars) when displaying
$sql = 'SELECT color FROM favorite WHERE person_name = ?';
$sth = $conn->prepare($sql);
$sth->execute(array(strip_tags($_POST['person_name'])));
$sth->setFetchMode(PDO::FETCH_BOTH);
while($color = $sth->fetch()){
  echo htmlspecialchars($color, ENT_QUOTES, 'UTF-8');
}

6 个答案:

答案 0 :(得分:8)

它更简单。用户控制输入的htmlspecialchars()(带引号样式和字符集)就足够了。 strip_tags()仅在您需要在处理/保存数据库之前清理数据时才有用,这通常不会在现实世界中使用。 HTML代码在PHP源代码中没有坏处,但如果你在非消毒的用户控制输入上使用eval()或那种邪恶的东西,PHP代码可能会这样做。

然而,这并不能使您免于SQL injections,但这是另一个故事。

更新:要从请求中获取 clean 用户输入以避免用户控制输入中的magic quotes,您可以使用以下函数:

function get_string($array, $index, $default = null) {
    if (isset($array[$index]) && strlen($value = trim($array[$index])) > 0) {
         return get_magic_quotes_gpc() ?  stripslashes($value) : $value;
    } else {
         return $default;
    }
}

可以用作:

$username = get_string($_POST, "username");
$password = get_string($_POST, "password");

(您可以对get_numberget_booleanget_array等进行同声传译。

要准备SQL查询以避免SQL injections,请执行:

$sql = sprintf(
    "SELECT id FROM user WHERE username = '%s' AND password = MD5('%s')",
        mysql_real_escape_string($user),
        mysql_real_escape_string($password)
); 

要显示用户控制的输入以避免XSS,请执行以下操作:

echo htmlspecialchars($data, ENT_QUOTES, 'UTF-8');

答案 1 :(得分:5)

这取决于您希望使用用户数据的位置和方式。您需要知道要插入数据的上下文以及该上下文的元字符。

如果您只是想让用户在您的网站上放置文字,htmlspecialchars就足以转义HTML元字符。但是,如果您想允许某些HTML或想要将用户数据嵌入现有HTML元素(例如将网址嵌入A / IMG元素),那么htmlspecialchars是不够的不再在HTML上下文中,而是在URL上下文中。

因此,将<script>alert("xss")</script>输入图片网址字段会产生:

<img src="&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt" />

但是输入javascript:alert("xss")会成功:

<img src="javascript:alert(&quot;xss&quot;)" />

在这里,您应该看看神话般的XSS (Cross Site Scripting) Cheat Sheet,看看您的用户数据可以注入哪些上下文。

答案 2 :(得分:4)

strip_tags不是必需的。在大多数情况下,strip_tags只会令人恼火,因为您的某些用户可能希望在其文本中使用<>。在将文本回显给浏览器之前,只需使用htmlspecialchars(如果您愿意,可以使用htmlentities)。

(在将任何内容插入数据库之前,不要忘记mysql_real_esacpe_string!)

答案 3 :(得分:3)

一般规则/ meme是“过滤器输入,转义输出”。在输入中使用strip_tags删除任何HTML是输入过滤的好主意,但您应该在允许的输入中尽可能严格。例如,如果输入参数只应该是一个整数,则只接受数字输入并始终在使用它执行任何之前将其转换为整数。经过严格审查的输入过滤库将在这里为您提供帮助;一个不是特定于特定框架的Inspekt(我写的,所以我有点偏颇)。

对于输出,htmlspecialchars 能够逃脱XSS攻击,但仅当您传递正确的参数时。您必须传递引用转义样式一个字符集。

通常,此应该删除XSS攻击:

$safer_str = htmlspecialchars($unsafe_str, ENT_QUOTES, 'UTF-8');

如果不传递ENT_QUOTES作为第二个参数,则不对单引号字符进行编码。此外,当没有通过正确的字符集时,已经证明了XSS攻击(通常UTF-8就足够了)。 htmlspecialchars 始终使用ENT_QUOTES和charset参数进行调用。

请注意,PHP 5.2.12包含a multibyte XSS attack的修复程序。

虽然PHP版本不完整AFAIK,但您可能会发现OWASP ESAPI PHP port有趣且有用。

答案 4 :(得分:3)

是的,使用PDO预处理语句可以防止SQL注入。 SQL注入攻击基于以下事实:攻击者提交的数据被视为查询的一部分。例如,攻击者提交字符串“a”或“a”=“a”作为其密码。它不是将整个字符串与数据库中的密码进行比较,而是包含在查询中,因此查询变为“SELECT * FROM users WHERE login ='joe'AND password ='a'或'a'='a' ”。攻击者输入的部分被解释为查询的一部分。但是,对于预处理语句,您具体告诉SQL引擎,查询的哪个部分以及数据的哪个部分(通过设置参数),因此不会出现这种混淆。

不,使用strip_tags并不总能保护您免受跨站点脚本的攻击。请考虑以下示例。假设您的页面包含:

<script>
location.href='newpage_<?php echo strip_tags($_GET['language']); ?>.html';
</script>

攻击者提交请求时将“language”设置为“'; somethingevil();'”。 strip_tags()按原样返回此数据(其中没有标记)。生成的页面代码变为:

<script>
location.href='newpage_';somethingevil();'.html';
</script>

somethingevil()被执行。用实际的XSS漏洞代码替换somethingevil()。

你使用htmlspecialchars()的最后一个例子将防止这个,因为它将转义单引号。但是我在JavaScript代码中看到了更奇怪的用户提供的数据,甚至在引用的字符串中也没有。我认为它是变量或函数名称。在最后一种情况下,没有任何逃避可能会有所帮助。我相信最好避免使用用户输入来生成JavaScript代码。

答案 5 :(得分:2)

简单回答:没有

更长的答案:有一些方法可以注入PHP strip_stags无法避免的xss。

为了获得更好的保护,请尝试HTML purifier