防止会话劫持的最佳方法是什么?


124

具体来说,这与何时使用客户端会话cookie来标识服务器上的会话有关。

在整个网站上使用SSL / HTTPS加密是最好的答案,并且您能最好地保证没有中间人会嗅探现有的客户端会话cookie?

也许对存储在您的会话Cookie中的会话值本身使用某种加密的第二好方法?

如果恶意用户对计算机具有物理访问权,他们仍然可以查看文件系统以检索有效的会话cookie,并使用该cookie劫持会话?

Answers:


140

加密会话值将产生零影响。会话cookie已经是一个任意值,对其进行加密只会生成另一个可以嗅探的任意值。

唯一真正的解决方案是HTTPS。如果您不想在整个站点上使用SSL(也许您有性能方面的顾虑),则仅SSL保护敏感区域就可以摆脱困境。为此,请首先确保您的登录页面为HTTPS。当用户登录时,除了常规会话cookie外,还设置一个安全cookie(这意味着浏览器将仅通过SSL链接传输它)。然后,当用户访问您的“敏感”区域之一时,将其重定向到HTTPS,并检查该安全cookie的存在。真正的用户会拥有它,会话劫持者则不会。

编辑:此答案最初写于2008年。现在是2016年,没有理由不在整个站点上使用SSL。不再需要纯文本HTTP!


28
HTTPS将仅阻止嗅探。但是,如果您使用的是XSS,或者很容易猜到会话ID,或者您很容易受到会话固定的影响,或者会话ID的存储能力很弱(SQL注入?),那么SSL根本无法改善。
Calimo 2012年

5
@Josh如果恶意用户对计算机具有物理访问权,他们仍然可以查看文件系统以检索有效的会话cookie,并使用该cookie劫持会话?
Pacerier

72
如果恶意用户可以物理访问文件系统,则无需劫持会话。
乔什·辛曼

25
@乔什 事实并非如此,有时用户对文件系统的物理访问时间有限。想象一下,一台笔记本电脑被同事冲上厕所解锁,现在我要做的就是去笔记本电脑,安装EditThisCookie插件,使用EditThisCookie导出功能在plus.google.com上抓取他的cookie,现在我有了他的帐户。花费时间:18秒。
Pacerier,2012年

1
我很确定Google会内置某种安全功能,因为这显然是您在谈论会话劫持时会想到的第一件事
xorinzor 2012年

42

SSL仅有助于嗅探攻击。如果攻击者可以访问您的计算机,我将假定他们也可以复制您的安全cookie。

至少,请确保旧的Cookie会在一段时间后失去其价值。当cookie停止工作时,即使成功的hijaking攻击也将受到挫败。如果用户有一个多月前登录的会话中的cookie,请重新输入密码。确保每当用户单击您站点的“注销”链接时,就永远不能再次使用旧的会话UUID。

我不确定这种想法是否行得通,但是可以解决:在您的会话cookie中添加一个序列号,也许是这样的字符串:

SessionUUID,序列号,当前日期/时间

加密此字符串并将其用作您的会话cookie。定期更改序列号-可能是Cookie的使用时间为5分钟,然后重新发出Cookie。如果愿意,您甚至可以在每个页面视图上重新发布它。在服务器端,保留您为该会话发布的最后一个序列号的记录。如果有人发送了序列号错误的cookie,则意味着攻击者可能正在使用他们较早拦截的cookie,因此使会话UUID无效并要求用户重新输入密码,然后重新发出新的cookie。

请记住,您的用户可能有多台计算机,因此他们可能有多于一个活动会话。不要执行强迫他们每次在计算机之间切换时再次登录的操作。


我知道这是一篇旧文章,但只想包括一下,如果攻击者要劫持“序列号”分配的窗口中的会话,那么这不会影响他。
暗恋

@crush,但是攻击者将在分配的窗口之后被锁定,对吗?因此,至少攻击窗口较小。
Johanneke

2
唯一的问题是,如果用户离开您的网站5分钟,他们将不得不再次登录
elipoultorak 2015年

21

您是否考虑过阅读有关PHP安全性的书?强烈推荐。

