在Apache/PHP中阻止GET请求
因此,我有一个我自己没有设计但具有已知安全漏洞的PHP脚本。有一个管理面板,管理员可以为每个用户更改各种配置文件设置,包括他们的电子邮件地址。这个安全漏洞使得任何知道正确URL的人都可以通过简单计算他们想要的新电子邮件地址的MD5哈希值来更改任何注册用户的电子邮件地址,包括管理员,只要他们知道相应的用户ID即可更改为并发出GET请求,而无需以管理员身份登录。例如,输入以下网址到浏览器:在Apache/PHP中阻止GET请求
admin.php的用户id = 1 & md5hash = c59152a77c0bc073fe6f2a3141b99010 & [email protected]
会与ID成功更新的用户的电子邮件地址“? 1“发送至[email protected]。
现在从我到目前为止所做的研究看来,抛弃MD5哈希以获得稍微更专有/安全的加密形式将是实现这一目标的最佳/最安全的方式。但是,虽然我觉得自己对PHP有很好的理解,并且自己编写了一些基本脚本,但由于我没有设计特定的脚本,因此我不确定这是否可行和/或是否合理。此外,人们在实践中仍然使用MD5哈希值,所以必须存在另一种同样可行的方法来保护这种攻击,这导致我寻找Apache的mod_rewrite模块来阻止特定类型的GET请求:
[因为不相关的编辑原因的2对新用户的最大链接限制]
所以我的问题是:
1)不考虑它是否会实际上是可行的,但改变PHP脚本使用的加密一些其他形式除了MD5哈希是最好的方式去做这件事?还是有一些简单的功能,我可以添加到PHP脚本本身以防止这种漏洞?
2)如果我去使用Apache的mod_rewrite的路线,如上面的URL描述,这将是最好的方法(出THE_REQUEST,HTTP_REFERER,HTTP_COOKIE,REQUEST_URI,HTTP_USER_AGENT,QUERY_STRING的,和/或REMOTE_ADDR,其中REQUEST_METHOD是“GET”)?或者甚至有可能做我想要这样做的事情?
3)有人还建议可以通过.htaccess文件做我想做的事情吗?这是否可能,并且这种方法会比其他提到的方法更安全吗?
唯一要考虑的是,通过我最终使用的任何方法,服务器必须仍能够在管理员想要合法更改用户的电子邮件地址时发出请求。我只需要对其进行更新,以便普通公众无法通过在浏览器中输入正确的URL来更改用户的电子邮件地址,因为他们知道正确的用户ID。提前致谢。
--->编辑:对不起,我忽略了命名特定的脚本,因为它是一个公共可用的,我不知道这个特定的漏洞是否是已知的,但事实证明它是,所以我猜在这里发布并没有什么坏处。该脚本是TorrentTrade(v2.08) - 您可以在SourceForge上下载整个脚本(https://sourceforge.net/projects/torrenttrader/)。
我也复制并粘贴了account-ce的全部内容。PHP:
<?php
//
// TorrentTrader v2.x
// $LastChangedDate: 2012-09-28 20:35:06 +0100 (Fri, 28 Sep 2012) $
// $LastChangedBy: torrenttrader $
//
// http://www.torrenttrader.org
//
require_once("backend/functions.php");
dbconn();
$id = (int) $_GET["id"];
$md5 = $_GET["secret"];
$email = $_GET["email"];
if (!$id || !$md5 || !$email)
show_error_msg(T_("ERROR"), T_("MISSING_FORM_DATA"), 1);
$res = SQL_Query_exec("SELECT `editsecret` FROM `users` WHERE `enabled` = 'yes' AND `status` = 'confirmed' AND `editsecret` != '' AND `id` = '$id'");
$row = mysql_fetch_assoc($res);
if (!$row)
show_error_msg(T_("ERROR"), T_("NOTHING_FOUND"), 1);
$sec = $row["editsecret"];
if ($md5 != md5($sec . $email . $sec))
show_error_msg(T_("ERROR"), T_("NOTHING_FOUND"), 1);
SQL_Query_exec("UPDATE `users` SET `editsecret` = '', `email` = ".sqlesc($email)." WHERE `id` = '$id' AND `editsecret` = " . sqlesc($row["editsecret"]));
header("Refresh: 0; url=account.php");
header("Location: account.php");
?>
帐户ce.php在以下几个已知漏洞列表(第一个漏洞是唯一一个我看现在)引用的PHP文件:
https://www.exploit-db.com/exploits/21396/
我想,不要坐在等待TorrentTrader发布新更新,我会尝试主动修复一些漏洞。
您需要包含在会话处理程序中。我想假定用户在被允许访问任何管理页面之前需要登录,并且某种登录凭证或用户标识被保存到会话变量中。要实现,你就需要有一个这样的脚本包含在每一页上:
<?php
session_start();
if(!isset($_SESSION['uid'])){
$redirect_url='login.php';
if(isset($_SERVER['HTTP_REFERER'])){
$redirect_url.='?target='.urlencode($_SERVER['HTTP_REFERER']);
}
header('Location: '.$redirect_url);
}
?>
$ _SESSION [“UID”]是有点任意的,可能是你认为足够满足您的应用程序的安全性有任何会话变量。注意:会话变量连接到用户并在页面之间保存,直到通过调用session_destroy()销毁会话。
如果上面的脚本是在每次页面加载之前执行的,那么当某些恶意黑客试图在未登录的情况下触发脚本时,它们将在脚本/页面的其余部分执行前被重定向到login.php /加载。
呃,没有。在执行其余代码之前,脚本确实会**发出**重定向到login.PHP,但在调用header()之后没有退出语句时,它仍然会执行代码的其余部分。 – symcbean
好的,你有两个选择来处理:(如你所提到的)在头重定向之后调用exit()或die()(假设其余部分不应该被执行,如果达到的话),或者,你可以把其余的代码放在一个else语句中。如果还有其他问题,提供相关代码的副本可能会有所帮助。 – Andrew
调用header()不会立即重定向用户,它会在发送处理后的页面时提交头部请求。另外,需要注意的是,如果在调用header()之前有文本,可能会阻止设置头文件 – Andrew
当前脚本非常不安全,但不安全不是由使用md5散列产生的。仅仅使用Apache配置就可以将安全机制锁定在这样的系统上真的很难。
您可能希望通过在session security和cross site request forgery.
你需要编写一些代码读取赶快下手。由于您没有发布任何代码,也没有提出具体的解决方案,所以您的问题在这里非常关键。
你对脚本如何工作的分析是非常错误的。您可能不希望对此进行任何更改,直到您至少了解其当前的工作方式并知道更多关于安全编程的更多内容。 – symcbean
好的家伙,我觉得现在适度愚蠢,但感谢你的提示使用会话处理器因为这是最终指向我在正确的方向和正确的地方去寻找。周围挖之后好像那个特定的管理文件(帐户ce.php),无论出于何种原因,只是缺少这样的:
loggedinonly();
这是在后端/ functions.php中定义为:
function loggedinonly() {
global $CURUSER;
if (!$CURUSER) {
header("Refresh: 0; url=account-login.php?returnto=" . urlencode($_SERVER["REQUEST_URI"]));
exit();
}
}
另外,我打算为你的建议,所以我可以更好地与会话如何用于此目的自己熟悉的会话安全读了。再次感谢! :)
最好的方法就是以修复脚本,检测呼叫者是否有权调用脚本首先 – DarkBee
'而不必登录作为admin'为什么?不应该admin.php检查他们是否像任何其他网页的管理员? –
你应该使用某种会话。因此,如果用户登录并且是管理员,或者信息属于正在访问它的登录用户,则可以完成更新。这是授权/管理权限的常用方式。 –