Cookie 与 CSRF 攻击:如何使用 SameSite 属性防御攻击

Cookie 与 CSRF 攻击:如何使用 SameSite 属性防御攻击

HTTP Set-Cookie 响应头用于将 cookie 从服务器发送到用户代理,以便用户代理稍后将其发送回服务器。这可以用于跟踪用户会话、记住用户偏好或存储其他与用户相关的信息。

工作原理

当用户访问网站时,服务器可以向用户发送一个或多个 Set-Cookie 响应头。浏览器通常会存储 cookie 并将其与发送到同一服务器的请求一起发送在 Cookie HTTP 头中。

主要属性

  • Name: cookie 的名称。
  • Value: cookie 的值。
  • Expires: cookie 的到期时间。
  • Domain: cookie 所属的域。
  • Path: cookie 所属的路径。
  • Secure: cookie 是否仅在 HTTPS 连接上发送。
  • HttpOnly: cookie 是否仅可由服务器端脚本访问。
  • SameSite: cookie 是否在跨站点请求中发送。

示例代码

# 使用 Flask 框架设置 cookie

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    # 设置一个名为 "session_id" 的 cookie
    response = make_response("Hello, world!")
    response.set_cookie("session_id", "1234567890")
    return response

if __name__ == "__main__":
    app.run()

注释

  • cookie 的名称和值必须是有效的 ASCII 字符。
  • cookie 的到期时间可以是绝对时间或相对时间。
  • cookie 的域和路径必须是有效的 URL。
  • Secure 和 HttpOnly 属性可以提高安全性。
  • SameSite 属性可以防止 CSRF 攻击。

错误

  • 如果 cookie 名称或值无效,则会引发错误。
  • 如果 cookie 的到期时间无效,则会引发错误。
  • 如果 cookie 的域或路径无效,则会引发错误。

中文资源

  • 阮一峰的网络日志 - HTTP 协议中的 Cookie: [移除了无效网址]
  • 菜鸟教程 - HTTP Cookie: [移除了无效网址]

总结

HTTP Set-Cookie 响应头是 HTTP 协议中一个重要的部分,用于在服务器和用户代理之间存储信息。它可以用于各种目的,例如跟踪用户会话、记住用户偏好或存储其他与用户相关的信息。

Set-Cookie HTTP 响应头用于将 cookie 从服务器发送到用户代理,以便用户代理稍后可以将其发送回服务器。要发送多个 cookie,应在同一响应中发送多个 Set-Cookie 标头。

警告:根据 Fetch 规范的要求,浏览器会阻止前端 JavaScript 代码访问 Set-Cookie 标头,该规范将 Set-Cookie 定义为 forbidden response-header name ,而 must be filtered out 来自暴露给前端代码的任何响应。

有关更多信息,请参阅 Using HTTP cookies 指南。

Header type Response header
禁止的标头名称 no
禁止的响应标头名称 yes

Syntax

Set-Cookie: <cookie-name>=<cookie-value>
Set-Cookie: <cookie-name>=<cookie-value>; Expires=<date>
Set-Cookie: <cookie-name>=<cookie-value>; Max-Age=<number>
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>
Set-Cookie: <cookie-name>=<cookie-value>; Path=<path-value>
Set-Cookie: <cookie-name>=<cookie-value>; Secure
Set-Cookie: <cookie-name>=<cookie-value>; HttpOnly

Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Strict
Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Lax
Set-Cookie: <cookie-name>=<cookie-value>; SameSite=None; Secure

// Multiple attributes are also possible, for example:
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain-value>; Secure; HttpOnly

