【发布时间】:2010-12-19 11:33:27
【问题描述】:
好吧,我和一个朋友正在做一个关于 PHP 安全性的小型演示(虽然我并不真正喜欢 PHP),他让我找到一些易受攻击的 PHP 代码示例(一个容易受到 SQL 注入和所有其他问题的代码)攻击类型)。我想知道是否有任何网站包含好的和坏的代码片段显示你应该和不应该如何编码?
基本上我会将它们放入我们的网站,他会尝试破解它,然后我们将显示“正确”的网站,他会再次尝试破解它。
【问题讨论】:
好吧,我和一个朋友正在做一个关于 PHP 安全性的小型演示(虽然我并不真正喜欢 PHP),他让我找到一些易受攻击的 PHP 代码示例(一个容易受到 SQL 注入和所有其他问题的代码)攻击类型)。我想知道是否有任何网站包含好的和坏的代码片段显示你应该和不应该如何编码?
基本上我会将它们放入我们的网站,他会尝试破解它,然后我们将显示“正确”的网站,他会再次尝试破解它。
【问题讨论】:
SQL injection 很简单:
$var = $_POST['var'];
mysql_query("SELECT * FROM sometable WHERE id = $var");
这很容易解决:
$var = mysql_real_escape_string($_POST['var']);
另一个常见的是XSS (cross site scripting):
$var = $_POST['var'];
echo "<div>$var</div>\n";
允许您注入从您的站点运行的 Javascript。有几种处理方法,例如:
$var = strip_tags($_POST['var']);
和
$var = filter_var($_POST['var'], FILTER_SANITIZE_STRING);
【讨论】:
addslashes()、strip_tags() 或htmlspecialchars() 进行转义。
strip_tags 不足以阻止 HTML 注入(想想属性值注入)。使用 FILTER_SANITIZE_STRING 修改请求数组是一种可怕的 hack,永远不应该使用。相反,通过在您放入 HTML 内容的每个字符串上调用 htmlspecialchars 来避免 HTML 注入。
mysql_real_escape_string 在这种情况下不会阻止注入。
一个真正常见的初学者错误是在重定向后忘记终止脚本执行。
<?php
if ($_SESSION['user_logged_in'] !== true) {
header('Location: /login.php');
}
omg_important_private_functionality_here();
解决办法:
if ($_SESSION['user_logged_in'] !== true) {
header('Location: /login.php');
exit();
}
在普通浏览器中测试时可能会忽略这一点,因为浏览器通常会跟随 Location 标头而不呈现任何脚本输出。
【讨论】:
哦,孩子,你不会缺少例子。只要谷歌PHP tutorial,他们每个人都有足够的洞来填满阿尔伯特音乐厅。
结果 1,w3schools。他们第一个包含用户输入的例子是什么?
Welcome <?php echo $_POST["fname"]; ?>!<br />
Bzzt。 HTML 注入,在每段示例代码中重复出现。他们的第一个数据库查询是什么?
$sql="INSERT INTO Persons (FirstName, LastName, Age) VALUES ('$_POST[firstname]','$_POST[lastname]','$_POST[age]')";
Bzzt。 SQL注入,你输了。接下来。
结果 2,官方 PHP 教程。第一个输出变量的例子是什么?
echo $_SERVER['HTTP_USER_AGENT'];
Bzzt。 HTML 注入。这不是一个容易利用的方法,但仍然是在 php.net 的学习材料中重复出现的那种不好的做法。
结果 3,tizag.com。第一个回显用户输入的例子是什么?
echo "You ordered ". $quantity . " " . $item . ".<br />";
Bzzt。
结果 4,freewebmasterhelp.com。太基础了,无法包含太多内容,但仍然可以:
print "Hello $name"; // Welcome to the user
Bzzt。
结果5,learnphp-tutorial.com。
<title><?= $greeting ?> World!</title>
Bz...
我可以继续。
难怪 PHP 代码的总体质量如此糟糕,而程序员正在学习这种可悲的垃圾?
【讨论】:
eval 和system 的部分非常可怕。确实是“专业”安全性。
鲍比桌
Bobby Tables 是一个专门用于详细说明脚本通过SQL injection 易受攻击的方式的页面。这不是 PHP 独有的,然而,SQL 注入是许多网页漏洞的原因。
这可能是您想要包含在演示文稿中的内容。
【讨论】:
我以前见过这样的代码:
foreach ($_REQUEST as $var => $val) {
$$var = $val;
}
这是一种模拟被诽谤的register_globals 选项的方法。这意味着您可以像这样访问您的变量:
$myPostedVar
而不是非常复杂:
$_POST['myPostedVar']
在这样的情况下会出现安全风险:
$hasAdminAccess = get_user_access();
foreach ($_REQUEST as $var => $val) {
$$var = $val;
}
if ($hasAdminAccess) { ... }
因为您所要做的就是将?hasAdminAccess=1 添加到网址中,然后您就可以进入了。
【讨论】:
register_globals
另一个 sql-injection-vulnerable 登录脚本示例。不幸的是,这在新程序员中很常见。
$username = $_POST["username"];
$password = $_POST["password"];
$query = "SELECT username, password
FROM users
WHERE (username = '{$username}')
AND (password = '{$password}')";
【讨论】:
if(strstr($username, '**')) {
$admin = 1;
$username = str_replace('**', '', $username);
$_SESSION['admin'] = 1;
} else {
$admin = 0;
}
【讨论】:
CSRF 赢得胜利。
<?php
$newEmail = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_EMAIL);
$pdoStatement = $pdoDb->prepare('UPDATE user SET email=:email WHERE ID=:id');
$pdoStatement->execute(array(':email'=>$newEmail, ':id'=>$_SESSION['userId']));
您对这种代码感到安全。一切都很好,因为您的代码,您的用户可以在不注入 SQL 的情况下更改他们的电子邮件。 但是,假设您在您的网站http://siteA/ 上有这个,您的一位用户已连接。 使用相同的浏览器,他继续http://siteB/,其中一些 AJAX 执行与此代码等效的操作:
<form method="post" action="http://site/updateMyAccount.php">
<p>
<input name="email" value="badguy@siteB"/>
<input type="submit"/>
</p>
</form>
您的用户刚刚在他不知情的情况下更改了他的电子邮件。如果你觉得这种攻击不危险,ask google about it
为了帮助抵御此类攻击,您可以:
另一个是会话劫持。其中一种方法是捎带。 如果您的服务器接受非 cookie 会话,您可以使用像 http://siteA/?PHPSESSID=blabla 这样的 URL,这意味着您的会话 ID 是 blabla。
攻击者可以启动会话并记下其会话 ID,然后将链接 http://siteA/?PHPSESSID=attackerSessionId 提供给您网站的其他用户。当这些用户点击此链接时,他们与您的攻击者共享相同的会话:未记录的会话。所以他们登录。 如果网站不做任何事情,您的攻击者和您的用户仍然以相同的权限共享同一个会话。如果用户是管理员,那就不好了。
为了缓解这种情况,当您的用户凭据发生更改(登录和注销、进入管理部分等)时,您必须使用 session_regenerate_id。
【讨论】:
HTTP 响应拆分攻击
如果 Web 应用程序将来自 HTTP 请求的输入存储在 cookie 中,比如说
<?php setcookie("author",$_GET["authorName"]); ?>
如果输入未正确验证“\r\n”字符,则很容易受到 HTTP 响应拆分攻击。
如果攻击者提交了一个恶意字符串,例如“AuthorName\r\nHTTP/1.1 200 OK\r\n..”,那么HTTP响应将被分成如下形式的两个响应:
HTTP/1.1 200 正常
...
设置cookie:作者=作者姓名
HTTP/1.1 200 正常 ...
显然,第二个响应完全由攻击者控制,可以用任何标题和正文内容代替
【讨论】:
查看开放式 Web 应用程序安全项目。他们有很多不同类型的攻击的解释和例子。 http://www.owasp.org/index.php/Category:Attack
【讨论】:
Email headerinjection attacks 的颈部疼痛比您可能怀疑的要大得多(除非您必须处理它们)。
这很糟糕:
$to = 'contact@domain.com';
$subject = $_POST["subject"];
$message = $_POST["message"];
$headers = "From: ".$_POST["from"];
mail($to,$subject,$message,$headers);
(从上面的第二个参考中复制的代码。)
【讨论】:
制作模板的错误方式。
<?php
include("header.php");
include($_GET["source"]); //http://www.mysite.com/page.php?source=index.php
include("footer.php");
?>
【讨论】:
XSS 漏洞很容易显示。只需创建一个页面,将 GET 变量“q”的值放在页面的某处,然后点击以下 URL:
http://mysite.com/vulnerable_page.php?q%3D%3Cscript%20type%3D%22javascript%22%3Ealert(document.cookie)%3B%3C%2Fscript%3E
这将导致用户的 cookie 显示在警告框中。
【讨论】:
允许上传但不检查扩展。观察:
站点 A 允许上传图像并显示它们。
破解者上传一个文件并诱使您相信它是一个图像文件(通过 HTTP mimetypes)。该文件具有 PHP 扩展名并包含恶意代码。然后他试图查看他的图像文件,因为每个 PHP 扩展文件都是由 PHP 执行的,所以代码会运行。他可以做任何apache用户可以做的事情。
【讨论】:
基本(通常是安全敏感的)操作无法按预期工作,而是要求程序员使用第二个“真实”版本来获得未损坏的功能。
其中最严重的情况是实际运算符受到影响:“==”运算符无法按预期工作,而是需要“===”运算符才能获得真正的相等比较。
三大 PHP 论坛软件包之一受到其“保持登录”代码中的漏洞的影响。 cookie 将包含用户的 ID 和他们的密码哈希。 PHP 脚本会读取并清理 ID,使用它来查询用户在数据库中的正确哈希值,然后将其与 cookie 中的哈希值进行比较,看看他们是否应该自动登录。
但是比较是用 == 进行的,所以通过修改 cookie,攻击者使用 boolean:true 的哈希“值”,使得哈希比较语句无用。因此,攻击者可以替换任何用户 ID 以无需密码即可登录。
【讨论】:
允许人们上传文件,无论该 API 是否应该由用户使用。例如,如果一个程序将一些文件上传到服务器,并且该程序永远不会上传坏文件,那很好。
但是黑客可以追踪发送的内容以及发送到哪里。他可以发现它允许上传文件。
从那里,他可以轻松地上传一个 php 文件。一旦完成,游戏就结束了。他现在可以访问您的所有数据,并且可以销毁或更改他想要的任何东西。
另一个常见的错误是允许泛滥。你应该对你的数据设置一些合理的限制。不允许用户输入无意义的数据。为什么用户名的长度是 2MB?这样的事情很容易让某人因为空间不足错误而淹没您的数据库或文件系统并导致系统崩溃。
【讨论】: