[譯]web權限驗證方法說明

前言

本文將會從最基本的一種web權限驗證提及,即HTTP Basic authentication,而後是基於cookies和tokens的權限驗證,最後則是signatures和一次性密碼。nginx

HTTP Basic authentication

當客戶端發起一個請求時,它可使用HTTP Basic authentication來提供一個用戶名和密碼,來進行權限驗證。git

因爲它不依賴於cookies,sessions等任何外部因素,因此它是最簡單的權限驗證方法。在使用它時,客戶端須要在每次請求時,都附帶上Authorization請求頭,用戶名和密碼都不會被加密,可是須要被格式化爲如下結構:github

  • 用戶名和密碼由一個冒號鏈接,如username:passwordweb

  • 這個字符串需進行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);
};

固然,你也能夠在更高層上實現它,如nginxcookie

HTTP Basic authentication雖然十分簡單,但仍有一些須要注意的地方:session

  • 用戶名和密碼在每次請求時都會被帶上,即便請求是經過安全鏈接發送的,這也是潛在的可能暴露它們的地方。

  • 若是網站使用的加密方法十分弱,或者被破解,那麼用戶名和密碼將會立刻泄露。

  • 用戶經過這種方式進行驗證時,並無登出的辦法

  • 一樣,登錄超時也是沒有辦法作到的,你只能經過修改用戶的密碼來模擬。

Cookies

當服務端在響應HTTP請求時,它能夠在響應頭裏加上Set-Cookie頭。而後瀏覽器會將這個cookie保存起來,並在之後請求同源的地址時,在Cookie請求頭中附上這些cookie。

當使用cookies來進行權限驗證時,有如下幾點須要注意。

老是將cookies設爲HttpOnly

當設置cookies時,老是使用HttpOnly標識,這樣以來cookies就不能經過document.cookies獲取,用以減小被XSS攻擊可能性。

老是使用簽名(signed) cookies

當使用簽名cookies時,服務器則能夠判斷該cookie是否被客戶端更改過。

不足:

  • 須要花費額外的功夫來抵禦CSRF攻擊

  • 與REST風格不匹配。由於它在一個無狀態協議裏注入了狀態。

Tokens

現今,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攻擊

Signatures

不管是使用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/

相關文章
相關標籤/搜索