安全是計(jì)算機(jī)科學(xué)永遠(yuǎn)無(wú)法忽視的話題。隨著互聯(lián)網(wǎng)的發(fā)展,安全問題越來越突出,也越來越重要:它是一個(gè)程序可用性、健壯性的基礎(chǔ)。這個(gè)話題可大可小,大到系統(tǒng)的設(shè)計(jì),小到一行代碼的寫法,都可能影響系統(tǒng)的安全。
毫不例外,安全與前端開發(fā)的結(jié)合也持續(xù)走熱。不管是經(jīng)驗(yàn)豐富的程序員,還是尚在打基礎(chǔ)的學(xué)生,也許都對(duì) HTTPS、XSS、CSRF 等前端相關(guān)的安全問題不陌生。然而,這其中每一個(gè)主題都可以非常深入,都能系統(tǒng)地做一節(jié)課。但是,我認(rèn)為面面俱到、走馬觀花地梳理這些內(nèi)容,講解這些概念價(jià)值不大。畢竟,這方面知識(shí)都已經(jīng)比較成熟,社區(qū)上資料很多。
本講我想從一個(gè)大部分產(chǎn)品都要涉及的登錄鑒權(quán)入手,結(jié)合單頁(yè)面應(yīng)用,從這個(gè)角度,管中窺豹,盡可能多地涉及一些常見的安全知識(shí),幫助大家了解前端安全。
接下來,讓我們從應(yīng)用場(chǎng)景入手,從前后端交互切入,以單頁(yè)面應(yīng)用為基礎(chǔ),呈現(xiàn)「鑒權(quán)」這個(gè)安全領(lǐng)域重要話題的全貌,并盡力覆蓋到 XSS 和 CSRF 等攻擊手段以及最佳實(shí)踐。
關(guān)于這個(gè)主題的知識(shí)點(diǎn)如下:

單頁(yè)應(yīng)用鑒權(quán)簡(jiǎn)介
首先,我們要分清單頁(yè)應(yīng)用鑒權(quán)與傳統(tǒng)鑒權(quán)方式有所不同:
單頁(yè)應(yīng)用采用前后端分離的設(shè)計(jì)方式,路由由前端管理,前后端遵循一定規(guī)范(如 REST、GraphQL),通過 AJAX 進(jìn)行通信。在這種情況下,用戶對(duì)頁(yè)面請(qǐng)求時(shí),后端經(jīng)常無(wú)法獲取用戶身份信息,更無(wú)法確定返回的數(shù)據(jù)。
同時(shí)一次鑒權(quán)完畢后,如何在單頁(yè)應(yīng)用的體驗(yàn)當(dāng)中,保持這個(gè)鑒權(quán)狀態(tài)也值得思考。一般來說,單頁(yè)應(yīng)用鑒權(quán)采用下面的步驟實(shí)現(xiàn)。
- Step 1:前端根據(jù)用戶交互,發(fā)送數(shù)據(jù)請(qǐng)求之前,需要準(zhǔn)備用戶信息,同數(shù)據(jù)請(qǐng)求一起發(fā)給后端處理。
- Step 2-1:后端按照約定好的規(guī)則,根據(jù)請(qǐng)求中帶有的用戶身份信息,進(jìn)行驗(yàn)證。如果驗(yàn)證不通過,返回 403 或者 401 相關(guān)狀態(tài)碼或其他狀態(tài),以表示鑒權(quán)失敗。
- Step 2-2:如果鑒權(quán)成功,后端返回相關(guān)數(shù)據(jù)。
- Step 3:前端根據(jù)數(shù)據(jù)渲染視圖。
基本結(jié)構(gòu)非常簡(jiǎn)單清晰:

