具体来说,这是关于使用客户端会话 cookie 来识别服务器上的会话时的情况。

最好的答案是对整个网站使用 SSL/HTTPS 加密,并且可以最好地保证中间人攻击无法嗅探现有的客户端会话 cookie?

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

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

有帮助吗?

解决方案

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

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

编辑: :这个答案最初写于2008年。现在已经是 2016 年了,没有理由不在整个网站上使用 SSL。不再有纯文本 HTTP!

其他提示

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

至少,确保旧饼干在一段时间后失去其价值。当 cookie 停止工作时,即使是成功的劫持攻击也会被挫败。如果用户拥有一个多月前登录的会话的 cookie,请让他们重新输入密码。确保每当用户单击站点的“注销”链接时,旧的会话 UUID 永远不会再次使用。

我不确定这个想法是否可行,但这里是:将序列号添加到会话 cookie 中,可能是这样的字符串:

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

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

请记住,您的用户可能拥有不止一台计算机,因此他们可能有多个活动会话。不要做一些迫使他们每次在计算机之间切换时重新登录的事情。

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

对于非 SSL 认证站点,我使用以下方法取得了很大成功。

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

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

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

我绝不是该主题的专家,我在这个特定主题上有一些经验,希望其中的一些对那里的任何人有所帮助。

// 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 地址在同一会话中突然发生变化,则强烈暗示会话劫持尝试,因此您可以通过结束会话并强制用户重新进行身份验证来保护会话。这会阻止黑客尝试,攻击者还被迫登录而不是获得会话访问权限。通知用户该尝试(用ajax将其调高一点),vola,稍微恼火+知情的用户,他们的会话/信息受到保护。

我们引入 User Agent 和 X-FORWARDED-FOR 来尽最大努力捕获代理/网络后面的系统会话的唯一性。您也许可以使用更多信息,请随意发挥创意。

虽然不是100%有效,但是非常有效。

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

使会话过期,不要让它们无限期地保持有效。

不要依赖 cookie,它们可能会被窃取,它是会话劫持的攻击媒介之一。

尝试中描述的安全 Cookie 协议 Liu、Kovacs、Huang 和 Gouda 的论文:

正如文档中所述:

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

至于部署的便捷性:

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

简而言之:它安全、轻便,对我来说非常有用。

没有办法 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 令牌以及会话

6 - 使用用户 IP 来防止会话劫持并不是一个好方法,因为某些用户 IP 会随着每个请求而改变。影响有效用户的因素

7 - 我个人将会话数据存储在数据库中,这取决于你采用什么方法

如果您发现我的方法有错误,请纠正我。如果您有更多方法来防止会话 hyjaking,请告诉我。

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

有很多方法可以创建针对会话劫持的保护,但是所有这些方法要么降低用户满意度,要么不安全。

  • IP 和/或 X-FORWARDED-FOR 检查。这些有效,而且非常安全......但想象一下用户的痛苦。他们来到有 WiFi 的办公室,获得新的 IP 地址并失去会话。还得重新登录。

  • 用户代理检查。与上面相同,新版本的浏览器已发布,您将丢失一个会话。此外,这些很容易被“破解”。对于黑客来说,发送虚假的 UA 字符串是微不足道的。

  • 本地存储令牌。登录时生成一个令牌,将其存储在浏览器存储中并将其存储到加密的 cookie(在服务器端加密)。这对用户没有副作用(localStorage 通过浏览器升级仍然存在)。它并不那么安全——因为它只是通过默默无闻来实现安全。此外,您可以向 JS 添加一些逻辑(加密/解密)以进一步模糊它。

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

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

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 哈希

期待您的评论。

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

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

保护方式:

$ip=$_SERVER['REMOTE_ADDER'];
$_SESSEION['ip']=$ip;
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top