【问题标题】:Cookies don't work over WebSocket on Apple devicesCookie 无法在 Apple 设备上通过 WebSocket 工作
【发布时间】:2017-12-10 19:52:51
【问题描述】:

我已经在 WebSocket 之前的阶段设置和检索 cookie 以识别用户。我假设一切都可以通过典型的 HTTP 交换进行。

这在我测试过的所有浏览器上都完美运行,但开始有报告称,在 iPhone 上登录根本不会保留,这表明 cookie 要么未设置,要么未发送回服务器

// fret not, safety checks removed for brevity

const (
    sessionKeyCookieName string = "session-key"
    webSocketPath        string = "/ws"
)

func serveWs(w http.ResponseWriter, r *http.Request) {
    var sessionKey [sha1.Size]byte
    var u *user
    for _, cookie := range r.Cookies() {
        if cookie.Name != sessionKeyCookieName {
            continue
        }
        slice, err := base64.StdEncoding.DecodeString(cookie.Value)
        if err != nil {
            continue
        } else {
            copy(sessionKey[:], slice)
        }
    }
    u, _ = getUserBySessionKey(sessionKey)

    // regenerate key. TODO: does that add security?
    rand.Read(sessionKey[:])

    header := make(http.Header)
    header.Add("Set-Cookie", (&http.Cookie{
        Name:     sessionKeyCookieName,
        Value:    base64.StdEncoding.EncodeToString(sessionKey[:]),
        MaxAge:   int(sessionLength.Seconds()),
        HttpOnly: true,
        Domain:   strings.SplitN(r.Host, ":", 2)[0],
    }).String())

    ws, err := upgrader.Upgrade(w, r, header)
    if err != nil {
        if _, ok := err.(websocket.HandshakeError); !ok {
            log.Println(err)
        }
        return
    }

    // do things to `user` so their messages go to where they're needed

    go c.writePump()
    c.readPump()
}

在 Firefox 网络开发工具上看到的标题

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: eSazcZyZKj2dfa2UWSY+a4wThC8=
Access-Control-Allow-Origin: *
Set-Cookie: session-key=RNStK2z2gAsan7DyNKQ+efjyr7c=; Domain=redacted.org; Max-Age=259200; HttpOnly

我是否跳过了一些允许 Safari 存储 cookie 的步骤,或者这是一个问题上游1

附:我真的很想保留这种方法,因为我可以使用仅限 HTTP 的 cookie,这主要确保 JavaScript 无法访问它们。


  1. 看起来加里也有similar issues。简而言之,cookie 不会通过 WebSockets 传回。

【问题讨论】:

  • 请注意,非安全 cookie 和安全 cookie 分别存储在 Safari 上,防止安全 cookie 暴露于非安全连接。尝试使用来自http 相关cookie 的wss,或尝试使用https 相关cookie 进行ws 连接,注定会失败。会不会是您将 TLS 与非 TLS 连接混合在一起?
  • 不可能,@Myst,我现在没有使用加密。
  • 目标主机名是否有任何特殊性(例如“localhost”或非 TLD)?一些浏览器/客户端对其中一些有特殊处理,包括包含 cookie(例如,如果 IE 的域属性为“localhost”,则 IE 不会包含 cookie)。您是否测试过其他主机名?只是猜测:)
  • @HariLubovac 添加了实际发送的标头。这一切都发生在同一个域上。

标签: ios cookies websocket safari


【解决方案1】:

TLDR:这是HttpOnly 标志。


似乎虽然某些浏览器确实允许 WebSocket 连接响应中的 Set-Cookie 标头具有 HttpOnly 标志,但 iOS Safari 将这种情况视为“非 HTTP”并阻止此情况。

有趣的是,虽然无法设置 HttpOnly cookie,但在连接 WebSocket 时,HttpOnly cookie 会在请求标头中发送。这留下了一对选择:

  • 增加风险并省略HttpOnly
  • 使用另一个纯 HTTP 请求设置您的 cookie,很可能是一个甚至没有响应正文的请求。

我认为 iOS Safari 的行为与 RFC 6265 Storage model 中所述的行为相比是不正确的

【讨论】:

    【解决方案2】:

    如果您的 Set-Cookie 标头在其他浏览器中有效,我猜这是上游问题,特别是 iOS Safari 能够阻止 cookie。默认情况下,iOS Safari 会阻止 3rd 方 cookie。

    Can a webpage in mobile Safari check whether Settings > Safari > Accept Cookies 'From visited' or 'Always' is selected?

    如果 cookie 被阻止,您将无法使用它们。如果您需要 cookie,请通过在登录页面上设置一个 cookie 来检测支持,例如 enabled=1,然后在 /ws 处理程序中检查它。如果它出现空白并且 cookie 被阻止,您可以尝试重定向到 /please-enable-cookies 以要求用户为您的站点启用 cookie。

    另一种选择是将签名的会话数据存储在本地存储中,并将其包含在每个请求中的 Authorization 标头中。 https://jwt.io/

    【讨论】:

      猜你喜欢
      • 2011-07-02
      • 2014-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-09
      • 2018-12-10
      • 2017-11-04
      • 1970-01-01
      相关资源
      最近更新 更多