在這個(gè)結(jié)構(gòu)背后,隱藏的技術(shù)方案和安全細(xì)節(jié)非常值得我們思考,請(qǐng)繼續(xù)閱讀,我們將剖析幾個(gè)重要概念和安全實(shí)踐。
HTTPS
鑒權(quán)過程中,如果使用 HTTP 協(xié)議來傳輸敏感數(shù)據(jù)(用戶昵稱、用戶密碼、token……),那么很容易被中間人攔截獲取?,F(xiàn)代通信中,我們都使用 HTTPS 協(xié)議來對(duì)傳輸內(nèi)容進(jìn)行加密。關(guān)于 HTTPS 的應(yīng)用及其原理,又是一個(gè)超級(jí)話題。這里由于內(nèi)容的限制,不過多展開,給大家分享一下我收藏的關(guān)于 HTTPS 好的文章:
- https 連接的前幾毫秒發(fā)生了什么
- 完全圖解 HTTPS
- 更安全的 Web 通信 HTTPS
- 圖解基于 HTTPS 的 DNS
- 看圖學(xué) HTTPS
- http 與 https 的區(qū)別我真的知道嗎
- 深入揭秘 HTTPS 安全問題&連接建立全過程
- HTTPS 系列干貨(一):HTTPS 原理詳解
- HTTPS 為什么更安全,先看這些
不要使用 URL query 傳遞敏感數(shù)據(jù)
URL query 會(huì)通過服務(wù)端日志、瀏覽器日志、瀏覽器歷史記錄查到。不要使用 URL query 傳遞敏感數(shù)據(jù),這當(dāng)然是最基本的準(zhǔn)則之一。如果敏感數(shù)據(jù)在 URL query 中,這就給了惡意用戶輕松獲取數(shù)據(jù)的機(jī)會(huì)。同時(shí),URL query 的長(zhǎng)度也有限制,這也是其傳遞數(shù)據(jù)的弊端之一。
防止暴力攻擊的手段
攻擊者可以通過暴力手段,嘗試攻破用戶的密碼等信息。因此后端服務(wù)要時(shí)刻注意加入頻率限制,限制一個(gè)用戶短時(shí)間嘗試密碼的次數(shù);也可以限制可疑用戶(比如觸發(fā)了過多服務(wù)端錯(cuò)誤用戶)的訪問。另外,需要注意的是不要給任何人暴露服務(wù)端的技術(shù)細(xì)節(jié)信息,比如要記得關(guān)閉 X-Powered-By(服務(wù)器響應(yīng)頭隱藏);Node 端在使用 express.js 的情況下,強(qiáng)烈建議使用 Helmetjs。
Helmet 幫助 Node.js 開發(fā)者通過設(shè)置合理的 HTTP header,預(yù)防一些常見的 Web 漏洞,比如上面提到的關(guān)閉 X-Powered-By。實(shí)際上它就是一組靈活的中間件函數(shù),增強(qiáng)以下 HTTP header 的安全性:
Content-Security-Policy 響應(yīng)頭,它可以設(shè)置應(yīng)用是否可以引用某些來源內(nèi)容,進(jìn)而防止 XSS
關(guān)閉 X-Powered-By 響應(yīng)頭,以避免暴露服務(wù)端信息
增加 Public Key Pinning 響應(yīng)頭,預(yù)防中間人偽造證書
設(shè)置 Strict-Transport-Security 響應(yīng)頭,這樣瀏覽器只能通過 HTTPS 訪問當(dāng)前資源
為 IE8+ 設(shè)置 X-Download-Options 響應(yīng)頭,目前只有 IE8+ 支持這個(gè) header,用來預(yù)防下載內(nèi)容的安全隱患
設(shè)置 Cache-Control 和 Pragma header 以關(guān)閉瀏覽器端緩存
設(shè)置 X-Content-Type-Options 響應(yīng)頭,以禁用瀏覽器內(nèi)容嗅探
設(shè)置 X-Frame-Options 響應(yīng)頭,以預(yù)防 clickjacking,這個(gè)響應(yīng)頭給瀏覽器指示是否允許在 或者 標(biāo)簽中渲染某個(gè)頁(yè)面
設(shè)置 X-XSS-Protection 響應(yīng)頭,當(dāng)檢測(cè)到跨站腳本攻擊(XSS)時(shí),瀏覽器停止加載頁(yè)面
它的使用非常簡(jiǎn)單:
const express = require('express')
const helmet = require('helmet')
const app = express()
app.use(helmet())
其源碼是典型的 express 中間件寫法,它依次加載相關(guān)中間件集。比如它將引用 X-Powered-By 中間件,這個(gè)中間件的源碼非常簡(jiǎn)單:
module.exports = function hidePoweredBy (options) {
var setTo = (options || {}).setTo
if (setTo) {
return function hidePoweredBy (req, res, next) {
res.setHeader('X-Powered-By', setTo)
next()
}
} else {
return function hidePoweredBy (req, res, next) {
res.removeHeader('X-Powered-By')
next()
}
}
}
通過 setHeader 和 removeHeader 方法,完成對(duì) X-Powered-By 響應(yīng)頭的添加和刪除。
升級(jí)依賴保證安全
現(xiàn)如今我們的應(yīng)用,大部分腳本都來自第三方依賴,第三方庫(kù)出現(xiàn)安全隱患的新聞已經(jīng)屢見不鮮。除了從源頭把控依賴的引入外,適時(shí)合理地更新 npm 包,是值得倡導(dǎo)的做法,npm 便在 6.0 后有相關(guān)命令如下:
# npm 6.0 新增,掃描所有依賴,列出依賴中有安全隱患的包
npm audit
# npm 6.0 新增,掃描所有依賴,并把不安全的依賴包升級(jí)到可兼容的版本
npm audit fix
單頁(yè)應(yīng)用鑒權(quán)實(shí)戰(zhàn)
言歸正傳,我們來看一下實(shí)現(xiàn)單頁(yè)應(yīng)用鑒權(quán)的兩種主要手段:
- JWT
- Authentication cookie
這兩種方式不盡相同,我們將逐一分析,并嘗試合并這兩種方案的優(yōu)點(diǎn),將它們結(jié)合為第三種方式。
采用 JWT 實(shí)現(xiàn)鑒權(quán)
在鑒權(quán)過程中,為了驗(yàn)證用戶的身份,需要瀏覽器向服務(wù)器端提供一個(gè)驗(yàn)證信息,我們稱為 token。這個(gè) token 通常由 JSON 數(shù)據(jù)格式組成,通過 hash 散列算法生成一個(gè)字符串,稱為 JSON Web Token(JSON 表示令牌的原始類型為 JSON 格式,Web 表示在互聯(lián)網(wǎng)中進(jìn)行傳播,Token 表示令牌,簡(jiǎn)稱 JWT)。任何 token 持有者都可以無(wú)差別地用它來訪問相關(guān)的資源。
我們可以在 HTTP Authorization header 中找到 token,其實(shí)就是一個(gè)字符串值。這個(gè)字符串用來表示用戶的身份信息,進(jìn)行身份認(rèn)證或者從服務(wù)器獲取合法資源。當(dāng)然這個(gè) token 往往是被加密的。那么這個(gè) token 具體是如何生成的呢?
我們先從 JWT 說起,一個(gè) JWT 包含以下 3 個(gè)部分:
- header(消息頭)
- payload(消息體,儲(chǔ)存用戶 id、用戶角色等) + 過期時(shí)間(可選)
- signature(簽名)
我們說過,JWT 就是 JSON 格式的數(shù)據(jù),JWT 的前兩個(gè)部分就是 JSON 數(shù)據(jù),第三部分 signature 是基于前兩部分 header 和 payload 生成的簽名。前兩部分分別通過 Base64URL 算法生成兩組字符串,再和 signature 結(jié)合,三部分通過 . 號(hào)分割,就是最終的 token。
更多這方面的信息,大家可以參考:
正常來講,當(dāng)客戶端在提交用戶名/密碼(或者其他方式)通過認(rèn)證后,會(huì)獲得 JWT 的 token,接著通過 JavaScript 腳本,對(duì)于所有數(shù)據(jù)請(qǐng)求都在其 HTTP header 中加上這個(gè) JWT 的 token。服務(wù)端接到請(qǐng)求之后,驗(yàn)證 token 的 signature 是否等同于 payload,進(jìn)而得知 payload 字段是否被中間人更改。
細(xì)心的讀者可能會(huì)發(fā)現(xiàn),我們提到「通過 JavaScript 腳本,對(duì)于所有數(shù)據(jù)請(qǐng)求,都在 HTTP header 中加上這個(gè) token」。這就涉及客戶端如何存儲(chǔ)和維護(hù) JWT 的問題了。
存儲(chǔ) JWT,我們可以考慮:
- 內(nèi)存存儲(chǔ)
- local/session cookie
- local/session storage……
這幾種方式。我并不建議開發(fā)者將 token 存儲(chǔ)在 local storage 當(dāng)中,因?yàn)椋?/p>
- 當(dāng)用戶關(guān)掉瀏覽器后,JWT 仍然會(huì)被存儲(chǔ)在 local storage 中,即便 JWT 過期,可能一直被存儲(chǔ)(除非手動(dòng)更新或清理)
- 任何 JavaScript 都能輕而易舉地獲得 local storage 的內(nèi)容
- 無(wú)法被 web worker 使用
但在實(shí)際項(xiàng)目中,筆者也在 local storage 中存儲(chǔ)過 JWT,這需要我們分清利弊,結(jié)合實(shí)際場(chǎng)景選擇方案。如果吃透概念,就能減少 bug 的出現(xiàn),具體存儲(chǔ)方案可以靈活一些。
更好的選擇之一是將 JWT 存儲(chǔ)在 session cookie 中,auth0 有一篇很好的文章,感興趣的讀者可以參考:Where to Store Tokens。
JWT 隱患
JWT 實(shí)現(xiàn)鑒權(quán)也存在的隱患,上面我們也簡(jiǎn)要提到了,隱患主要來自 XSS。攻擊者可以主動(dòng)注入惡意腳本或者使用用戶輸入,通過 JavaScript 代碼來偷取 token,接下來便能通過 token 冒充受害用戶。
比如,一個(gè)博客留言系統(tǒng),用戶可以在其留言內(nèi)容中加入以下腳本:
<img src="x" onerror="javascript:alert('XSS')" style="height: 1px; width: 100%; />
一般的防御手段是采用 HTML 轉(zhuǎn)義來控制過濾用戶輸入(為了防止 XSS 攻擊,常常需要將用戶輸入的特殊字符進(jìn)行轉(zhuǎn)義)。
采用 Authentication cookie 實(shí)現(xiàn)鑒權(quán)
cookie 是含有有效期和相關(guān) domain,存儲(chǔ)在瀏覽器中的鍵值對(duì)組合,可以由 JavaScript 創(chuàng)建:
document.cookie = 『my_cookie_name=my_cookie_value』
也可以由服務(wù)端通過 response header 創(chuàng)建:
Set-Cookie: my_cookie_name=my_cookie_value
瀏覽器會(huì)自動(dòng)在每個(gè)請(qǐng)求當(dāng)中加入相關(guān) domain 下的 cookie:
GET https://www.example.com/api/users Cookie: my_cookie_name=my_cookie_value
cookie 一般分為兩種(出處):
Session cookie,這種 cookie 會(huì)隨著用戶關(guān)閉瀏覽器而被清除,不會(huì)被標(biāo)記任何過期時(shí)間 Expires 或者最大時(shí)限 Max-Age。
Permanent cookie,與 session cookie 相反,會(huì)在用戶關(guān)閉瀏覽器之后被瀏覽器持久化存儲(chǔ)。
同時(shí),服務(wù)端可以對(duì) cookie 進(jìn)行一些關(guān)鍵配置,以保障 cookie 的使用安全,諸如:
- HttpOnly cookie:瀏覽器端 JavaScript 沒有讀 cookie 權(quán)限。
- Secure cookie:傳輸鏈路只有在特定安全通道(通常指 HTTPS),請(qǐng)求才會(huì)自動(dòng)加入相關(guān) cookie。
- SameSite cookie:在跨域情況下,相關(guān) cookie 無(wú)法被請(qǐng)求攜帶,這里主要是為了防止 CSRF 攻擊。
一個(gè)經(jīng)典場(chǎng)景就是使用 cookie 存儲(chǔ)一個(gè) session ID(session ID 由服務(wù)端管理,進(jìn)行創(chuàng)建和計(jì)時(shí),以便在必要的時(shí)候清除)。通過驗(yàn)證 cookie 和 session ID,服務(wù)端便能標(biāo)記一個(gè)用戶的訪問信息。這種情況就是我們說的 stateful,而本節(jié)課的主角 JWT 是 stateless 的,因?yàn)樗恍枰?wù)端維護(hù) session ID,是無(wú)狀態(tài)的,更加利于橫向擴(kuò)展。
Authentication cookie 隱患
采用 Authentication cookie 實(shí)現(xiàn)單頁(yè)應(yīng)用鑒權(quán)的安全隱患主要有兩種:
XSS 如果沒有使用 httpOnly 選項(xiàng),那么攻擊者可能會(huì)通過注入惡意腳本,任意讀取用戶 cookie。而 cookie 直接存儲(chǔ)了用戶的身份認(rèn)證信息,這當(dāng)然是非常可怕的。
CSRF) 是常見的針對(duì) cookie 展開進(jìn)攻的手段。我們知道跨域訪問技術(shù)(CORS,跨域資源共享)的同源策略能保證不同源的客戶端腳本在沒有明確授權(quán)的情況下,無(wú)法讀寫對(duì)方資源。同源策略只是針對(duì)瀏覽器側(cè)的編程腳本語(yǔ)言,如果我們對(duì)另一個(gè)惡意服務(wù)器發(fā)送 AJAX 請(qǐng)求,同源策略會(huì)有所限制,但是如果請(qǐng)求直接通過 HTML form 發(fā)送,那么同源策略毫無(wú)辦法。
另一個(gè)利用 CSRF 實(shí)施攻擊的場(chǎng)景為:假如受害者在網(wǎng)頁(yè)中登錄了 Facebook,同時(shí)又打開了 bad.com,bad.com 屬于攻擊者的網(wǎng)站,這個(gè)網(wǎng)站中有這樣的代碼:
總結(jié) 為了防御 XSS 攻擊,需要開發(fā)者設(shè)置 httpOnly 選項(xiàng);為了防御 XSRF,需要開發(fā)者設(shè)置 SameSite 選項(xiàng)。需要注意,并不是所有瀏覽器都支持 SameSite。
此外,一些其他防御手段有:
Short session timeout:設(shè)置 session 過期時(shí)間,比如銀行網(wǎng)站往往需要每 10 分鐘或者更短時(shí)間就重新登錄。
關(guān)鍵操作需要用戶重新進(jìn)行鑒權(quán)認(rèn)證。
Double submitted cookie:當(dāng)用戶瀏覽一個(gè)站點(diǎn)時(shí),服務(wù)端生成一個(gè)偽隨機(jī)數(shù) pseudorandom value,并將其設(shè)置為 cookie,且不設(shè)置 httpOnly 標(biāo)識(shí)。這樣 JavaScript 就能夠訪問這個(gè) pseudorandom value,并要求在提交每個(gè)表單時(shí),一并將這個(gè) pseudorandom value 作為 form value 提交上來,同時(shí)在 cookie 中也要提交 value。服務(wù)端便可以對(duì)比 form value 中的 pseudorandom value 和 cookie value 是否一致,以此來認(rèn)證用戶的安全身份。
Double submitted cookie 之所以能有效防范攻擊,是因?yàn)橥床呗灾率构粽邿o(wú)法讀取來自攻擊目標(biāo)服務(wù)端的 cookie 值,更無(wú)法修改攻擊網(wǎng)站的 cookie value。即便攻擊者可以從 form 中提交任何 form value,但是無(wú)法通過服務(wù)端對(duì) form value 中的 pseudorandom value 和 cookie value 的一致性進(jìn)行驗(yàn)證。
混合 JWT 和 cookie 進(jìn)行鑒權(quán)
設(shè)想我們要實(shí)現(xiàn)這樣一個(gè)鑒權(quán)系統(tǒng):
- 盡可能抵御 XSS 和 CSRF
- 做到 stateless
考慮到安全性能,JWT 方案的主要問題在于攻擊者存在直接讀取 JWT 信息的可能。如果我們將 JWT 和 cookie 方案結(jié)合呢?即將 JWT 部分敏感信息放入 cookie 當(dāng)中,這樣一來,便可以結(jié)合前文兩種方式的優(yōu)點(diǎn)。
如圖,我們?cè)倏偨Y(jié)一下存在的三種交互可能。第一種是經(jīng)典 JWT 方式:

