问题:在任何已保存的输入字段上使用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');
}
答案 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_number
,get_boolean
,get_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="<script>alert("xss")</script>" />
但是输入javascript:alert("xss")
会成功:
<img src="javascript:alert("xss")" />
在这里,您应该看看神话般的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)