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)) // 使用HMAC-SHA256算法
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)

// 創建HTTP請求
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)
}

在這段代碼中,generateSignature 函數用來生成簽名。注意,我們使用了HMAC-SHA256算法來確保簽名的安全性。這種方法不僅可靠,而且易于實現。

服務器端:驗證簽名并響應請求

接下來是服務器端的實現,服務器會從請求中提取簽名,并根據相同的算法重新生成簽名,然后進行對比。

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)
}

服務器端的validateSignature函數用來驗證簽名,首先提取出請求中的簽名、時間戳等信息,然后根據與客戶端相同的算法重新生成簽名,并與請求中的簽名對比。如果兩者一致,則表示請求合法。

簽名驗證的優勢

簽名驗證不僅能防止請求被篡改,還能有效防止重放攻擊(Replay Attack)。通過驗證時間戳,我們可以確保請求是在一個合理的時間范圍內發送的,防止有人惡意重復發送相同的請求。

在實際開發中,這種簽名驗證機制雖然看起來步驟繁瑣,但卻是確保API安全性的重要措施之一。通過合理設計和實現,簽名驗證可以在不顯著增加系統負擔的前提下,大幅提升API的安全性。

小結

API開發中,簽名驗證是不可或缺的一環。通過合理的密鑰管理、簽名生成和驗證機制,我們可以確保每一個請求的完整性和可靠性。作為一個程序員,掌握這種技術不僅能讓你的API更加安全,也能讓你在面對潛在的安全威脅時更加從容。

好了,今天就聊到這里。如果你有任何問題或者想法,歡迎在評論區和我討論。我們下次再見,祝大家編程愉快!

文章轉自微信公眾號@Go語言教程

上一篇:

從哪些標準評估API的性能和質量

下一篇:

通過負面測試構建更具彈性的API
#你可能也喜歡這些API文章!

我們有何不同?

API服務商零注冊

多API并行試用

數據驅動選型,提升決策效率

查看全部API→
??

熱門場景實測,選對API

#AI文本生成大模型API

對比大模型API的內容創意新穎性、情感共鳴力、商業轉化潛力

25個渠道
一鍵對比試用API 限時免費

#AI深度推理大模型API

對比大模型API的邏輯推理準確性、分析深度、可視化建議合理性

10個渠道
一鍵對比試用API 限時免費