這種情況下,前后端使用 JWT 進(jìn)行鑒權(quán)交互,前端通過 JavaScript 操作 JWT 信息完成請(qǐng)求準(zhǔn)備。
第二種方式,將 JWT 信息在 session cookie 中維護(hù):

在這種情況下,JWT 信息全部存儲(chǔ)在 cookie 中, 并設(shè)置 cookie 的 httpOnly、SameSite、Secure 屬性,前端無(wú)法讀取 JWT 信息,但每次請(qǐng)求都會(huì)由瀏覽器帶上必要的 JWT 數(shù)據(jù)(作為 cookie)。同時(shí),由于采用 session cookie,也不存在 JWT 信息過期的情況,用戶關(guān)閉頁(yè)面之后不會(huì)將 JWT 信息持久化存儲(chǔ),下次再打開頁(yè)面時(shí),會(huì)重新進(jìn)行鑒權(quán)流程。
第一種方式有一定的安全隱患;第二種方式我們將 JWT 所有信息存儲(chǔ)在 session cookie 當(dāng)中,優(yōu)點(diǎn)明顯,但是無(wú)法做到持久化存儲(chǔ),在某種程度上也會(huì)帶來不便。那么我們權(quán)衡之后進(jìn)行了變通,結(jié)合前面兩種方式產(chǎn)生了第三種方式:

這樣,JWT 的 signature 部分維護(hù)在設(shè)置了 httpOnly 的 cookie 中,這意味著 JavaScript 無(wú)法讀取完整的 JWT 信息。同時(shí),cookie 會(huì)在每次請(qǐng)求中被攜帶, 并由服務(wù)端返回后在瀏覽器中進(jìn)行存儲(chǔ),這樣 JWT 信息在每次請(qǐng)求時(shí)都可以被更新,JWT 過期時(shí)間也會(huì)被自動(dòng)加入。
這篇文章:Getting Token Authentication Right in a Stateless Single Page Application 就很好地對(duì)上述方式進(jìn)行了總結(jié)。
為了實(shí)現(xiàn)最大限度的安全保障,我們也可以考慮結(jié)合前文介紹的 Double submitted cookie 以及「關(guān)鍵操作需要用戶重新進(jìn)行鑒權(quán)認(rèn)證」的處理。
例如,我們認(rèn)為用戶更改郵箱地址,是一個(gè)關(guān)鍵操作。那么,在發(fā)生這個(gè)操作時(shí),即便用戶已經(jīng)登錄,系統(tǒng)還是要求用戶重新填寫用戶密碼,以確認(rèn)修改。后端在收到修改請(qǐng)求后,產(chǎn)生一個(gè)隨機(jī) number(經(jīng)過加密運(yùn)算),作為 permanent cookie 返回給前端,JavaScript 需要讀取這個(gè)值,并將這個(gè)隨機(jī) number 作為表單 form value 的一項(xiàng),它需要隨新的郵箱地址一起提交,服務(wù)端對(duì)這個(gè)隨機(jī) form value 進(jìn)行驗(yàn)證,驗(yàn)證方式是對(duì)比表單中的 form value 和 cookie 當(dāng)中的隨機(jī) number 是否一致。
這樣便更大限度地防御了 CSRF 攻擊,流程如下:

