個人對於SameSite這詞早有耳聞,但對於當時還沒意識到這個更新多麽要命,直到最近開始有客戶反應金流回傳後造成登出的案例頻傳,我開始重新審視這個問題。

在客戶反應後我在測試過程中發現,在第三方服務回傳之後 session id 被更新了,想必是系統重新給一個新的,讓我苦惱於這個問題許久,果然這種事情絕對不是只有我會發生,在其他文章中提到 SameSite 機制,在 POST 回傳時因為這項機制讓 cookie 不會傳送回來,導致系統判定是新的使用者,並給予新的 session id。

image host

SameSite 機制其實早已行之有年,直到Chromium開發日記發佈了重大消息,在Chrome 80之後所有的 SameSite 機制從 None 改成 Lax ,如果需要改成 None 的話,則必須開啟 Secure 的選項,這樣站台必須要走 HTTPS ,至於 SameSite 內容這邊不多作說明,最下方參考內容有非常豐富的介紹。

cross-site 對於 cookie 發送示意表

Method/Mode Strict Lax None
POST X X O
GET X O O

GET這塊包含 a link以及JS的 location 跳轉和 window.open

由次表得知,大多數第三方串接回傳時都是使用POST回傳,在這樣的狀況下,會導致我們的 session cookie 遺失,所以我整理出兩個 SameSite 調整方法,在這邊做個筆記。

方法一 Apache端

以 PHP 為例,打開 php.ini 來做點環境調整

session.cookie_secure = 1
session.cookie_path = "/; samesite=none"

# 額外補充 httponly 可以防止 Javascript 從外部存取 cookie ,可以防止XSS攻擊
session.cookie_httponly = 1  

存檔後重啟Apache即可

方法二 Web端

由於第一個方法是主機上所有站台都會限制於這個設定,礙於可能有站台沒有https的問題,我們就必須獨立修改,這樣我們必須從網站的 session 起始位置調整,我們直接強制讓 cookie 都吃這樣的 SameSite 設定。

if (empty($_COOKIE[$session_name])) {
    session_set_cookie_params(3600,'/; samesite=none','',true,true);
    session_name($session_name);
    session_start();
} else {
    session_name($session_name);
    session_start();
    setcookie($session_name, session_id(), time() + 3600,'/; samesite=none','',true,true);
}


上線時檢查自己的 session cookie 是有設定完成, httpOnly 及 Secure 必須打勾,還有 SameSite 是否有掛上 None ,這時候再去嘗試第三方回來之後就一切正常囉。

samesite cookie


到這裡,我們漫長旅途終於要結束了~

才怪!!!!
在這篇文章有提到,我也認為頗有道理, Google 提升了這樣的安全機制,但大多數是以修正回 SameSite=None 的方式,等於我們放棄了這個機制,在文中是使用 Database 加上 token 方式是比較好的方式,但不想開表做的人也可以加密 session id ,讓它出去旅行一趟回來,在接收回傳同時將 session id 設定回去。

# 回傳參數請自行定義
if(isset($_GET[$field]) && $_GET[$field] != ''){
    $sessionId = decrypt($_GET[$field]);
}

if($sessionId != '' && session_id() != $sessionId){
    session_destroy();
    session_id($sessionId);
    session_start();
    setcookie('PHPSESSID', $sessionId);
}

雖然有些第三方都會保留參數讓串接方可以放值進去,我是建議以 GET 方式回傳最好,因為我們不確定每家第三方在失敗回傳後都會丟回這些參數,但如果設定在回傳網址就一定收的到。



2021-04-06 更新

最近在iOS 12瀏覽器碰到一個問題,cookie會有異常導致登入判斷異常,後來廠商找到Chromium的文章有提到相容性問題,這個 samesite=none 設定在 MacOS 10.14 和 iOS 12的瀏覽器都不相容,所以可以檢視自己的cookie議題,如果需要處理samesite就要注意裝置版本問題,在設定上可能會出現分水嶺。

原文連結:SameSite=None: Known Incompatible Clients

參考資料