Golang做API開發離不開簽名驗證,如何設計 ?
作者:磊豐
在API開發中,簽名驗證是一種常見的安全措施,用于確保請求的完整性和來源的可靠性。以下是設計一個簽名驗證機制的步驟和示例代碼。
在API開發中,簽名驗證是一種常見的安全措施,用于確保請求的完整性和來源的可靠性。以下是設計一個簽名驗證機制的步驟和示例代碼。
設計思路
- 密鑰管理:為每個客戶端分配一個唯一的API密鑰和API密鑰。
- 簽名生成:客戶端在請求API時,使用預定義的算法生成簽名,并將簽名和其他必要參數(如時間戳、隨機數等)一起發送到服務器。
- 簽名驗證:服務器接收到請求后,根據相同的算法重新生成簽名,并與請求中的簽名進行對比,如果匹配,則驗證通過。
簽名生成與驗證步驟
- 客戶端:
- 生成時間戳和隨機數。
- 將API密鑰、時間戳、隨機數、請求參數等按照預定義的順序拼接成字符串。
- 使用API密鑰對字符串進行哈希運算(如HMAC-SHA256)生成簽名。
- 將簽名、時間戳、隨機數等信息作為請求參數發送到服務器。
- 服務器:
- 從請求中提取簽名、時間戳、隨機數等信息。
- 驗證時間戳是否在合理范圍內(防止重放攻擊)。
- 根據相同的算法重新生成簽名。
- 對比服務器生成的簽名和請求中的簽名,如果匹配,則驗證通過。
示例代碼
以下是一個簡單的Go語言實現,用于演示API簽名驗證。
客戶端代碼
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"net/http"
"net/url"
"strconv"
"time"
)
func generateSignature(apiSecret, apiKey, timestamp, nonce string, params url.Values) string {
message := apiKey + timestamp + nonce + params.Encode()
mac := hmac.New(sha256.New, []byte(apiSecret))
mac.Write([]byte(message))
signature := hex.EncodeToString(mac.Sum(nil))
return signature
}
func main() {
apiKey := "your_api_key"
apiSecret := "your_api_secret"
timestamp := strconv.FormatInt(time.Now().Unix(), 10)
nonce := "random_nonce"
params := url.Values{}
params.Set("param1", "value1")
params.Set("param2", "value2")
signature := generateSignature(apiSecret, apiKey, timestamp, nonce, params)
req, err := http.NewRequest("GET", "http://example.com/api", nil)
if err != nil {
fmt.Println("Error creating request:", err)
return
}
query := req.URL.Query()
query.Add("apiKey", apiKey)
query.Add("timestamp", timestamp)
query.Add("nonce", nonce)
query.Add("signature", signature)
req.URL.RawQuery = query.Encode()
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error making request:", err)
return
}
defer resp.Body.Close()
fmt.Println("Response status:", resp.Status)
}
服務器端代碼
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"net/http"
"net/url"
"strconv"
"time"
)
const (
apiKey = "your_api_key"
apiSecret = "your_api_secret"
)
func generateSignature(apiSecret, apiKey, timestamp, nonce string, params url.Values) string {
message := apiKey + timestamp + nonce + params.Encode()
mac := hmac.New(sha256.New, []byte(apiSecret))
mac.Write([]byte(message))
return hex.EncodeToString(mac.Sum(nil))
}
func validateSignature(r *http.Request) bool {
apiKey := r.URL.Query().Get("apiKey")
timestamp := r.URL.Query().Get("timestamp")
nonce := r.URL.Query().Get("nonce")
signature := r.URL.Query().Get("signature")
if apiKey != apiKey {
return false
}
timeInt, err := strconv.ParseInt(timestamp, 10, 64)
if err != nil {
return false
}
if time.Now().Unix()-timeInt > 300 {
return false
}
params := r.URL.Query()
params.Del("signature")
expectedSignature := generateSignature(apiSecret, apiKey, timestamp, nonce, params)
return hmac.Equal([]byte(signature), []byte(expectedSignature))
}
func handler(w http.ResponseWriter, r *http.Request) {
if !validateSignature(r) {
http.Error(w, "Invalid signature", http.StatusUnauthorized)
return
}
fmt.Fprintf(w, "Request is authenticated")
}
func main() {
http.HandleFunc("/api", handler)
http.ListenAndServe(":8080", nil)
}
代碼說明
- 客戶端:
- generateSignature函數生成簽名。
- 使用當前時間戳和隨機數生成簽名,并將簽名和其他必要參數添加到請求中。
- 服務器端:
- generateSignature函數用于重新生成簽名。
- validateSignature函數驗證請求中的簽名,包括檢查時間戳是否在合理范圍內,防止重放攻擊。
- handler函數處理請求并驗證簽名,如果驗證通過,則返回成功響應。
通過這種方式,API請求可以通過簽名驗證機制確保請求的完整性和來源的可靠性,有效防止重放攻擊和篡改。
責任編輯:武曉燕
來源:
Go語言圈