聊聊Cookie的SameSite屬性

背景

前幾天在業(yè)務(wù)開發(fā)中,在iframe中嵌入打開一個xxx的url鏈接擒权,在鏈接的主頁中疫稿,會跳轉(zhuǎn)到另一個登錄的頁面恢着,然而登錄一直失敗,失敗原因是xxx的服務(wù)端沒有收到對應(yīng)的cookie危纫。但是在瀏覽器中的頂層搜索打開xxx的url鏈接宗挥,在跳轉(zhuǎn)到另一個登錄的頁面后乌庶,就可以正常的登錄。

頁面嵌套關(guān)系如下所示:

image.png

Cookie簡介:

HTTP 協(xié)議是無狀態(tài)的契耿,但可以通過 Cookie 來維持客戶端與服務(wù)端之間的“會話狀態(tài)”瞒大。

簡單來說就是:服務(wù)端通過 Set-Cookie 響應(yīng)頭設(shè)置 Cookie 到客戶端,而客戶端在下次向服務(wù)器發(fā)送請求時添加名為 Cookie 的請求頭搪桂,以攜帶服務(wù)端之前“埋下”的內(nèi)容透敌,從而使得服務(wù)端可以識別客戶端的身份。

場景模擬

本地代碼示例如下:

配置本地host

127.0.0.1 a.cross.com
127.0.0.1 b.test.com
127.0.0.1 a.test.com

開啟serverB:

const http = require("http");
const fs = require("fs");

let server = http.createServer((req, res) => {
    const cookie = req.headers.cookie
    console.log('cookie', cookie);
    res.writeHead(200, [
        ["Set-Cookie", "name=bbb"], // 設(shè)置 cookie
    ]);

    if (!cookie) {
        res.end("no cookie");//沒有cookie時
        return
    }
    if ("/" == req.url) {
        fs.readFile(__dirname + "/index.html", "utf-8", (err, data) => {
            if (err) {
                throw err;
            } else {
                res.end(data);
            }
        });
    } else if (req.url == "/favicon.ico") {
        res.statusCode = 204;
        res.end();
    } else {
        res.end("404 NOT Found");
    }

});
server.listen(3002, () => {
    console.log("服務(wù)器啟動成功");
});

serverB中index.html的body為:

<body>
    <div>i am B頁面</div>
</body>

在瀏覽器頂部導航欄輸入http://b.test.com:3002時踢械,正常的B頁面展示為

image.png

在A中使用iframe嵌套B的url酗电,開啟serverA:

const http = require("http");
const fs = require("fs");

let server = http.createServer((req, res) => {
    console.log(req.url);
    if ("/" == req.url) {
        fs.readFile(__dirname + "/index.html", "utf-8", (err, data) => {
            if (err) {
                throw err;
            } else {
                res.end(data);
            }
        });
    } else if (req.url == "/favicon.ico") {
        res.statusCode = 204;
        res.end();
    } else {
        res.end("404 NOT Found");
    }

});
server.listen(3001, () => {
    console.log("服務(wù)器啟動成功");
});

serverA中index.html的body為:

<body>
    <div>i am A頁面</div>
    <iframe src="http://b.test.com:3002"></iframe>//iframe嵌套B頁面的url
</body>

在chrome中打開http://a.cross.com:3001,頁面展示如下:

image.png

可以看到在A頁面的iframe中嵌套B頁面時内列,在B服務(wù)中沒有獲取到cookie信息撵术,所以沒有展示正常的B頁面。

排查問題

那接下來就一塊來分析問題吧话瞧。

既然在瀏覽器頂部導航欄輸入http://b.test.com:3002時可以正常顯示嫩与,那看一下此時的網(wǎng)絡(luò)請求情況:

image.png

看一下訪問失敗時的請求頭情況

image.png

可以看到請求異常的情況下,請求頭中沒有攜帶cookie信息交排,并且在響應(yīng)頭中會提示SameSite=Lax信息划滋。

查看b站點的Application中的Cookie信息