对于非SSL认证的网站,以下方法取得了很大的成功。

  1. 禁止在同一帐户下进行多个会话,请确保您不是仅通过IP地址进行检查。而是通过登录时生成的令牌(与用户会话一起存储在数据库中)以及IP地址,HTTP_USER_AGENT等进行检查

  2. 使用基于关系的超链接生成链接(例如,http : //example.com/secure.php?token=2349df98sdf98a9asdf8fas98df8),该链接后面附加有x-BYTE(首选大小)随机腌制的MD5字符串,在页面重定向时会随机生成令牌对应于请求的页面。

    • 重新加载后,将执行几项检查。
    • 原始IP地址
    • HTTP_USER_AGENT
    • 会话令牌
    • 你明白了。
  3. 短寿命会话认证cookie。如上所述,一个包含安全字符串的cookie是一个好主意,它是对会话有效性的直接引用之一。使它每x分钟过期一次,重新发出该令牌,然后将会话与新数据重新同步。如果数据不匹配,请注销用户,或让他们重新验证其会话。

我绝不是这个主题的专家,我在这个特定主题上已有一些经验,希望其中一些可以帮助任何人。


4
您会推荐什么书吗?
Rikki 2012年

1
尤其是考虑到OP并没有特别声明有关PHP的任何信息,我想说的是,最好只看一本通用的安全性书(特别是因为不同语言之间的安全性仅在实现细节上有所不同,但是概念保持不变)。
matts1 2014年

在2017年,除非您讨厌用户,甚至facebook / gmail等都允许在同一帐户下(尤其是在移动设备上)使用多个会话,除非您讨厌用户,#1有点过时了。
考伯特

20
// Collect this information on every request
$aip = $_SERVER['REMOTE_ADDR'];
$bip = $_SERVER['HTTP_X_FORWARDED_FOR'];
$agent = $_SERVER['HTTP_USER_AGENT'];
session_start();

// Do this each time the user successfully logs in.
$_SESSION['ident'] = hash("sha256", $aip . $bip . $agent);

// Do this every time the client makes a request to the server, after authenticating
$ident = hash("sha256", $aip . $bip . $agent);
if ($ident != $_SESSION['ident'])
{
    end_session();
    header("Location: login.php");
    // add some fancy pants GET/POST var headers for login.php, that lets you
    // know in the login page to notify the user of why they're being challenged
    // for login again, etc.
}

它的作用是捕获有关用户会话的“上下文”信息,这些信息在单个会话的生存期内不应更改。用户不会同时在美国和中国使用计算机,对吗?因此,如果IP地址在同一会话中突然更改,这强烈暗示着会话劫持尝试,那么您可以通过结束会话并强制用户重新进行身份验证来保护会话。这阻止了黑客尝试,攻击者还被迫登录,而不是获得对会话的访问权限。通知用户该尝试(将其略微增加一点),然后咯咯地烦了+消息灵通的用户及其会话/信息受到保护。

我们加入了用户代理和X-FORWARDED-FOR,以尽最大努力为代理/网络背后的系统捕获会话的唯一性。这样一来,您也许可以使用更多的信息,随时保持创造力。

它不是100%,但是非常有效。

当用户离开网站并返回时,您可以采取更多措施来保护会话,使会话过期,或者强迫他们再次登录。您可以通过捕获空白的HTTP_REFERER(在URL栏中键入域)来检测用户离开并回来,或者检查HTTP_REFERER中的值是否等于您的域(用户单击了外部/精心制作的链接以转到您的域现场)。

终止会话,不要让它们无限期保持有效。

不要依赖Cookie,它们可能会被盗,这是会话劫持的攻击手段之一。


3
我遇到过这样的情况,即某个ISP(相当大,但从技术上来说是落后的)会基于重新路由用户的连接而不时更改用户浏览器的IP。这使REMOTE_ADDR检查为我们返回了假阴性。
goofballLogic

为什么要创建哈希表呢?$_SESSION['ident'] = $aip . $bip . $agent;一样安全。
丹·布雷

2
如果您让移动用户在旅途中使用您的网站并从一个接入点移到另一个接入点,则他们的IP将不断变化,并且他们将不断退出帐户。
Kareem

代理和VPN呢?实际上,每隔几分钟,使用TOR代理的任何人都会不断注销他们的帐户。
布拉德利

即使您忽略了这一点,客户端也可以操纵IP地址,因此无论如何也不能说服攻击者。
布拉德利

9

尝试中所描述的安全cookie协议文件由刘,科瓦奇,黄,和豪达:

如文件中所述:

在客户端和服务器之间运行的安全cookie协议需要提供以下四个服务:身份验证,机密性,完整性和防重播。

至于易于部署:

在效率方面,我们的协议不涉及任何数据库查找或公共密钥加密。在可部署性方面,我们的协议可以轻松地部署在现有的Web服务器上,并且不需要更改Internet Cookie规范。

简而言之:它安全,轻便,对我来说很棒。


9
您的链接是协议的规范-您是否有实现的链接?那太好了-谢谢。
亚当

9

无法阻止会话100%激越会话,但是通过某种方法,我们可以减少攻击者激越会话的时间。

防止会话干扰的方法:

1-始终使用带有ssl证书的会话;

2-仅在httponly设置为true的情况下发送会话cookie(防止JavaScript访问会话cookie)

2-在登录和注销时使用会话重新生成ID(请注意:请勿在每个请求中使用会话重新生成,因为如果您有连续的ajax请求,则有机会创建多个会话。)

3-设置会话超时

4-将浏览器用户代理存储在$ _SESSION变量中,并在每次请求时与$ _SERVER ['HTTP_USER_AGENT']进行比较

5-设置令牌cookie,并将该cookie的过期时间设置为0(直到关闭浏览器)。为每个请求重新生成cookie值。(对于ajax请求,请不要重新生成令牌cookie)。例如:

    //set a token cookie if one not exist
    if(!isset($_COOKIE['user_token'])){
                    //generate a random string for cookie value
        $cookie_token = bin2hex(mcrypt_create_iv('16' , MCRYPT_DEV_URANDOM));

        //set a session variable with that random string
        $_SESSION['user_token'] = $cookie_token;
        //set cookie with rand value
        setcookie('user_token', $cookie_token , 0 , '/' , 'donategame.com' , true , true);
    }

    //set a sesison variable with request of www.example.com
    if(!isset($_SESSION['request'])){
        $_SESSION['request'] = -1;
    }
    //increment $_SESSION['request'] with 1 for each request at www.example.com
    $_SESSION['request']++;

    //verify if $_SESSION['user_token'] it's equal with $_COOKIE['user_token'] only for $_SESSION['request'] > 0
    if($_SESSION['request'] > 0){

        // if it's equal then regenerete value of token cookie if not then destroy_session
        if($_SESSION['user_token'] === $_COOKIE['user_token']){
            $cookie_token = bin2hex(mcrypt_create_iv('16' , MCRYPT_DEV_URANDOM));

            $_SESSION['user_token'] = $cookie_token;

            setcookie('user_token', $cookie_token , 0 , '/' , 'donategame.com' , true , true);
        }else{
            //code for session_destroy
        }

    }

            //prevent session hijaking with browser user agent
    if(!isset($_SESSION['user_agent'])){
        $_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
    }

    if($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']){
      die('session hijaking - user agent');
    }

注意:不要使用ajax请求重新生成令牌cookie。注意:上面的代码是示例。注意:如果用户注销,则cookie令牌以及会话都必须销毁

6-使用用户ip防止会话干扰不是一个好办法,因为有些用户ip随每个请求而变化。影响有效的用户

7-我个人将会话数据存储在数据库中,由您决定采用哪种方法

如果您发现我的方法有误,请纠正我。如果您还有其他方法可以防止会话中断,请告诉我。


嗨,我试图防止会话劫持(在ASP.NET中),并考虑了您建议的所有上述步骤。这是大概的工作方式,但是当我使用浏览器的InPrivateBrowsing / inognito模式时,会话被劫持了。您能否建议在sessionId字符串中添加任何其他内容?
Vishwanath Mishra

4

确保您不对会话ID使用递增整数。使用GUID或其他长时间随机生成的字符串会更好。


3

有很多方法可以防止会话劫持,但是所有这些方法都在降低用户满意度或不安全。

  • IP和/或X-FORWARDED-FOR检查。这些工作非常安全,但是可以想象用户的痛苦。他们来到带有WiFi的办公室,获得了新的IP地址,并丢失了会话。再次登录。

  • 用户代理检查。与上述相同,新版本的浏览器已退出,您丢失了会话。另外,这些确实很容易“破解”。对于黑客来说,发送伪造的UA字符串是微不足道的。

  • localStorage令牌。登录时生成令牌,将其存储在浏览器存储中,并将其存储到加密的cookie(在服务器端加密)。这对用户没有副作用(localStorage在浏览器升级后仍然存在)。它不那么安全-只是模糊不清的安全性。另外,您可以向JS添加一些逻辑(加密/解密)以进一步使其模糊。

  • 重新发布Cookie。这可能是正确的方法。诀窍是一次只允许一个客户端使用cookie。因此,活跃用户将每小时或更短时间重新发布一次Cookie。如果发布了新的cookie,则旧的cookie将失效。骇客仍然是可能的,但要困难得多-骇客或有效用户都会被拒绝访问。


1

让我们考虑一下,在登录阶段,客户端和服务器可以就秘密的盐值达成一致。此后,服务器会在每次更新时提供一个计数值,并期望客户端以(秘密盐+计数)的哈希值进行响应。潜在的劫机者无法获取此秘密盐值,因此无法生成下一个哈希。


3
但是,您如何将这种盐存储在没有人可以窃取的客户端上?
Dcortez

1

AFAIK会话对象无法在客户端访问,因为它存储在Web服务器上。但是,会话ID被存储为Cookie,它使Web服务器可以跟踪用户的会话。

为防止使用会话ID进行会话劫持,您可以在会话对象内部存储一个哈希字符串,该字符串是使用远程属性和远程端口这两个属性组合而成的,可以在请求对象内部的Web服务器上进行访问。这些属性将用户会话绑定到用户登录的浏览器。

如果用户从同一系统上的其他浏览器或隐身模式登录,则IP地址将保持不变,但端口将不同。因此,当访问该应用程序时,Web服务器将为用户分配不同的会话ID。

下面是我通过将会话ID从一个会话复制到另一个会话而实现和测试的代码。效果很好。如果存在漏洞,请让我知道您是如何模拟的。

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    HttpSession session = request.getSession();
    String sessionKey = (String) session.getAttribute("sessionkey");
    String remoteAddr = request.getRemoteAddr();
    int remotePort = request.getRemotePort();
    String sha256Hex = DigestUtils.sha256Hex(remoteAddr + remotePort);
    if (sessionKey == null || sessionKey.isEmpty()) {
        session.setAttribute("sessionkey", sha256Hex);
        // save mapping to memory to track which user attempted
        Application.userSessionMap.put(sha256Hex, remoteAddr + remotePort);
    } else if (!sha256Hex.equals(sessionKey)) {
        session.invalidate();
        response.getWriter().append(Application.userSessionMap.get(sessionKey));
        response.getWriter().append(" attempted to hijack session id ").append(request.getRequestedSessionId()); 
        response.getWriter().append("of user ").append(Application.userSessionMap.get(sha256Hex));
        return;
    }
    response.getWriter().append("Valid Session\n");
}

