PHP会话的安全性


Security with PHP Sessions

我知道这个问题已经被问过无数次了,但我对我的代码的安全性非常偏执/强迫症。我在做一个小项目。会话数据将只包含:

user_id 1
user_name MyUsername
logged_in true
csrf_token 87 cc51ee94178df79cccce2aebc45d53

这是我的代码。是否安全足以在小型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'] ) )

提前感谢您的帮助。

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

    预测
  • 捕获
  • 固定

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

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

固定意味着攻击者可以创建一个会话,然后强迫另一个用户使用他们的会话。在这种情况下,这取决于:如果攻击者知道您正在这样做,并且他们伪造了用户代理和客户端的ip,他们可以固定会话。或者如果它们共享ip和用户代理。

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


话虽如此,它安全吗?和否

如果你痴迷于安全,答案总是一样的:使用SSL

除非你的代码是开源的,否则你所做的任何改变php会话行为的事情都是足够安全的。

唯一的例外是那些非常受欢迎的网站,它们会吸引黑客的注意。

关于这个主题有一些非常好的文档:

  • http://phpsec.org/projects/guide/4.html
  • PHP会话安全
  • http://www.squarefree.com/securitytips/web-developers.html CSRF

我不是安全专家。然而,我谦虚地怀疑你的安全强制措施会给带来实质性的好处。

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

我相信没有通道安全就没有会话安全。如果您使用SSL,您确保会话ID仅通过cookie发送(您已经这样做了),并且您的会话很快就会过期,我相信您是相当安全的,并且比在不安全的通道上实施这些更安全。

首先,您在会话重新生成代码中有一个错误。下面的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注入攻击成功并且您的数据库暴露于外界。但是,如果您的服务器被泄露,并且salt被泄露,那么就有可能生成一组已知的散列,并尝试对特定密码进行反向查找。底线?用盐散列你的用户密码

第三,大多数安全漏洞不是来自欺骗会话。它们来自于糟糕的输入检查。像Essential PHP Security这样的书应该是一本很好的介绍在PHP项目中应该做的输入检查的书。如果做不到这一点,至少要阅读PHP手册中的安全部分。注意SQL注入位。它很酷!

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

这只是两个主要的会话攻击

1。)会话固定攻击。

这可以通过使用session_regenerate_id()

来防止。

2。)会话劫持:

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

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

有了这三个实现,让我看看那个声称要破解用户会话的黑客…

说实话,我觉得你太谨慎了,但不是很有用。

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

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

但为了完整起见,我将对您的实际代码做一些注释,只是指出一些事情:

我不知道为什么你认为MD5哈希有什么不同。MD5哈希可以在几秒钟内被破解,因此在任何类型的安全功能中使用它们完全是任意的。它也可以是纯文本。也就是说,我真的不认为它们需要纯文本之外的任何东西——如果黑客已经设法掌握了会话数据,能够读取其中包含的IP地址,那么你已经不用担心他们是否知道IP地址了。

选择图片上传:";$res=mysql_query("SELECT ' id ', ' FirstName ', ' LastName ', ' Address ','密码','重密码','生日','性别',' user_image ' FROM(mysql_error());虽然美元($ result中进行row = mysql_fetch_array res)){id =美元行("id");firstname =美元行("firstname");user_image =美元行("user_image");页面。美元= "美元firstname";}页面。美元= ";$ res_post = mysql_query("选择post_info.post_info_id,post_info。id, post_info。post_info_desc,登记。FirstName FROM ' post_info 'join ' registration ' WHERE post_info。Id =注册。我订购post_info。Post_info_id desc") or die(mysql_error());而($ 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'];页面。美元= "

FirstName

post_desc美元

";}页面。美元= ";包括(包括/main_file.php);?>
<?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');
}
?>