在函數計算為HTTP觸發器配置JWT認證鑒權,可以確保只有持有有效JWT的客戶端才能訪問,從而提升HTTP服務的安全性,有效防止未經授權的訪問和阻擋惡意攻擊。
背景信息
簡介
函數計算支持為HTTP觸發器開啟JWT認證鑒權。JWT(JSON Web Token,RFC7519)是一種基于令牌的便捷請求認證鑒權方案。用戶狀態信息存儲在Token中,由客戶端提供,函數(服務端)無需存儲,是一種Serverless友好的鑒權方式。函數計算可以通過用戶綁定在HTTP觸發器上的Public JWKS實現對HTTP調用請求的JWT認證。并根據HTTP觸發器上的配置,將claims
作為參數轉發給函數,函數無需對請求進行鑒權,只需關注業務邏輯即可。如果需要了解JWT的Token
認證流程及基礎知識,請參見基于JWT的token認證和JWT簡介。
JWT認證流程
上圖是函數計算HTTP觸發器利用JWT實現認證的整個業務流程時序圖(使用非對稱加密算法),步驟詳細解析如下。
客戶端向自定義授權服務發起認證請求,請求中一般會攜帶終端用戶的用戶名和密碼。
自定義授權服務讀取請求中的驗證信息(例如用戶名、密碼等)進行驗證,驗證通過之后使用私鑰生成標準的
Token
。自定義授權服務將攜帶
Token
的應答返回給客戶端,客戶端需要將這個Token
緩存到本地。客戶端向HTTP觸發器發送業務請求,請求中攜帶
Token
。HTTP觸發器使用用戶設置的公鑰對請求中的
Token
進行驗證。驗證通過之后,將請求透傳給受保護的函數。
受保護的函數處理業務請求,并進行應答。
HTTP觸發器將業務應答返回給客戶端。
前提條件
使用限制
可以使用任何方式來生成和分發JWT,函數計算負責通過觸發器配置的Public JWKS來認證JWT。
支持不含
kid
的JWK。支持從
header
、Query
參數(GET)、表單參數(POST)和cookie
中讀取Token。支持將
claims
作為header
、Query
參數(GET)、表單參數(POST)和cookie
轉發給函數。函數計算支持為一個HTTP觸發器配置一組JWT(JWKS),在JWKS中尋找與
Token
中的kid
相同的JWK公鑰,并使用這個公鑰對Token
進行簽名校驗。一個觸發器的JWKS最多只允許一個JWK的kid
不存在或者為空字符串。目前函數計算的JWT支持如下算法。
簽名算法
alg取值
RSASSA-PKCS1-V1_5
RS256,RS384,RS512
RSASSA-PSS
PS256,PS384,PS512
Elliptic Curve (ECDSA)
ES256,ES384,ES512
HMAC
HS256,HS384,HS512
EdDSA
EdDSA
重要HMAC簽名算法為對稱加密,安全性相對較低,建議使用安全性更高的非對稱加密算法。
使用非對稱加密算法時,出于安全考慮,您的JWT中只需要包含公鑰信息即可,不建議包含私鑰信息。
建議使用HTTPS來對請求中的
Token
等敏感信息進行保護,可以有效避免Token泄漏。
操作步驟
步驟一:配置JWT認證
- 登錄函數計算控制臺,在左側導航欄,單擊服務及函數。
- 在頂部菜單欄,選擇地域,然后在服務列表頁面,單擊目標服務。
- 在函數管理頁面,單擊目標函數名稱,然后在函數詳情頁面,單擊觸發器管理(URL)頁簽。
在觸發器管理(URL)頁簽,單擊HTTP觸發器操作列的編輯按鈕。
在編輯觸發器面板,設置以下配置項,然后單擊確定。
認證方式選擇為JWT 認證。
配置JWKS。
為HTTP觸發器配置JWT鑒權,首先需要提供一個有效的JWKS(JSON Web Key Set)。您可以自行生成JWKS,或者搜索JSON Web Key Generator尋找在線可用的生成工具,例如mkjwk.org。如果您已經有pem格式的密鑰,可以借助工具(例如jwx),將其轉換為JWKS格式。
本文使用mkjwk.org工具生成JWKS,在生成界面選擇Show X.509為Yes才能查看Private Key。在您的代碼中需要使用Private Key簽發JWT Token,請妥善保存。您可以復制Public Key中的內容填入到控制臺中的JWKS的keys數組中。具體可參考下圖。
本文配置的JWKS示例如下。
{ "keys": [ { "alg": "RS256", "e": "AQAB", "kty": "RSA", "n": "u1LWgoomekdOMfB1lEe96OHehd4XRNCbZRm96RqwOYTTc28Sc_U5wKV2umDzolfoI682ct2BNnRRahYgZPhbOCzHYM6i8sRXjz9Ghx3QHw9zrYACtArwQxrTFiejbfzDPGdPrMQg7T8wjtLtkSyDmCzeXpbIdwmxuLyt_ahLfHelr94kEksMDa42V4Fi5bMW4cCLjlEKzBEHGmFdT8UbLPCvpgsM84JK63e5ifdeI9NdadbC8ZMiR--dFCujT7AgRRyMzxgdn2l-nZJ2ZaYzbLUtAW5_U2kfRVkDNa8d1g__2V5zjU6nfLJ1S2MoXMgRgDPeHpEehZVu2kNaSFvDUQ", "use": "sig" } ] }
在JWT Token 配置配置項中,選擇
Token
所在位置和Token
的名稱。Token
位置支持Header、Cookie、Query參數(GET)和表單參數(POST)。如果Token
位置選擇為Header,則還需為其指定參數名稱和去除前綴。函數計算在獲取Token時,會刪除去除前綴中設定的前綴內容。重要設定去除前綴時,請注意前綴后面是否存在空格。推薦在前綴字段后加一個空格,例如
Bearer
。在JWT Claim 轉換配置項中,選擇透傳給函數的參數所在位置、參數原始名稱和參數透傳給函數之后的名稱。
映射參數位置支持Header、Cookie、Query參數(GET)和表單參數(POST)。
設置請求匹配模式。
匹配全部:所有HTTP請求都需要進行JWT校驗。
白名單模式:請求路徑白名單中設置的Path的HTTP請求不需要JWT校驗,其他請求需要JWT校驗。
黑名單模式:請求路徑黑名單中設置的Path的HTTP請求需要JWT校驗,其他請求不需要JWT校驗。
白名單模式和黑名單模式支持以下兩種匹配模式。
精確匹配
請求的路徑和設置的路徑完全一致才可以匹配。例如,設置請求路徑黑名單為/a,則來自路徑/a的請求需要JWT校驗,來自路徑/a/的請求無需校驗。
模糊匹配
支持使用通配符(*)設置路徑,且通配符(*)只能放到路徑的最后。例如,設置請求路徑黑名單為/login/*,則來自路徑前綴為/login/(例如/login/a、/login/b/c/d)的請求均需要JWT校驗。
步驟二:操作驗證
在調測工具(本文以Postman工具為例)中,根據HTTP觸發器的JWT配置,填寫訪問地址、Token等,驗證是否可以正常訪問HTTP服務。
使用步驟一中生成的X.509 PEM格式的Private Key作為私鑰來頒發JWT Token。以下步驟以Python為例演示通過本地腳本生成Token的過程。
安裝 PyJWT模塊。
pip install PyJWT
在本地運行如下Python示例腳本生成JWT Token。
import jwt import time private_key = """ -----BEGIN PRIVATE KEY----- <使用步驟一生成的 X.509 PEM格式的private key> -----END PRIVATE KEY----- """ headers = { "alg": "RS256", "typ": "JWT" } payload = { "sub": "1234567890", "name": "John Snow", "iat": int(time.time()), # token頒發時間 "exp": int(time.time()) + 60 * 60, # 設定token有效時間為1小時 } encoded = jwt.encode(payload=payload, key=private_key.encode(), headers=headers) print("Generated token: %s" % encoded)
使用Postman工具驗證HTTP服務是否可正常訪問。
在目標函數的觸發器管理(URL)頁簽獲取HTTP觸發器的公網訪問地址,將地址填入Postman的URL位置。
在Postman的Headers配置Token參數信息,然后單擊Send發送請求。本文填寫的Token示例如下。
名稱
示例值
說明
Key
Authentication
在JWT Token 配置中設置的參數名稱。
Value
Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiSm9uIFNub3ciLCJhZG1pbiI6dHJ1ZSwiZXhwIjo0ODI5NTk3NjQxfQ.eRcobbpjAd3OSMxcWbmbicOTLjO2vuLR9F2QZMK4rz1JqfSRHgwQVqNxcfOIO9ckDMNlF_3jtdfCfvXfka-phJZpHmnaQJxmnOA8zA3R4wF4GUQdz5zkt74cK9jLAXpokwrviz2ROehwxTCwa0naRd_N9eFhvTRnP3u7L0xn3ll4iOf8Q4jS0mVLpjyTa5WiBkN5xi9hkFxd__p98Pah_Yf0hVQ2ldGSyTtAMmdM1Bvzad-kdZ_wW0jcctIla9bLnOo-Enr14EsGvziMh_QTZ3HQtJuToSKZ11xkNgaz7an5de6PuF5ISXQzxigpFVIkG765aEDVtEnFkMO0xyPGLg
在JWT Token 配置中設置的去除前綴信息拼接JWT Token。示例值假設去除前綴已設置為
Bearer
。重要請注意,請求header中JWT參數的前綴和空格需要與JWT Token 配置中設置的去除前綴內容一致,否則會導致觸發器解析Token時出錯并返回invalid or expired jwt錯誤。
配合自定義域名使用JWT鑒權
如上圖所示,自定義域名位于HTTP觸發器之前,用戶的請求會先經過自定義域名的處理,然后才會被HTTP觸發器處理,JWT認證鑒權是位于HTTP觸發器上的邏輯。下文介紹自定義域名如何使用JWT認證鑒權。
普通自定義域名
如果為自定義域名配置了路由,未配置重寫策略,那么到達HTTP請求中的Path就是自定義域名請求的Path。
假設自定義域名www.fc-jwt.com
設置的路由規則如下,且函數jwt-demo
的HTTP觸發器設置的JWT鑒權配置中請求路徑黑名單配置為/fc-jwt/auth/*。
路徑 | 服務名 | 函數名 | 版本 |
/fc-jwt/* | jwt | jwt-demo | 1 |
如果用戶請求URL為/fc-jwt/auth/aliyun,則HTTP觸發器會對請求進行校驗,因為到達HTTP觸發器的請求的Path與設置的請求路徑黑名單匹配。
結合自定義域名的重寫功能
如果為自定義域名配置了路由,且配置了重寫策略,那么到達HTTP請求中的Path為自定義域名重寫后的Path。關于自定義域名的重寫功能,請參見配置重寫策略(公測中)。
假設自定義域名www.fc-jwt.com
設置的路由規則如下,函數jwt-demo
的HTTP觸發器設置的JWT鑒權配置中請求路徑黑名單配置為/fc-jwt/auth/*,且配置了通配符重寫策略(匹配規則為/fc-jwt/*
,替換規則為 /$1
)。
路徑 | 服務名 | 函數名 | 版本 |
/fc-jwt/* | jwt | jwt-demo | 1 |
如果用戶請求URL為/fc-jwt/auth/aliyun,則重寫后的URL為/auth/aliyun。關于通配符重寫規則,請參見通配符重寫。此時,HTTP觸發器不會對請求進行校驗,因為到達HTTP觸發器的請求的Path為/auth/aliyun,與設置的請求路徑黑名單不匹配。
如果將觸發器請求路徑黑名單配置為/auth/*,那么HTTP觸發器會對URL為/fc-jwt/auth/aliyun的請求進行JWT校驗。
常見問題
該提示說明JWT鑒權失敗,可能原因如下。
您的Token簽名、格式等非法,導致校驗出錯。
您的Token已過期,導致校驗出錯。
您的Token中的
kid
與您在觸發器中配置的JWKS不匹配,或者匹配到的JWK不準確,無法正確檢驗Token。
該提示說明函數計算無法根據JWT Token配置找到Token,請檢查請求中是否攜帶了Token、Token的位置或Token的名稱是否正確。如果您在配置JWT Token 配置時選擇讀取位置為header,則需要在設置Token時加上去除前綴及空格,否則會報錯。
不會產生額外的費用。函數計算默認提供的網關相關的功能計費都是在函數調用次數中進行收費,所以不管您是否開啟JWT認證,都不會產生額外的費用。