本文將會從最基本的一種web權限驗證提及,即HTTP Basic authentication,而後是基於cookies和tokens的權限驗證,最後則是signatures和一次性密碼。nginx
當客戶端發起一個請求時,它可使用HTTP Basic authentication來提供一個用戶名和密碼,來進行權限驗證。git
因爲它不依賴於cookies,sessions等任何外部因素,因此它是最簡單的權限驗證方法。在使用它時,客戶端須要在每次請求時,都附帶上Authorization
請求頭,用戶名和密碼都不會被加密,可是須要被格式化爲如下結構:github
用戶名和密碼由一個冒號鏈接,如username:password
web
這個字符串需進行Base64編碼算法
Basic
關鍵字需被放置在這個編碼後的字符串的前面瀏覽器
例子:安全
curl --header "Authorization: Basic am9objpzZWNyZXQ=" my-website.com
在Node.js
中實現它是很是簡單的,如下是一個經過Express
中間件來實現的例子:服務器
import basicAuth from 'basic-auth'; function unauthorized(res) { res.set('WWW-Authenticate', 'Basic realm=Authorization Required'); return res.send(401); }; export default function auth(req, res, next) { const {name, pass} = basicAuth(req) || {}; if (!name || !pass) { return unauthorized(res); }; if (name === 'john' && pass === 'secret') { return next(); } return unauthorized(res); };
固然,你也能夠在更高層上實現它,如nginx
。cookie
HTTP Basic authentication雖然十分簡單,但仍有一些須要注意的地方:session
用戶名和密碼在每次請求時都會被帶上,即便請求是經過安全鏈接發送的,這也是潛在的可能暴露它們的地方。
若是網站使用的加密方法十分弱,或者被破解,那麼用戶名和密碼將會立刻泄露。
用戶經過這種方式進行驗證時,並無登出的辦法
一樣,登錄超時也是沒有辦法作到的,你只能經過修改用戶的密碼來模擬。
當服務端在響應HTTP請求時,它能夠在響應頭裏加上Set-Cookie
頭。而後瀏覽器會將這個cookie保存起來,並在之後請求同源的地址時,在Cookie
請求頭中附上這些cookie。
當使用cookies來進行權限驗證時,有如下幾點須要注意。
HttpOnly
當設置cookies時,老是使用HttpOnly
標識,這樣以來cookies就不能經過document.cookies
獲取,用以減小被XSS攻擊可能性。
當使用簽名cookies時,服務器則能夠判斷該cookie是否被客戶端更改過。
不足:
須要花費額外的功夫來抵禦CSRF攻擊
與REST風格不匹配。由於它在一個無狀態協議裏注入了狀態。
現今,JWT(JSON Web Token)無處不在。讓咱們先來看看它到底長什麼樣。
JWT由三部分組成:
Header
,由token的類型和哈希算法組成
Payload
,包含了內容主體
Signature
,當你選擇HMAC SHA256算法時,它由HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
計算得出。
將你的Koa
應用加上JWT僅需幾行代碼:
var koa = require('koa'); var jwt = require('koa-jwt'); var app = koa(); app.use(jwt({ secret: 'very-secret' })); // Protected middleware app.use(function *(){ // content of the token will be available on this.state.user this.body = { secret: '42' }; });
例子:
curl --header "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ" my-website.com
若是你在寫提供給原生移動應用或單頁web應用的API,JWT是一個不錯的選擇。
不足:
須要額外的措施來防禦XSS攻擊
不管是使用cookies仍是token,若是你傳輸的內容被他人截獲,那麼它們將能夠很容易得假裝成真實的用戶。
若是解決這個問題?當咱們討論的是API之間的通訊,而不是瀏覽器之間的通訊時,有一個辦法。
當API的消費者發送一個須要權限驗證的請求時,你能夠對整個請求用一個私鑰進行哈希。你可使用的請求的內容有:
HTTP方法
請求路徑
HTTP頭
HTTP體
以及一個私鑰
API的消費者和提供者都必須持有相同的私鑰。在生成了signature
以後,你必須將其加在query string
或HTTP頭中。另外,還需附上一個時間戳,用於判斷過時。
當這麼作時,即便你傳輸的內容暴露了,攻擊者也沒法假裝成真實用戶,由於它沒法本身生成signature
。
不足:
不能用於瀏覽器/客戶端中,只能用於API之間的通訊中。
一次性密碼算法使用一個共享的密鑰和一個當前時間戳或計數器來生成一個一次性密碼:
基於時間的一次性密碼算法,使用一個當前時間的時間戳
基於HMAC的一次性密碼算法,使用一個計數器
這些方法被用於雙重認證(two-factor authentication)中:一個用戶輸入了用戶名和密碼,而後服務器和客戶端同時生成一個一次性密碼。
在Node.js
中,使用notp實現它是相對簡單的。
不足:
若是共享密鑰被竊取,那麼用戶的token將能夠被僞造
若是你只需支持一個web應用,那麼cookies和tokens的實現都是能夠的(cookies對XSRF的防禦較好,而JWT則更易於防禦XSS)。
若是你須要同時支持web應用和移動客戶端,那麼請使用基於token的驗證。
若是你正在構建僅與其餘API通訊的API,那麼就使用signatures。
原文連接:https://blog.risingstack.com/web-authentication-methods-explained/