Attributes

  • <cookie-name>=<cookie-value>

    定义 cookie 名称及其值。Cookie 定义以名称-值对开始。 <cookie-name> 可以包含任何 US-ASCII 字符,但以下字符除外:控制字符、空格或制表符。它还不得包含如下分隔符: ( ) < > @ , ; : \ " / [ ] ? = { }<cookie-value> 可以选择用双引号括起来,并包含除控制字符、 Whitespace 、双引号、逗号、分号和反斜杠之外的任何 US-ASCII 字符。 编码:许多实现对 cookie 值执行 URL 编码。然而,RFC 规范并不要求这样做。URL 编码确实有助于满足 <cookie-value> 允许的字符要求。 注意:有些 <cookie-name> 有特定的语义: __Secure- :名称以 __Secure- 开头的 Cookie(破折号是前缀的一部分)必须使用安全页面 (HTTPS) 中的 secure 标志进行设置。 __Host- :名称以 __Host- 开头的 Cookie 必须使用 secure 标志进行设置,必须来自安全页面 (HTTPS),不得指定域(因此不会发送到子域),并且路径必须为 /

  • Expires=<date>Optional

    将 cookie 的最大生命周期指示为 HTTP 日期时间戳。请参阅 Date 了解所需的格式。 如果未指定,该 cookie 将成为会话 cookie。当客户端关闭时,会话结束,之后会话 cookie 将被删除。 警告:许多网络浏览器都有会话恢复功能,可以保存所有选项卡并在下次使用浏览器时恢复它们。会话 cookie 也将被恢复,就好像浏览器从未关闭过一样。 设置 Expires 日期时,截止日期与设置 cookie 的客户端相关,而不是与服务器相关。

  • Max-Age=<number>Optional

    表示 cookie 过期之前的秒数。零或负数将使 cookie 立即过期。如果同时设置了 ExpiresMax-Age ,则 Max-Age 优先。

  • Domain=<domain-value>Optional

    定义 cookie 将发送到的主机。 如果省略,此属性默认为当前文档 URL 的主机,不包括子域。 与早期规范相反,域名 ( .example.com ) 中的前导点将被忽略。 不允许使用多个主机/域值,但如果指定了域,则始终包含子域。

  • Path=<path-value>Optional

    指示浏览器发送 Cookie 标头所请求的 URL 中必须存在的路径。 正斜杠 ( / ) 字符被解释为目录分隔符,并且子目录也会匹配。例如,对于 Path=/docs , 请求路径 /docs/docs//docs/Web//docs/Web/HTTP 将全部匹配。 请求路径 //docsets/fr/docs 将不匹配。

  • SecureOptional

    表示仅当使用 https: 方案发出请求时(本地主机除外)才将 cookie 发送到服务器,因此更能抵抗 man-in-the-middle 攻击。 注意:不要假设 Secure 阻止对 cookie 中的敏感信息(会话密钥、登录详细信息等)的所有访问。如果未设置 HttpOnly cookie 属性,则仍然可以通过访问客户端硬盘或从 JavaScript 读取/修改具有此属性的 Cookie。 不安全站点 ( http: ) 无法设置具有 Secure 属性的 cookie(自 Chrome 52 和 Firefox 52 起)。对于 Firefox,当 localhost 设置 Secure 属性时, https: 要求将被忽略(自 Firefox 75 起)。

  • HttpOnlyOptional

    禁止 JavaScript 访问 cookie,例如通过 Document.cookie 属性。请注意,使用 HttpOnly 创建的 cookie 仍将随 JavaScript 发起的请求一起发送,例如,在调用 XMLHttpRequest.send()fetch() 时。这可以减轻针对跨站点脚本( XSS )的攻击。

  • SameSite=<samesite-value>Optional

    控制是否随跨站点请求发送 cookie,从而提供一些针对跨站点请求伪造攻击的保护 ( CSRF )。 可能的属性值为: Strict 表示浏览器仅针对同站点请求发送 Cookie,即来自设置 Cookie 的同一站点的请求。如果请求源自不同的域或方案(即使具有相同的域),则不会发送具有 SameSite=Strict 属性的 cookie。 Lax 意味着 Cookie 不会在跨站点请求(例如加载图像或框架的请求)上发送,而是在用户从外部站点导航到源站点(例如,点击链接时)时发送。如果未指定 SameSite 属性,这是默认行为。 None 意味着浏览器会通过跨站点请求和同站点请求发送 cookie。设置此值时还必须设置 Secure 属性,例如 SameSite=None; Secure 注意:与 SameSite Cookies 相关的标准最近发生了变化,例如: 如果未指定 SameSite ,则 cookie 发送行为为 SameSite=Lax 。以前,默认情况下会为所有请求发送 cookie。 具有 SameSite=None 的 Cookie 现在还必须指定 Secure 属性(换句话说,它们需要安全上下文)。 如果使用不同的方案( http:https: )发送,来自同一域的 Cookie 将不再被视为来自同一站点。 有关特定浏览器实现的信息,请参阅 Browser compatibility 表(行: " SameSite : Defaults to Lax " 、 " SameSite : Secure context required" 和 " SameSite : URL scheme-aware (" schemeful ")" )。