image.png

可以看到本地有b站點的cookie信息。為什么本地有cookie信息埃篓,但是請求的時候request header中沒有攜帶此cookie信息呢处坪?

查找資料得知,從 Chrome 80 開始架专,如果不指定 SameSite 就等效于設(shè)置為 Lax同窘。

SameSite屬性

SameSite 是 HTTP 響應(yīng)頭 Set-Cookie的屬性之一。它允許聲明該 Cookie 是否僅限于第一方或者同一站點上下文胶征。

SameSite 可以有下面三種值:

  1. Strict 僅允許一方請求攜帶 Cookie塞椎,即瀏覽器將只發(fā)送相同站點請求的 Cookie,即當前網(wǎng)頁 URL 與請求目標 URL 完全一致睛低。
  2. Lax 允許部分第三方請求攜帶 Cookie案狠。
  3. None 無論是否跨站都會發(fā)送 Cookie。

之前默認是 None 的钱雷,Chrome80 后默認是 Lax骂铁。

Lax的情況見下表:

請求類型 示例 正常情況 Lax
鏈接 <a href="..."></a> 發(fā)送 Cookie 發(fā)送 Cookie
預加載 <link rel="prerender" href="..."/> 發(fā)送 Cookie 發(fā)送 Cookie
GET 表單 <form method="GET" action="..."> 發(fā)送 Cookie 發(fā)送 Cookie
POST 表單 <form method="POST" action="..."> 發(fā)送 Cookie 不發(fā)送
iframe <iframe src="..."></iframe> 發(fā)送 Cookie 不發(fā)送
AJAX $.get("...") 發(fā)送 Cookie 不發(fā)送
Image <img src="..."> 發(fā)送 Cookie 不發(fā)送

當sameSite為Lax時,post罩抗、iframe拉庵、ajax、image的跨站請求都不會發(fā)送cookie套蒂。

要理解上面的規(guī)則钞支,還需要了解一下跨域和跨站的區(qū)別茫蛹。

跨域和跨站

首先要理解的一點就是跨站和跨域是不同的。同站(same-site)/跨站(cross-site)和第一方(first-party)/第三方(third-party)是等價的烁挟。但是與瀏覽器同源策略(SOP)中的同源(same-origin)/跨域(cross-origin)是完全不同的概念婴洼。

同源策略的同源是指兩個 URL 的協(xié)議/主機名/端口一致。例如撼嗓,https://www.baidu.com柬采,它的協(xié)議是 https,主機名是 www.baidu.com且警,端口是 443粉捻。

同源策略作為瀏覽器的安全基石,其同源判斷是比較嚴格的斑芜。相對而言肩刃,Cookie中的同站判斷就比較寬松:只要兩個 URL 的 eTLD+1 相同即可,不需要考慮協(xié)議和端口押搪。其中树酪,eTLD 表示有效頂級域名浅碾,注冊于 Mozilla 維護的公共后綴列表(Public Suffix List)中大州,例如,.com垂谢、.co.uk厦画、.github.io 等。eTLD+1 則表示滥朱,有效頂級域名+二級域名根暑,例如 baidu.com 等。

舉幾個例子徙邻,www.taobao.comwww.baidu.com 是跨站排嫌,a.baidu.comb.baidu.com是同站,a.github.iob.github.io 是跨站(注意是跨站)缰犁。

在上面的模擬示例中我使用的chrome瀏覽器的版本是107版本淳地,雖然本地是有cookie信息,但是SameSite為空帅容,也就是沒有設(shè)置颇象,所以默認SameSite=Lax,導致在A頁面訪問iframe中的B站點時并徘,是跨站的方式遣钳,不會發(fā)送B站點的cookie信息。

解決方案

這種問題的解決方案有以下幾種

