日常踩坑中遇到的cookie問題: 跨域,特殊字符

這篇文章主要用於記錄自己平時遇到的cookie相關的問題. 如跨域設置cookie, cookie特殊字符被截斷, 中文cookie導致報錯.

跨域設置cookie

這個場景一般是在賬號打通中會遇到,兩個系統使用同一個賬號體系,但是不同的域名。登陸一個系統的時候自動登陸到另一個系統。例如在 a.com 下同時把 cookie 設置到 b.com 下。

一般的處理方式是:在登陸完成之後,返回另一個域的setCookieUrl和獲取cookie的信息(可以是加密的cookie,或者是把cookie存入緩存返回key,保證隨機且複雜的key,且過期時間儘可能短)。
然後再讓前端發起另一個域的異步請求設置cookie。 (在 a 的域下請求 b 域的url並設置cookie)

但是對於 chrome80 之後的版本,chrome默認不支持跨域設置cookie。解決方式有兩個:

  • 引導用戶設置瀏覽器支持三方cookie,以及在 chrome://flags 下面修改以下兩項設置. 大概的做法就是:在登陸前,先發一個跨域設置cookie的請求,再發一個請求判斷是否設置成功. 不成功就引導用戶去修改瀏覽器設置.

  • 在 cookie 中添加 SameSite=None; Secure 字段,且必須使用 https協議. 不能直接用 Cookie 類, Cookie無SameSite屬性. 需手動在response header 中設置,如:
    response.addHeader("Set-Cookie", "key=name; SameSite=None; Secure")

但是, 對於部分瀏覽器(如ios微信內置瀏覽器) 仍然不支持跨域設置cookie. 這個時候就只能先跳到相同的域名的中間頁下面, 再請求setCookieUrl, 然後再回到之前的頁面. 流程比上面要多一些.

cookie 包含特殊字符導致被截斷

如:
header中: cookie:"key=value@1234"
然後使用 HttpServletRequest.getCookies 得到的cookie的則是key=value。實際上完整的value還是存在header中.

這個主要原因是使用了 LegacyCookieProcessor 作爲 cookie處理器,value包含以下特殊字符會被截斷。

// Excludes '/' since configuration controls whether or not to treat '/' as
// a separator
private static final char[] HTTP_SEPARATORS = new char[] {
   
   
        '\t', ' ', '\"', '(', ')', ',', ':', ';', '<', '=', '>', '?', '@',
        '[', '\\', ']', '{', '}' };  

推薦一篇相關的文章: https://juejin.cn/post/6844903918330183694

看完這篇文章,我猜可能就是前面的人因爲setCookie的時候在 domain 裏面加了 . 才改成 LegacyCookieProcessor的, 但其實沒必要, domain前面根本不用加. .

解決方式:

  • 不在cookie中使用特殊字符
  • 不使用LegacyCookieProcessor。
  • 自己從 request 的 header 讀取 Cookie,然後自己解析

因爲cookie是外部傳來的, 不能修改cookie. 這裏選擇第三種方式, 影響範圍小,風險最小.

private static List<Cookie> parseCookies(HttpServletRequest request) {
   
   
        String cookieStr = request.getHeader("Cookie");
        if (StringUtils.isEmpty(cookieStr)) {
   
   
            return Collections.emptyList();
        }
        List<Cookie> cookies = new ArrayList<Cookie>();
        String[] cks = cookieStr.split(";");
        for (String ckStr : cks) {
   
   
            try {
   
   
                String[] ck = ckStr.trim().split("=", 2);
                if (ck.length<2) continue;
                Cookie cookie = new Cookie(ck[0], ck[1]);
                cookies.add(cookie);
            } catch (Exception e) {
   
   
                log.error("parseCookies error.", e);
            }
        }
        return cookies;
    }

cookie 中有中文導致後端報錯

cookie中最好不要用中文, 否則服務端可能處理不了導致報錯. 具體原因也是上面那個 LegacyCookieProcessor 解析cookie時拋出的異常.

注意: 不僅自己不要使用中文cookie, 也要注意前端有沒有給傳中文cookie!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章