2009-03-05 183 views
4

在过去的几天里它一直在我的脑海中运行,但我阅读了一些关于如何让PHP会话更安全的文章。几乎所有这些文章都表示,您需要在会话中使用额外的salt来保存useragent。类似这样的:PHP Sessions + Useragent with salt

$fingerprint = md5('SECRET-SALT'.$_SERVER['HTTP_USER_AGENT']); 

盐会让攻击者更难以劫持或任何会话。但是,为什么每次添加盐,你会检查它是这样的:

md5('SECRET-SALT'.$_SERVER['HTTP_USER_AGENT']) == $_SESSION [ 'fingerprint' ] 

那么,为什么盐使其更加安全,因为攻击者仍然只需要用户代理(这是relativly一小套不同useragents的)和sessionid?

也许小东西我俯瞰,但无法弄清楚,我逼疯了,哈哈

谢谢!

回答

0

我也这样做到partially protect from session impersonation attacks。您还需要包含IP地址。

请记住,当客户端的浏览器会自动更新用户代理的改变,你会认为他的会议已被劫持;)

+0

包括会话指纹中的IP地址是不好的,因为它会阻止用户合法更改IP地址,例如断开 – Guss 2009-03-05 21:40:29

+0

@Guss的DSL线路:发生这种情况时(或用户代理的浏览器自动更新时),则I会话失效。没什么大不了的,用户必须重新登录。 – cherouvim 2009-03-05 21:42:51

0

由于指纹存储在服务器端,你不需要使用盐腌散列。 “正常”散列足以减少数据。

+0

salt = good:D看到我的回答 – Mez 2009-03-05 21:27:52

+0

花了我一会儿才输入:D – Mez 2009-03-05 21:48:01

+0

盐没用,看我的评论给你的回答。 – Guss 2009-03-05 21:53:08

0

请记住,如果你这样做,你迫使人们再次登录,如果他们升级他们的浏览器。这可以,但确保它是你的意图。

使用用户的远程地址也不是没有问题。许多人使用来自不同地点的同一台计算机。移动设备,在家中和工作中使用的笔记本电脑,在Wifi热点中使用的笔记本电脑等。恕我直言,这是一个坏主意,以这样的方式使用IP地址,新的IP地址需要登录,除非你处理高度敏感的信息如网上银行。是这样吗?

您关心什么?外部攻击?或者在共享主机的情况下,有人可以阅读您的会话信息?

如果是后者,解决方案很简单:只是不要在会话中存储任何敏感内容。任何敏感的东西都应该存储在数据库中。

就创建秘密盐而言,您需要使用不可猜测的东西。我会去创建一个像创建用户时创建的随机字符串。如果有必要,每次会话失效时重新创建它。

至于什么使它更安全,你自己说:有限的用户代理字符串(少于100个可能会覆盖99.99%的用户)。盐只是增加了可能性的数量。话虽如此,如果你在所有会议中使用相同的盐,那么在蛮力中发现它只是一个时间问题。

7

建议添加盐的原因很简单。一般来说,当你创建这个“指纹”时 - 如果你只使用一个有限数据集的数据项,那么它会使外部黑客更容易产生这个数据,并劫持会话。

在上例中,如果攻击者同时拥有“指纹”和用户代理,则他们将能够劫持会话。

加入盐只能使得攻击者更难生成指纹,它是:“如果他们都只有一个资料片,那么信息的最后一块毫无用处)

我的情况下, d建议你在vBulletin(一个我曾经使用过的项目)中添加更多的东西,会话ID散列(基本上与指纹相同)用下面的代码生成:

define('SESSION_IDHASH', md5($_SERVER['HTTP_USER_AGENT'] . $this->fetch_substr_ip($registry->alt_ip))); // this should *never* change during a session 

此外,会话哈希使用

md5(uniqid(microtime(), true)); 

这些都是当试图

所以识别会话,劫持会话时,人会需要知道服务器上的以下

  • 的时间(精确地)托运时创建会话是
  • 用户的浏览器代理字符串
  • 用户的IP地址

他们也必须欺骗IP地址(或至少前2/3个八位字节)才能做到这一点。

如果他们确实处于能够获得上述信息的地步,那么他们可能会以其他方式进行攻击,而不仅仅是会话劫持。 vBulletin实际上并没有使用“salt”本身,但在上面的例子中,盐只是添加了有限的熵,最好总能找到尽可能多的熵。

例如,在我正在用python编写的东西中,我使用XSRF保护生成哈希值。以下是我使用的。

self.key = sha1(
     self.user.username + 
     self.user.password + 
     settings.SECRET_KEY + 
     strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime()) 
    ).hexdigest() 

这取用户的用户名和密码,当前时间,以及预设的盐来生成这个。对于攻击者而言,由于盐和时间的缘故,攻击者很难生成(尽管如此,请注意,只有在它被使用后才会发生变化,随着时间的推移,如果它没有改变,为特定用户破解这个)

