PHP会话的安全性

问题描述 投票:8回答:7

我知道这已被问过数十亿次,但我对于编码的安全性我是超级偏执/强迫症。我正在做一个小项目。会话数据仅包含:

user_id 1 user_name MyUsername logged_in是的 csrf_token 87cc51ee94178df79cccce2aebc45d53

这是我的代码。它是否足够安全,可以在小型CMS上使用?

session_start();

ini_set('session.cookie_httponly', 'On');
ini_set('session.cookie_secure', 'On');
ini_set('session.use_cookies', 'On');
ini_set('session.use_only_cookies', 'On');

$rand = rand(1, 10);

if ($rand != 1 || $rand != 3 || $rand != 5)
    session_regenerate_id();

$user_ip = md5($_SERVER['REMOTE_ADDR']);
$user_agent = md5($_SERVER['HTTP_USER_AGENT']);

if (isset($_SESSION['user_ip'], $_SESSION['user_agent'])) {
    $session_user_ip = $_SESSION['user_ip'];
    $session_user_agent = $_SESSION['user_agent'];

    if ($session_user_ip != $user_ip || $session_user_agent != $user_agent) {
        unset($_SESSION);
        session_destroy();

        die('Error');
    }
} else {
    $_SESSION['user_ip'] = $user_ip;
    $_SESSION['user_agent'] = $user_agent;
}

然后调用会话:

$_SESSION['user_id'] = 1;
$_SESSION['user_name'] = 'MyUsername'; // etc.

额外信息 我将使用会话数据来检查用户是否有权执行某些操作。示例:if ( user_has_perm( $_SESSION['user_id'] ) )

感谢您的帮助。

php security session suhosin
7个回答
12
投票

会话安全风险来自三种不同的可能性:

  • 预测
  • 捕获
  • 固定术

预测意味着不是创建会话的用户的某个人猜到了他们的会话ID。发生这种情况的可能性几乎为0,尽管随着越来越多的用户同时使用该网站,它们确实会增长。

使用您的代码,您可以将风险降低甚至更低,因为只有在攻击者共享用户代理和预测会话的IP时才会起作用。但在这种情况下,差异是微不足道的。

修复意味着攻击者可以创建会话,然后强制其他用户使用他们的会话。在这种情况下,它将取决于:如果攻击者知道您正在执行此操作并伪造用户代理和客户端的IP,则他们可以修复会话。或者如果他们共享ip和用户代理。

最后我们有会话劫持,可能是三者中最常见的方法。在这种情况下,攻击者会以某种方式获得对有效登录用户的会话ID的访问权限,然后使用它登录到他们的帐户。与前面的方法一样,只有当他们知道您正在检查ip和用户代理并伪造与用户相同的方法时,这才适用于他们。您使用的技术并不是唯一的,一些攻击者可能会伪造它们以防万一。


话虽如此,它是否安全?是的,不是

如果您沉迷于安全性,答案总是一样的:使用SSL

除非你的代码是开源的,否则你所做的几乎所有改变php会话的行为都是足够安全的。

唯一的例外是真正受欢迎的网站,它们会引起黑客的注意。

有关此主题的一些非常好的文档:


3
投票

我不是安全专家。但是,我谦卑地怀疑您的安全执行会带来实质性的好处。

如果有人可以窃取用户的会话ID,例如通过窃听未加密的无线网络,我打赌他还可以窃取用户在进行身份验证时发送给服务器的用户名和密码。一旦他拥有访问凭据,攻击者就可以在一天之后或一周之后登录,并且可以使用他的“安全” - 和100%有效 - 会话。

我相信没有通道安全性就没有会话安全性。如果您使用SSL,则确保会话ID仅通过cookie发送(您已经在执行)并且您的会话很快就会过期,我相信您相当安全,并且比在不安全的渠道上执行这些操作更安全。


2
投票

首先,会话重新生成代码时出错。以下if将始终评估为true:

if ($rand != 1 || $rand != 3 || $rand != 5)

如果$rand不是1,则返回true。如果$rand为1,那么它不是3,它返回true。你可能想在这里使用and

其次,你不需要MD5 user_ipuser_agent字符串。如果有人可以直接访问您服务器上的会话数据,那么您就可以深入了解数据无法保存的哈希值。