Examples

当客户端关闭时,会话 cookie 将被删除。如果 Cookie 未指定 ExpiresMax-Age 属性,则它们是会话 Cookie。

Set-Cookie: sessionId=38afes7a8

永久 cookie 将在特定日期 ( Expires ) 或特定时间长度 ( Max-Age ) 后删除,而不是在客户端关闭时删除。

Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT
Set-Cookie: id=a3fWa; Max-Age=2592000

Invalid domains

不包括设置它的服务器的域的 cookie should be rejected by the user agent

如果由 originalcompany.com 上托管的服务器设置以下 cookie 将被拒绝:

Set-Cookie: qwerty=219ffwef9w0f; Domain=somecompany.co.uk

服务域的子域的 cookie 将被拒绝。

如果由 example.com 上托管的服务器设置以下 cookie 将被拒绝:

Set-Cookie: sessionId=e8bb43229de9; Domain=foo.example.com

仅当使用来自安全 (HTTPS) 源的 secure 属性设置了前缀为 __Secure-__Host- 的 Cookie 名称时,才可以使用它们。

此外,带有 __Host- 前缀的 cookie 必须具有 / 路径(表示主机上的任何路径),并且不得具有 Domain 属性。

警告:对于不实现 cookie 前缀的客户端,您不能指望这些额外的保证,并且带前缀的 cookie 将始终被接受。

// 来自安全来源 (HTTPS) 时两者均被接受
Set-Cookie: __Secure-ID=123; Secure; Domain=example.com
Set-Cookie: __Host-ID=123; Secure; Path=/

// 由于缺少安全属性而被拒绝
Set-Cookie: __Secure-id=1

// 由于缺少 Path=/ 属性而被拒绝
Set-Cookie: __Host-id=1; Secure

// 由于设置域而被拒绝
Set-Cookie: __Host-id=1; Secure; Path=/; Domain=example.com

Specifications

Specification
HTTP 状态管理机制 # sane-set-cookie

Browser compatibility

Desktop Mobile
Chrome Edge Firefox Internet Explorer Opera Safari WebView Android Chrome Android 安卓版火狐浏览器 Opera Android iOS 上的 Safari Samsung Internet
HttpOnly 1 12 3 9 11 5 37 Yes 4 Yes 4 Yes
Max-Age Yes 12 Yes 8 Yes Yes Yes Yes Yes Yes Yes Yes
SameSite 51 16 60 11 39 13 macOS 10.14 (Mojave) 上的 Safari 13 将 SameSite=None 和无效值视为 Strict 。此问题已在版本 10.15 (Catalina) 及更高版本中修复。 12 在 10.15 Catalina 之前的 macOS 中,将 SameSite=None 和无效值视为 Strict 。参见 bug 198181 51 51 60 41 13 12.2 在 13 之前的 iOS 中,将 SameSite=None 和无效值视为 Strict 。请参阅 bug 198181 5.0
Set-Cookie Yes 12 Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
cookie_prefixes 49 79 50 No 36 Yes 49 49 50 36 Yes 5.0

Compatibility notes

  • 从 Chrome 52 和 Firefox 52 开始,不安全站点 ( http: ) 无法再设置具有 Secure 属性的 cookie。

See also

Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie

原文:https://runebook.dev/zh/docs/http/headers/set-cookie

posted @ 2024-04-04 20:00  hirak0  阅读(388)  评论(0编辑  收藏  举报