2

如果我理解正确,你想阻止远程攻击者会话劫持,猜测会话ID?

如果情况并非如此,那么你就深深地陷入了困境 - 一个可以窥探流量的攻击者也可以模仿用户代理,而一个攻击者可以获得对会话存储的访问权限。

如果存储用户代理字符串以将会话“锁定”到当前用户代理,那么对它进行散列确实毫无意义 - 对完整用户代理字符串的字符串比较更快(然后散列和比较)并且在存储方面不会更昂贵。

我不认为存储用户代理正在提供足够的区别 - 更好的做法是在会话开始时生成更大的ID(可能包含更多位)(可能是当前时间戳+用户名+用户代理+然后将其存储在cookie中以及会话中,并在每个附加请求上进行匹配。这并没有太多的改变攻击向量(你仍然需要猜测一些数字),但是通过大量增加攻击的难度,它很容易显着增加必须为成功攻击而猜测的比特数。

0

好了,例如我用下面的代码虚构:

<?php 

// The sessionid cookie is now a certain hash 
if (array_key_exists ($_COOKIE [ 'sessionid' ])) 
{ 
    // Get the session from database 
    $db_sessid = $pdo -> getStuff ('session_database', $_COOKIE [ 'sessionid' ]); 

    if ($db_sessid !== null && $db_sessid [ 'fingerprint' ] == sha1 ('SOMESALT' . $_SERVER [ 'HTTP_USER_AGENT' ])) 
    { 
     set_cookie (...); // New sessionid and write also to DB 

     // User is now logged in, execute some user stuff 
    } 
    else 
    { 
     // Session doesn't exist, or the fingerprint does not match 
    } 
} 

现在,攻击者只是仍然需要会话ID,这是在cookie中(以及HTTP头发送)和用户代理。那么额外的盐还有什么意义呢?

检查IP的也是在我看来不是一个很好的选择,有些提供商或代理服务器改变他们的每一个请求。

由于到目前为止( - :

3

如果你是你自己的服务器上,加密会话变量是没有意义的,因为他们不出去服务器的更多信息,请参见Linead答案What do I need to store in the php session when user logged in?。如果您在共享服务器中,除了会话ID之外,您可能需要加密每个会话变量,因为它们存储在您的邻居正在使用的同一Web服务器可读的临时文件中。真的担心安全问题,你用自己的(虚拟的或不是)服务器更好,所以危险只会来自你的服务器外部。

风险到您的会议的一些例子:

  • 您的服务器的URL发送会话ID和用户遵循以badguys.com他们将在服务器变量的引用者获得一个链接(完整的URL,包括会话ID),浏览器和用户的IP地址。如果您没有检查IP,或者您的用户使用开放式代理,则只需安装相同的浏览器版本,粘贴网址即可完成。
  • 用户转到公共电脑登录,然后离开而不关闭他的会话(嘿,他毕竟是人类)。该行中的下一个人打开浏览器,查看历史记录并找到公开会话。呸。

所以,有些措施可以采取,由我通常偏好:

  1. 不要发送的URL中的会话ID;在PHP中启用session.use_only_cookies。缺点:用户需要启用cookie。
    • 关于危险操作(更改密码,下单......),请再次询问用户密码。你也可以定期做。缺点:烦人。
    • 快速超时会话。缺点:在大多数网站中,这会迫使用户经常登录,烦人。
    • 使用SSL(只有这样才能避免'中间人'攻击)。缺点:慢。愚蠢的浏览器消息。在服务器上需要SSL。
    • 检查IP。缺点:对使用公共代理的访问者无效。烦人的动态IP。
    • 检查用户代理(浏览器)。缺点:几乎没用,UA很容易得到和模仿。

(我认为是理所当然你还没有PHP配置最大的安全性)。

一些更极端的措施:

  • 维护服务器和浏览器,例如之间的永久连接使用Java小程序。没有连接,没有会话。缺点:用户需要Java,ActiveX或任何你使用的。会话关闭浏览器(这可以很好)。不适用于连接速度很慢的情况。服务器负载较高。您需要打开端口,为applet创建一个特殊的服务器。
  • 同样的,但使用异步请求(例如AJAX)非常频繁地刷新会话,以及非常短的超时。或者刷新隐藏的IFRAME。缺点:用户需要JavaScript。不适用于连接速度很慢的情况。服务器负载较高。
  • 相同,但重新加载整个页面。缺点:用户需要JavaScript。当你正在阅读一个页面时自动重新加载烦人。

在某些情况下,您可以忘记会话并使用Apache身份验证。最简单的解决方案,但有很多限制。

1

我看到一个目的是腌制指纹。如果一个坏人抓住了你的session-db(天知道为什么)而不是你的代码,他不能通过尝试普通的用户代理来“猜测”你的指纹方法。