澄清:正如SDC和crush在评论中指出的那样,如果用哈希值哈希,MD5适用于散列密码。这意味着即使SQL注入攻击成功并且您的数据库暴露给全世界,您的用户密码通常仍然是安全的。但是,如果您的服务器遭到入侵,并且盐被泄露,则可以生成一组已知的哈希值,并尝试反向查找特定密码。底线?用盐哈希你的用户密码。

第三,大多数安全漏洞并非来自欺骗会话。他们来自糟糕的输入检查。像Essential PHP Security这样的书应该是对PHP项目中应该进行的输入检查的一个很好的介绍。没错,至少读了security section of the PHP Manual。注意SQL注入位。这很酷!

最后,我完全同意另一张海报,您应该使用SSL来保护与您网站的通信。


0
投票

说实话,我认为你过于谨慎,但不是非常有用。

如果您真的担心会话安全性,请不要自己尝试。使用像Suhosin这样的PHP安全补丁。让它为您完成所有艰苦的工作。 Suhosin是一个完善的PHP补丁。它包含处理PHP会话被攻击的所有方式的东西。如果你已经安装了它,那么你不需要做任何额外的事情来保护你的会话。如果你没有安装它,那么你绝对不能声称对安全性超级偏执!

所以简而言之,安装Suhosin(如果你还没有),并忘掉它。

但为了完整起见,我会在你的实际代码上做一些评论,只是指出一些事情:

我不确定你为什么认为MD5哈希有任何区别。 MD5哈希值可以在几秒钟内破解,因此将它们置于任何类型的安全功能中都是完全随意的。它也可以是纯文本。也就是说,我真的不认为除了普通文本之外还需要它们 - 如果黑客已经设法获取会话数据以便能够读取它包含的IP地址,那么你就是已经超出了他们是否知道IP地址的担忧。


0
投票

它们只是两次主要的会话攻击

1.)会话固定攻击。

这可以通过使用session_regenerate_id()来防止

2.)会话劫持:

这可以通过使用SSL证书进行数据加密来防止。您的网站现在将在https而不是http上运行。

3.)如果您位于未实现CloudFare或JailRoot的共享服务器上。您可以显示将会话存储在数据库中,而不是默认文件系统存储。

有了这三个实现,让我看看那个声称​​黑客用户会话的黑客......


-1
投票
Select image to upload: "; $res=mysql_query("SELECT `id`, `FirstName`, `LastName`, `Address`, `Password`, `Repassword`, `Birthday`, `Gender`, `user_image` FROM `registration`") or die(mysql_error()); while($row=mysql_fetch_array($res)) { $id=$row['id']; $firstname=$row['FirstName']; $user_image=$row['user_image']; $page.=" $firstname"; } $page.=" "; $res_post=mysql_query("SELECT post_info.post_info_id, post_info.id, post_info.post_info_desc, registration.FirstName FROM `post_info` join `registration` WHERE post_info.id = registration.id order by post_info.post_info_id desc") or die(mysql_error()); while($row_post=mysql_fetch_array($res_post)) { $post_id = $row_post ['post_info_id']; $post_desc = $row_post ['post_info_desc']; $id = $row_post ['id']; $FirstName = $row_post ['FirstName']; $page.="

$FirstName

$post_desc

"; } $page.=" "; include('include/main_file.php'); ?>

-2
投票
<?php

session_start();
$con=mysql_connect("localhost","root","");
$seldb=mysql_select_db('myfreind', $con);
$email=$_POST['txtEmail'];
$password=$_POST['txtPass'];
$res=mysql_query("SELECT `id`, `FirstName`, `LastName`, `Address`, `Password`, `Repassword`, `Birthday`, `Gender` FROM `registration` WHERE 
`Password`='$password' and  `FirstName`='$email'");
$num=mysql_num_rows($res);

if($num==1)
{
$row=mysql_fetch_array($res);
$id=$row['id'];
$firstname=$row['FirstName'];
$_SESSION['id']=$id;
$_SESSION['FirstName']=$firstname;
//echo $_SESSION['id'];
header('Location:main.php');
}else

{

header('Location:index.php?error');
}

?>
热门问题
推荐问题
最新问题