我使用了SHA-2算法,使用baeldung的SHA-256 Hashing中给出的示例对值进行哈希处理

期待您的评论。


@zaph很抱歉,但我没有添加答案来获得声望。重点也不是SHA-2加密。但是事实是,我能够检测到另一个用户的会话ID Cookie在另一个用户的会话中的使用情况,即,与原始问题一样,会话劫持。我测试了解决方案,发现它可以工作。但是我不是这方面的专家,所以我希望社区检查我的回答是否足够好。也许您可以看到我的代码段的作用,然后确定它是否回答了问题。谢谢!
Jzf

@zaph感谢您指出错误。根据您的建议,我已经更新了我的答案。如果您认为答案有帮助,请取消您的不赞成投票。
Jzf

0

为了降低风险,您还可以将原始IP与会话相关联。这样,攻击者必须在同一专用网络中才能使用会话。

检查引荐标头也可以是一种选择,但是更容易被欺骗。


7
不可以,您不能使用原始IP,因为它可能会更改-通过动态IP,在用户临时断开连接时更改,或者通过(隐式或显式)代理服务器场使用。此外,来自同一ISP的会话劫持者可能会使用与合法用户相同的代理和IP ...
Olaf Kock,

1
PHP-Nuke的有关于他们的会话的方式一个很好的网页,他们详细讨论如何挂钩的IP不工作,所有的互联网服务供应商phpnuke.org/...
Sembiance

4
更改Ip在移动互联网提供商中非常普遍。使用沃达丰,我的IP随每个请求而改变。
布莱斯

1
有点旧的帖子,但进一步。IP是一个坏主意。如前所述,移动用户倾向于漫游IP。过去,某些ISP也具有漫游IP(例如AOL),但是由于IPv4 IP的短缺,这种方法现在变得越来越流行。此类ISP包括Plus net和BT
Peter

-15

保护者:

$ip=$_SERVER['REMOTE_ADDER'];
$_SESSEION['ip']=$ip;

12
我看不到你在这里做什么。
samayo
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.