我們總結(jié)一下流程。
Step 1:?jiǎn)雾?yè)應(yīng)用檢查 cookie 中是否存在 JWT payload,如果存在,表示用戶已經(jīng)成功進(jìn)行鑒權(quán);反之,重定向到類似 /login 的登錄頁(yè)面。
Step2:用戶在未授權(quán)的情況下,在登錄頁(yè)面 /login 將用戶名和密碼提交給服務(wù)端,服務(wù)端返回信息中設(shè)置 authentication cookie,cookie 中含有 JWT 信息。
第二步的具體操作方法可以采用上述第二種和第三種方式,或者增強(qiáng) CSRF 防御的其他手段。
總結(jié)
我們?cè)賮砜偨Y(jié)一下單頁(yè)應(yīng)用進(jìn)行鑒權(quán)的關(guān)鍵問題:token 最初由服務(wù)端下發(fā),前端在請(qǐng)求時(shí)需要攜帶。這樣一來:
如果前端將 JWT 存儲(chǔ)在 localStorage 或者 sessionStorage 當(dāng)中,由于 localStorage 或者 sessionStorage 都可以被 JavaScript 訪問,如果攻擊者能夠讀取 localStorage 或者 sessionStorage,那么就能輕易獲取 token,很容易進(jìn)行 XSS 攻擊。
如果將 JWT 存儲(chǔ)在 cookie 當(dāng)中,我們就可以指定 cookie httpOnly 屬性,來防止被 JavaScript 讀取,也可以指定 secure 屬性,來保證 JWT 信息只在 HTTPS 下被攜帶。但是這樣容易遭到 CSRF 攻擊,因此就出現(xiàn)了我們的增強(qiáng)方式。
本節(jié)我們通過分析和設(shè)計(jì)單頁(yè)應(yīng)用鑒權(quán)方案,熟悉了 JWT 和傳統(tǒng) cookie-session。我們?cè)诮榻B一些安全方面最佳實(shí)踐的同時(shí),覆蓋了一些常見的攻擊手段:XSS 和 CSRF 等。前端安全是一個(gè)龐大且復(fù)雜的課題,本節(jié)只是通過一個(gè)比較重要的話題帶大家切入,要想全面熟悉前端安全,完全可以開一門新課了。雖然我的課程志不在此,不過下面我會(huì)根據(jù)相關(guān)安全話題,將我收藏的文章分享給大家。
彩蛋分享
HTTPS 相關(guān)
攻防
同源策略和跨域理論相關(guān)
鑒權(quán)
Getting Token Authentication Right in a Stateless Single Page Application
:現(xiàn)代 Web 應(yīng)用的典型身份驗(yàn)證需求">登錄工程:現(xiàn)代 Web 應(yīng)用的典型身份驗(yàn)證需求