前言
這篇文章主要是記錄一下使用跨域 cookie 需要設定及注意的地方,以下範例程式後端是使用 Python/Flask, 前端則是用 Axios 來送出 request 到後端。
Cookies
首先,先來介紹一下 Cookie 幾個比較重要的屬性:
- HttpOnly: 只能被用在 HTTP 傳輸,不可被 JavaScript 存取
- Domain: 可使用的 domain, 如果沒有設定,則只能被設定此 cookie 的 domain 所使用,如果希望設定子網域都可使用此 cookie, 則可以設為
.domain.com
- Path: 指定可存取 cookie 的路徑
- Max-Age: cookie 的期限,單位為秒,或者可以用
Expires
來設定,格式是 Unix time - SameSite: 用來防止瀏覽器將 cookie 跨網站傳送,可以幫助避免 CSRF 攻擊,以下是
SameSite
的三種設定值:- Strict: 最嚴謹,request 的網域與目前網址相同才會發送 cookie
- Lax: 除了 same site request 能夠使用 cookie之外,部分的 cross-site request 也能夠使用 cookie, 包含 HTML 中的
<a>
,<link rel="prerender">
,<form method="GET">
- None: Cross site 的 request 都能夠使用 cookie, 注意在 Chrome 80 之後,若使用這個選項,則必須要設定 Secure
- Secure: 若設為 True, 表示只能透過 HTTPS 傳輸
注意: 在 Chrome 80 之後,如果沒有設定 SameSite, 則預設為 Lax, 如果 SameSite 設為 None, 則必須要有 Secure.
Backend
後端需要設定 CORS (Cross Origin Resource Sharing), 因為會使用到 Cross site cookie, 所以也記得要設定 Access-Control-Allow-Credentials = true
, for example:
1 | # In app.py |
注意: 設定 supports_credentials
的話, origins
就不能用 *
Frontend
前端的部分,我們是使用 Axios 來送出 request 到後端,這邊記得要設定 withCredentials: true
, for example:
1 | axios.post('/login', data, { |
如果順利的話,會在在網頁的 Cookie 中看到新增了兩個 Cookie (access_token, refresh_token).
但是,在 localhost 測試時會發現無法設定 cookie, 這是因為要跨域使用 cookie, SameSite 就必須設為 None, 而 SameSite 設為 None 就必須要設定 Secure, 但我們目前的 localhost 是沒有設定 SSL 的,所以會無法設定 cookie. 解決方式是把 localhost 加上 SSL.
Localhost 加上 SSL 可參考以下文章:
- Windows: 讓 Windows 環境的 localhost 啟用 HTTPS 連線
- MacOS: 設定macOS本地端HTTPs/SSL證書 (MacOS 的部分沒測試過,可能需要大家自行測試)