ITPub博客

首页 > 数据库 > 数据库开发技术 > 任选一种签名方式,提高接口安全性

任选一种签名方式,提高接口安全性

原创 数据库开发技术 作者:皇子谈技术 时间:2024-03-23 18:09:34 0 删除 编辑

网址:https://itgogogo.cn

大家好,我是皇子。

有人会好奇:``SSL/TLS`等加密协议后,还要做API签名?

虽然SSL/TLS等加密协议为数据传输提供了安全通道,确保数据在传输过程中不被窃听和篡改。

但这并不能完全满足API安全的所有需求,SSL/TLS主要是提供数据加密、传输安全和服务器身份验证,但它并不一定能验证客户端的身份。API签名则可以保证请求的合法性、可靠性和完整性,一旦请求被篡改或伪造,签名校验就会失败,防止了恶意攻击。

同时,签名机制与``SSL/TLS`等加密协议是互补的,它们在安全性方面起到协同作用。

在安全方面,很多企业都会做三级等保认证:

❝

“三级等保”指的是我国的“信息安全等级保护三级认证”,这是根据《中华人民共和国网络安全法》和《信息安全等级保护管理办法》等法规要求,对信息系统安全保护的一个等级划分和认证标准。它是针对非银行机构的最高保护级别。

三级等保标准的信息系统需要在物理安全、网络安全、主机安全、应用安全、数据安全和安全管理等多个层面实施严格的保护措施。

API签名的作用

身份验证:API签名有助于验证发起请求的来源是否合法和可信。通过签名,服务器可以确认请求确实是由持有正确密钥或证书的客户端发出的,从而防止未授权的访问。

数据完整性:签名可以确保数据在传输过程中没有被篡改。当数据和签名一同发送时,服务器通过对数据重新计算签名并与接收到的签名对比,可以检测数据是否在传输过程中发生了变化。

防止重放攻击:结合时间戳和nonce(一次性令牌)等元素,签名可以帮助防止恶意用户捕获并重放之前合法的API请求,确保每个请求只能执行一次且在有效期内。

访问控制:不同的API调用可能有不同的权限要求,通过API签名,服务端可以根据签名信息实施细粒度的访问控制策略,限制不同用户或应用对API资源的访问级别。

安全合规:在很多行业和法规环境中,确保API交互的安全性是法律或行业规定的基本要求,API签名是达到这一要求的技术手段之一。

防止中间人攻击:加密签名可以配合SSL/TLS等加密协议,进一步增强安全性,使得第三方难以拦截并篡改数据,同时确保消息在传输过程中不被中间人窃听或篡改。

六种 API 签名方式

1. HMAC签名

HMAC签名通过使用密钥和哈希函数(如SHA-256)来保证请求的安全性。它结合了密钥与消息内容生成固定长度的哈希值,以此作为请求的签名。在API请求中,所有待签名的内容会被规范化并用密钥通过HMAC算法计算签名,然后将其随请求一起发送至服务器端进行验证。

Golang实现代码:

package main

import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"net/url"
"strings"
)

func createHMACSignature(secretKey []byte, method string, urlStr string, params map[string]string) string {
// 参数排序和规范化
sortedParams := url.Values{}
for k, v := range params {
sortedParams.Add(k, v)
}
paramStr := sortedParams.Encode()

// 创建消息摘要
message := fmt.Sprintf("%s\n%s\n%s", strings.ToUpper(method), urlStr, paramStr)
h := hmac.New(sha256.New, secretKey)
h.Write([]byte(message))
signature := h.Sum(nil)

return hex.EncodeToString(signature)
}

func main() {
params := map[string]string{"key1": "value1", "key2": "value2"}
secretKey := []byte("your-secret-key")
method := "POST"
urlStr := "/api/path"

signature := createHMACSignature(secretKey, method, urlStr, params)
fmt.Println("Generated HMAC Signature:", signature)
}

// 注意:在实际应用中,需要确保将签名加入到请求头或请求体中发送给服务器验证。

优点:

  • 安全性强,通过密钥与哈希函数保证了数据完整性与不可抵赖性。
  • 性能较好,计算效率相对较高。

缺点:

  • 密钥管理较为关键,一旦密钥泄露则签名保护失效。
  • 不能解决密钥分发和撤销的问题。

2. RSA签名

RSA签名基于非对称加密算法,客户端使用私钥对请求内容进行签名,服务器端使用对应的公钥验证签名。这种方式确保只有持有私钥的实体才能产生有效的签名。

Golang实现代码:

package main

import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"encoding/base64"
"fmt"
)

func signWithRSA(privateKey *rsa.PrivateKey, data []byte) (string, error) {
hashed := sha256.Sum256(data)
signature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashed[:])
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(signature), nil

// 省略加载私钥部分,通常从文件或其他安全存储中读取私钥
}