1麦乞、服務(wù)器在set-cookie時蕴茴,設(shè)置SameSite=None; Secure劝评。但是這里需要注意:

  • HTTP 接口不支持 SameSite=none。如果你想加 SameSite=none 屬性倦淀,那么該 Cookie 就必須同時加上 Secure 屬性付翁,表示只有在 HTTPS 協(xié)議下該 Cookie 才會被發(fā)送。
  • 部分瀏覽器不支持部分SameSite=none晃听。IOS 12 的 Safari 以及老版本的一些 Chrome 會把 SameSite=none 識別成 SameSite=Strict百侧,所以服務(wù)端必須在下發(fā) Set-Cookie 響應(yīng)頭時進行 User-Agent 檢測,對這些瀏覽器不下發(fā) SameSite=none 屬性能扒。

2佣渴、使用Nginx或其他網(wǎng)關(guān)工具進行Proxy操作,使跨站請求變?yōu)橥菊埱?/p>

將這個被調(diào)用接口的應(yīng)用和發(fā)起請求的應(yīng)用放在同一個站下面初斑,使他們是同站請求辛润,這樣就不存在跨站問題了。

比如上面模擬示例所示见秤,在host配置中砂竖,將A站點127.0.0.1使用a.test.com映射,這樣在a.test.com中訪問b.test.com就是同站訪問了鹃答。

或者使用nginx代理請求乎澄,將a.test.com代理到a.cross.com,這樣在瀏覽器中頂部導航欄中輸入a.test.com就可以被nginx代理訪問到a.cross.com测摔,而這時瀏覽器會認為在a.test.com頁面中訪問b.test.com置济,瀏覽器會當作同站處理cookie。同理可以使用nginx代理b站點的url锋八,使與A站點同站浙于。

3、使用http auth也就是header auth方式進行挟纱,將令牌通過header的形式傳輸羞酗,不使用Cookie,那當然也就不存在Cookie中奇奇怪怪的問題了紊服。

4檀轨、使用指定版本的瀏覽器,使用chrome內(nèi)核低于80的瀏覽器围苫,或者在safari中關(guān)閉防止跨站追蹤選項裤园。

以上列出了4種解決此類問題的方法,具體還需要結(jié)合自己的業(yè)務(wù)場景選擇合適的解決方案剂府。

參考:

https://github.com/mqyqingfeng/Blog/issues/157

https://zhuanlan.zhihu.com/p/266282015

https://juejin.cn/post/6963632513914765320#heading-6

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拧揽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌淤袜,老刑警劉巖痒谴,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異铡羡,居然都是意外死亡积蔚,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門烦周,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尽爆,“玉大人,你說我怎么就攤上這事读慎∈” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵夭委,是天一觀的道長幅狮。 經(jīng)常有香客問我,道長株灸,這世上最難降的妖魔是什么崇摄? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮慌烧,結(jié)果婚禮上逐抑,老公的妹妹穿的比我還像新娘。我一直安慰自己杏死,他們只是感情好泵肄,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著淑翼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪品追。 梳的紋絲不亂的頭發(fā)上玄括,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音肉瓦,去河邊找鬼遭京。 笑死,一個胖子當著我的面吹牛泞莉,可吹牛的內(nèi)容都是我干的哪雕。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼鲫趁,長吁一口氣:“原來是場噩夢啊……” “哼斯嚎!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤堡僻,失蹤者是張志新(化名)和其女友劉穎糠惫,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體钉疫,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡硼讽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了牲阁。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片固阁。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖城菊,靈堂內(nèi)的尸體忽然破棺而出您炉,到底是詐尸還是另有隱情,我是刑警寧澤役电,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布赚爵,位于F島的核電站,受9級特大地震影響法瑟,放射性物質(zhì)發(fā)生泄漏冀膝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一霎挟、第九天 我趴在偏房一處隱蔽的房頂上張望窝剖。 院中可真熱鬧,春花似錦酥夭、人聲如沸赐纱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽疙描。三九已至,卻和暖如春讶隐,著一層夾襖步出監(jiān)牢的瞬間起胰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工巫延, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留效五,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓炉峰,卻偏偏與公主長得像畏妖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子疼阔,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容