131

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

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

或许次佳对存储在会话 cookie 中的会话值本身使用某种加密?

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

4

14 回答 14

144

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

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

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

于 2008-08-22T17:11:46.723 回答
42

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

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

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

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

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

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

于 2008-08-23T18:07:32.603 回答
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 分钟过期一次,重新颁发该令牌,并将会话与新数据重新同步。如果数据中有任何不匹配,请注销用户或让他们重新验证其会话。

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

于 2011-07-04T00:11:14.843 回答
21
// 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 地址在同一会话中突然发生变化,强烈暗示会话劫持尝试,那么您可以通过结束会话并强制用户重新进行身份验证来保护会话。这阻止了黑客攻击,攻击者也被迫登录而不是访问会话。将尝试通知用户(将其放大一点),vola,有点恼火+知情的用户,他们的会话/信息受到保护。

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

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

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

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

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

于 2013-12-03T21:24:19.123 回答
12

没有办法 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 - 我个人将会话数据存储在数据库中,取决于您采用什么方法

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

于 2013-11-01T12:16:10.047 回答
9

试试Liu、Kovacs、Huang 和 Gouda在这篇论文中描述的 Secure Cookie 协议:

如文件所述:

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

至于易于部署:

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

简而言之:它安全、轻巧,非常适合我。

于 2008-11-24T10:54:46.237 回答
4

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

于 2008-08-23T18:10:25.840 回答
4

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

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

  • 用户代理检查。和上面一样,新版本的浏览器已经出来了,你失去了一个会话。此外,这些真的很容易“破解”。黑客发送虚假的 UA 字符串是微不足道的。

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

  • Cookie 重新发行。这可能是正确的方法。诀窍是一次只允许一个客户端使用一个cookie。因此,活跃用户将每隔一小时或更短时间重新发布 cookie。如果发出新的 cookie,旧的 cookie 将失效。黑客仍然是可能的,但更难做到 - 无论是黑客还是有效用户都将被拒绝访问。

于 2015-08-17T09:57:55.903 回答
2

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 中给出的示例对值进行散列

期待您的评论。

于 2018-02-10T18:13:05.430 回答
1

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

于 2014-02-14T19:31:53.303 回答
0

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

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

于 2008-08-22T17:04:53.527 回答
0

仅使用 SSL,而不是在会话 id 中加密 HTTP_USER_AGENT 并在每个请求上验证它,只需将 HTTP_USER_AGENT 字符串也存储在会话数据库中。

现在您只有一个简单的基于服务器的字符串与 ENV'HTTP_USER_AGENT' 进行比较。

或者,您可以在字符串中添加某种变体,以便对浏览器版本更新更加稳健。你可以拒绝某些 HTTP_USER_AGENT id。(空的,即)不能完全解决问题,但它至少增加了一点复杂性。

另一种方法可能是使用更复杂的浏览器指纹识别技术,并将这些值与 HTTP_USER_AGENT 结合起来,并在单独的标头值中不时发送这些值。但是,您应该加密会话 ID 本身中的数据。

但这使它变得更加复杂,并提高了每次请求解密时的 CPU 使用率。

于 2021-02-10T21:33:51.697 回答
0

如果 ISP 劫持证书验证,则 ISP 可能会发起中间人攻击。尤其是在证书颁发机构受损的情况下。

所以我相信你不能阻止来自 ISP 的会话劫持。尤其是当法律力量带有根据执法机构从 CA 获得的假证书时。

您将需要网络外部的一些东西来保护您的会话,例如一个时间垫。这就是为什么一次性垫如此敏感,只能由少数公司出售的原因。

小心,一次性垫可能会被利用。选择您的专业一次性垫。

于 2021-03-11T04:28:10.363 回答
-15

通过以下方式保护:

$ip=$_SERVER['REMOTE_ADDER'];
$_SESSEION['ip']=$ip;
于 2011-06-30T09:36:18.843 回答