func main() {
// 假设已经正确加载了privateKey
privateKey, _ := loadPrivateKey()
method := "POST"
urlStr := "/api/path"
payload := "your-request-payload"
dataToSign := []byte(fmt.Sprintf("%s\n%s\n%s", strings.ToUpper(method), urlStr, payload))

signature, err := signWithRSA(privateKey, dataToSign)
if err != nil {
panic(err)
}
fmt.Println("Generated RSA Signature:", signature)
}

// 注意:同样需要将签名传递给服务器验证。

优点:

  • 非对称加密特性保证了即使密钥在网络中传输也不影响安全性。
  • 支持密钥撤销,因为可以更换公钥。

缺点:

  • 计算开销相对较大,尤其对于大尺寸数据。
  • 私钥的管理和保护更加重要。

3. 时间戳和Nonce签名

时间戳和Nonce通常是结合其他签名方式使用的增强措施。时间戳用来防止重放攻击,每个请求都带上当前时间戳,服务器只接受一定时间段内的请求。Nonce是一个随机数,确保每次请求唯一,防止重复利用同一个签名。

这个概念本身不涉及特定代码实现,但在任何签名方法中都可以添加时间戳和Nonce字段,比如在HMAC或RSA签名的数据字符串中包含它们。

优点:

  • 防止重放攻击,增加了请求的时效性。
  • 提高了请求的唯一性,避免了单一签名在多个请求中的复用。

缺点:

  • 服务器需要处理时间同步问题,确保客户端和服务器之间的时间差在可接受范围内。
  • 对Nonce的生成和验证逻辑要求严格,以防止碰撞。

4. 基于Token的签名(如JWT)

JSON Web Tokens (JWT) 是一种标准,通过使用密钥(HS256使用HMAC,RS256使用RSA)对载荷(payload)进行签名,形成一个可以在各方之间安全传输的信息载体。JWT包含了头信息、载荷和签名三部分,服务器通过验证签名确认JWT的有效性和完整性。

Golang实现(使用jwt-go库):

package main

import (
"time"
"github.com/dgrijalva/jwt-go"
)

func generateJWT(secretKey []byte, claims jwt.MapClaims) (string, error) {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

// 设置过期时间等信息
claims["exp"] = time.Now().Add(time.Hour * 24).Unix()

tokenString, err := token.SignedString(secretKey)
if err != nil {
return "", err
}
return tokenString, nil
}

func main() {
secretKey := []byte("your-secret-key")
claims := jwt.MapClaims{
"sub": "1234567890",
"name": "John Doe",
"iat": time.Now().Unix(),
}

token, err := generateJWT(secretKey, claims)
if err != nil {
panic(err)
}
fmt.Println("Generated JWT Token:", token)
}

// 使用时将JWT放入Authorization头(Bearer 模式)发送给服务器验证。

优点:

  • 自包含性好,携带用户信息方便。
  • 可配置有效期,自动处理过期验证。

缺点:

  • 若密钥泄露,所有已签发的Token均可能被伪造。
  • 一旦签发无法撤销,除非设置较短的有效期。

5. 参数签名

参数签名是指对请求中所有参数(包括URL、Header、Body等)按照特定规则排序后,再通过某种签名算法生成签名字符串,通常附加在请求的参数列表中一同发送给服务器验证。

这部分的实现与上述HMAC签名类似,只是侧重于对所有参数的处理和排序。

6. HTTP Header签名

技术原理:HTTP Header签名是在HTTP请求头中添加特定的签名字段,常见的做法是在Authorization头中携带经过签名的字符串。这可以采用上述任意一种签名算法,将签名结果放置在Authorization头中,例如 Authorization: Signature keyId="...", signature="...", headers="...", algorithm="..."。

Golang实现:此方法的具体实现会根据所选择的签名算法有所不同,但基本思路都是计算出签名之后,将其设置到请求头中:

package main

import (
"net/http"
)

func setHeaderSignature(r *http.Request, signature string) {
r.Header.Set("Authorization", fmt.Sprintf("Signature keyId=%q, signature=%q, algorithm=HMAC-SHA256", "key-id-value", signature))
}

func main() {
req, _ := http.NewRequest("POST", "/api/path", nil)
// 假设signature已通过HMAC或其他方式计算得出
signature := calculateSignature()

setHeaderSignature(req, signature)
// 发送请求...
}

优点:

  • 将签名与常规HTTP头结构集成,易于服务器解析和验证。
  • 可以更好地与HTTP协议的其他特性结合,如CORS等。

缺点:

  • 需要保持请求头的规范性和一致性,否则可能导致签名验证失败。

小结

我们认识了做API 签名的必要性,以及详细介绍API签名的六种方式:HMAC签名、RSA签名、时间戳和Nonce签名、基于Token的签名、参数签名、HTTP Header签名。

推荐阅读

百度,别淘汰程序员,没人用 ping 了

保护数据,一套安全架构设计方案

我也开源了一个模型生成工具!

认识大模型Embedding技术,加代码实战

写了个小程序,解决朋友全家烦恼

觉得有用,点个赞、在看或分享 再走呀

原文作者:皇子谈技术;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2023-12-21

  • 博文量
    113
  • 访问量
    56524