問題描述
我正在使用 React SPA、Express、Express-session、Passport 和 JWT.我對一些用于存儲令牌的不同客戶端存儲選項感到困惑:Cookie、Session 和 JWT/Passport.
I am using React SPA, Express, Express-session, Passport, and JWT. I'm confused about some of the different client-side storage options to store tokens: Cookies, Session, and JWT / Passport.
令牌是否必須存儲在 cookie 中,即使我可以將它們存儲在 req.sessionID
中?
Do tokens have to be stored in cookies, even if I can store them in req.sessionID
?
許多網站使用 cookie 來存儲購物車令牌.到目前為止,我已經根據會話 ID 存儲了購物車數據,而沒有添加任何 cookie.
Many websites use cookies to store shopping cart tokens. So far I have stored shopping cart data based on the session ID without adding any cookies.
所以當用戶訪問我的網站時,我會將其與他們的req.sessionID
然后檢索數據庫中的數據,如購物車和用戶會話.
So when users visit my website, I will match it with their
req.sessionID
and then retrieve the data in the database like shopping carts and user session.
我需要存儲 cookie 嗎?我可以通過 req.sessionID
訪問它以獲取所需的數據.
Do I need to store cookies? I can access it via req.sessionID
to get the data needed.
還有第二個
我已使用 passport-google-oauth20
進行身份驗證.成功登錄后,數據將保存到會話中.并將其發送給客戶端,我必須通過 URL 查詢 ?token='sdsaxas'
發送它.
I have made authentication using a passport-google-oauth20
.After I successfully login, the data is saved into the session. and to send it to the client I have to send it via the URL query ?token='sdsaxas'
.
在這種情況下,我有很多不同的意見.有人保存了它到本地存儲中,有人通過使用 JWT 將其轉換為令牌將其保存到 cookie 中.
in this case I get a lot of difference of opinion. someone saved it into local storage and someone saved it into cookies by converting it to a token using JWT.
jwt.sign(
payload,
keys.jwt.secretOrPrivateKey,
{
expiresIn:keys.jwt.expiresIn // < i dont know what is this expired for cookies or localstorage ?
}, (err, token) => {
res.redirect(keys.origin.url + "?token=" + token);
});
我真的可以使用 sessionID(不帶 cookie 或本地存儲)存儲與會話相關的所有內容嗎?
因為我使用 React SPA,所以只需要進行一次或每次頁面刷新并檢索數據然后保存到 redux 中.
Only by doing fetch once or every page refresh and retrieving the data and then saved into redux because I use React SPA.
推薦答案
這個答案是基于無狀態的方法,因此它沒有談論傳統的會話管理
你問了兩個完全不同的問題:
You have asked two altogether different questions:
- 購物車 - 與業務功能更相關
- OAuth 2 &JWT - 與安全和身份驗證有關
作為電子商務網站的用戶,我希望在上下班途中從移動設備添加到購物車中的任何商品在我從 PC 登錄到網站后,都應該可以在購物車中找到到達家.因此,購物車數據應保存在后端數據庫中并鏈接到我的用戶帳戶.
As an user of an ecommerce website, I'd expect that any item I add to my shopping cart from my mobile device while commuting to my workplace, should be available in the cart when I login to the website from my PC after reaching home. Therefore, the cart data should be saved in the back-end DB and linked to my user account.
在使用 OAuth 2.0 進行身份驗證時,JWT 訪問令牌和/或刷新令牌需要存儲在客戶端設備中的某個位置,這樣一旦用戶通過提供登錄憑據進行身份驗證,他就不需要提供他的憑據再次瀏覽該網站.在這種情況下,瀏覽器本地存儲、會話存儲和 cookie 都是有效的選項.但是,請注意這里的 cookie 沒有鏈接到服務器端的任何會話.換句話說,cookie 不存儲任何會話 ID.cookie 僅用作訪問令牌的存儲,該令牌隨每個 http 請求傳遞給服務器,然后服務器使用數字簽名驗證令牌,以確保它沒有被篡改并且沒有過期.
When it comes to authentication using OAuth 2.0, the JWT access token and / or refresh token need to be stored somewhere in the client device, so that once the user authenticates himself by providing login credentials, he doesn't need to provide his credentials again to navigate through the website. In this context, the browser local storage, session storage and cookies are all valid options. However, note that here the cookie is not linked to any session on the server side. In other words, the cookie doesn't store any session id. The cookie is merely used as a storage for access token which is passed to the server with every http request and the server then validates the token using the digital signature to ensure that it is not tampered and it is not expired.
雖然訪問和/或刷新令牌的所有三個存儲選項都很流行,但如果以正確的方式使用,cookie 似乎是最安全的選項.
Although all three storage options for access and / or refresh tokens are popular, cookie seems to be the most secured option when used in the correct way.
為了更好地理解這一點,我建議您閱讀 this 和 this 以及 OAuth 2.0 規范.
To understand this better, I recommend you read this and this along with the OAuth 2.0 specification.
我之前說過,cookie 似乎是最安全的選項.我想在這里進一步澄清這一點.
I said earlier that cookie seems to be the most secured options. I'd like to further clarify the point here.
我認為瀏覽器 localStorage
和 sessionStorage
沒有為存儲身份驗證令牌提供足夠的安全性的原因如下:
The reason I think browser localStorage
and sessionStorage
do not provide enough security for storing auth tokens are as follows:
如果發生 XSS,惡意腳本可以輕松地從那里讀取令牌并將其發送到遠程服務器.從那里開始,遠程服務器或攻擊者在冒充受害者用戶時不會有任何問題.
If XSS occurs, the malicious script can easily read the tokens from there and send them to a remote server. There on-wards the remote server or attacker would have no problem in impersonating the victim user.
localStorage
和 sessionStorage
不跨子域共享.因此,如果我們在不同的子域上運行兩個 SPA,我們將無法獲得 SSO 功能,因為一個應用程序存儲的令牌將無法用于組織內的另一個應用程序.有一些使用 iframe
的解決方案,但這些看起來更像是變通方法,而不是一個好的解決方案.而當響應頭 X-Frame-Options
用于避免使用 iframe
的點擊劫持攻擊時,任何使用 iframe
的解決方案都是沒有問題的.
localStorage
and sessionStorage
are not shared across sub-domains. So, if we have two SPA running on different sub-domains, we won't get the SSO functionality because the token stored by one app won't be available to the other app within the organization. There are some solutions using iframe
, but those look more like workarounds rather than a good solution. And when the response header X-Frame-Options
is used to avoid clickjacking attacks with iframe
, any solution with iframe
is out of question.
但是,這些風險可以通過使用指紋來降低(如 OWASP JWT Cheat Sheet) 這又需要一個 cookie.
These risks can, however, be mitigated by using a fingerprint (as mentioned in OWASP JWT Cheat Sheet) which again in turn requires a cookie.
指紋的想法是,生成一個加密強的隨機字節串.然后將原始字符串的 Base64 字符串存儲在 HttpOnly
、Secure
、SameSite
cookie 中,名稱前綴為 __Secure-代碼>.應根據業務需求使用正確的域和路徑屬性值.字符串的 SHA256 哈希也將在 JWT 的聲明中傳遞.因此,即使 XSS 攻擊將 JWT 訪問令牌發送到攻擊者控制的遠程服務器,它也無法在 cookie 中發送原始字符串,因此服務器可以根據 cookie 的缺失拒絕請求.XSS 腳本無法讀取
HttpOnly
的 cookie.
The idea of fingerprint is, generate a cryptographically strong random string of bytes. The Base64 string of the raw string will then be stored in a HttpOnly
, Secure
, SameSite
cookie with name prefix __Secure-
. Proper values for Domain and Path attributes should be used as per business requirement. A SHA256 hash of the string will also be passed in a claim of JWT. Thus even if an XSS attack sends the JWT access token to an attacker controlled remote server, it cannot send the original string in cookie and as a result the server can reject the request based on the absence of the cookie. The cookie being HttpOnly
cannot be read by XSS scripts.
因此,即使我們使用 localStorage
和 sessionStorage
,我們也必須使用 cookie 來確保其安全.最重要的是,我們添加了上面提到的子域限制.
Therefore, even when we use localStorage
and sessionStorage
, we have to use a cookie to make it secured. On top of that, we add the sub-domain restriction as mentioned above.
現在,使用 cookie 存儲 JWT 的唯一問題是 CSRF 攻擊.由于我們使用 SameSite
cookie,CSRF 得到緩解,因為跨站點請求(AJAX 或僅通過超鏈接)是不可能的.如果該站點用于任何舊瀏覽器或其他一些不那么流行的不支持 SameSite
cookie 的瀏覽器,我們仍然可以通過另外使用具有加密強隨機值的 CSRF cookie 來緩解 CSRF,這樣每個AJAX 請求讀取 cookie 值并將 cookie 值添加到自定義 HTTP 標頭中(GET 和 HEAD 請求除外,它們不應該進行任何狀態修改).由于 CSRF 由于同源策略而無法讀取任何內容,并且它基于利用 POST、PUT 和 DELETE 等不安全的 HTTP 方法,因此此 CSRF cookie 將減輕 CSRF 風險.所有現代 SPA 框架都使用這種使用 CSRF cookie 的方法.這里提到了 Angular 方法.
Now, the only concern about using a cookie to store JWT is, CSRF attack. Since we use SameSite
cookie, CSRF is mitigated because cross-site requests (AJAX or just through hyperlinks) are not possible. If the site is used in any old browser or some other not so popular browsers that do not support SameSite
cookie, we can still mitigate CSRF by additionally using a CSRF cookie with a cryptographically strong random value such that every AJAX request reads the cookie value and add the cookie value in a custom HTTP header (except GET and HEAD requests which are not supposed to do any state modifications). Since CSRF cannot read anything due to same origin policy and it is based on exploiting the unsafe HTTP methods like POST, PUT and DELETE, this CSRF cookie will mitigate the CSRF risk. This approach of using CSRF cookie is used by all modern SPA frameworks. The Angular approach is mentioned here.
另外,由于 cookie 是 httpOnly
和 Secured
,XSS 腳本無法讀取它.因此 XSS 也得到了緩解.
Also, since the cookie is httpOnly
and Secured
, XSS script cannot read it. Thus XSS is also mitigated.
值得一提的是,可以通過使用適當的 content-security-policy
響應標頭進一步緩解 XSS 和腳本注入.
It may be also worth mentioning that XSS and script injection can be further mitigated by using appropriate content-security-policy
response header.
- 狀態變量(Auth0 使用它)- 客戶端將生成并隨每個請求傳遞一個加密的強隨機隨機數,服務器將連同其響應一起回顯該隨機數,從而允許客戶端驗證隨機數.Auth0 文檔中對此進行了說明.
- 始終檢查referer 標頭并僅在referer 是受信任的域時接受請求.如果沒有引用標頭或未列入白名單的域,則只需拒絕請求.使用 SSL/TLS 時,通常會出現引用.登陸頁面(主要是信息性的,不包含登錄表單或任何安全內容)可能有點放松,并允許缺少引用標頭的請求.
- 應在服務器中阻止 TRACE HTTP 方法,因為這可用于讀取
httpOnly
cookie. - 另外,設置標題 Strict-Transport-Security: max-age=;includeSubDomains 只允許安全連接,以防止任何中間人覆蓋子域中的 CSRF cookie.
- State Variable (Auth0 uses it) - The client will generate and pass with every request a cryptographically strong random nonce which the server will echo back along with its response allowing the client to validate the nonce. It's explained in Auth0 doc.
- Always check the referer header and accept requests only when referer is a trusted domain. If referer header is absent or a non-whitelisted domain, simply reject the request. When using SSL/TLS referrer is usually present. Landing pages (that is mostly informational and not containing login form or any secured content) may be little relaxed ?and allow requests with missing referer header.
- TRACE HTTP method should be blocked in the server as this can be used to read the
httpOnly
cookie. - Also, set the header Strict-Transport-Security: max-age=; includeSubDomains? to allow only secured connections to prevent any man-in-the-middle overwrite the CSRF cookies from a sub-domain.
這篇關于我必須將令牌存儲在 cookie 或本地存儲或會話中嗎?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!