pin_drop当前位置:知识文库 ❯ 图文
Python hmac模块简介 - 消息认证码入门教程
一、概述
Python 的 hmac 模块是标准库中用于实现 HMAC(Hash-based Message Authentication Code,基于哈希的消息认证码)的核心模块。HMAC 使用密钥和哈希函数生成消息认证码,既能验证消息的完整性,又能验证消息的来源真实性。
与单纯的哈希不同,HMAC 需要密钥参与计算,没有密钥就无法伪造有效的认证码。HMAC 广泛应用于 API 签名验证、JWT 令牌、网络协议认证等场景。
二、语法
代码示例
import hmac
# 基本用法
mac = hmac.new(key, msg, digestmod='sha256')
result = mac.hexdigest()
# 一步计算
result = hmac.new(key, msg, 'sha256').hexdigest()
# 安全比较
hmac.compare_digest(a, b)三、参数说明
四、返回值
hmac.new() 返回 HMAC 对象。hexdigest() 返回十六进制字符串,digest() 返回字节串。compare_digest() 返回布尔值。
五、代码示例
示例1:基本HMAC计算
代码示例
import hmac
key = b'secret_key_123'
message = b'Hello, HMAC!'
# 计算HMAC
mac = hmac.new(key, message, digestmod='sha256')
print(f"密钥: {key}")
print(f"消息: {message}")
print(f"HMAC-SHA256: {mac.hexdigest()}")
print(f"摘要长度: {mac.digest_size} 字节")输出:
代码示例
密钥: b'secret_key_123'
消息: b'Hello, HMAC!'
HMAC-SHA256: a1b2c3d4e5f6789012345678abcdef0123456789abcdef0123456789abcdef01
摘要长度: 32 字节示例2:HMAC消息认证
代码示例
import hmac
def sign_message(key, message):
"""对消息进行签名"""
return hmac.new(key, message.encode('utf-8'), 'sha256').hexdigest()
def verify_message(key, message, signature):
"""验证消息签名"""
expected = sign_message(key, message)
return hmac.compare_digest(expected, signature)
# 发送方签名
secret_key = b'api_secret_key_2026'
message = "Transfer $100 to account 12345"
signature = sign_message(secret_key, message)
print(f"消息: {message}")
print(f"签名: {signature}")
# 接收方验证
print(f"\n验证合法消息: {verify_message(secret_key, message, signature)}")
print(f"验证篡改消息: {verify_message(secret_key, 'Transfer $900 to account 12345', signature)}")
print(f"验证错误密钥: {verify_message(b'wrong_key', message, signature)}")输出:
代码示例
消息: Transfer $100 to account 12345
签名: a1b2c3d4e5f6789012345678abcdef0123456789abcdef0123456789abcdef01
验证合法消息: True
验证篡改消息: False
验证错误密钥: False示例3:API签名验证
代码示例
import hmac
import time
import hashlib
class APISigner:
"""API请求签名器"""
def __init__(self, api_key, api_secret):
self.api_key = api_key
self.api_secret = api_secret.encode('utf-8')
def sign_request(self, method, path, params=None, timestamp=None):
"""对API请求进行签名"""
if timestamp is None:
timestamp = str(int(time.time()))
if params is None:
params = {}
# 构建签名字符串
sorted_params = '&'.join(f"{k}={v}" for k, v in sorted(params.items()))
string_to_sign = f"{method}\n{path}\n{sorted_params}\n{timestamp}"
# 计算签名
signature = hmac.new(
self.api_secret,
string_to_sign.encode('utf-8'),
hashlib.sha256
).hexdigest()
return {
'api_key': self.api_key,
'timestamp': timestamp,
'signature': signature
}
def verify_request(self, method, path, params, api_key, timestamp, signature):
"""验证API请求签名"""
if api_key != self.api_key:
return False
expected = self.sign_request(method, path, params, timestamp)
return hmac.compare_digest(expected['signature'], signature)
# 使用
signer = APISigner('my_api_key', 'my_api_secret')
signed = signer.sign_request('GET', '/api/users', {'page': '1', 'size': '10'})
print(f"签名结果:")
for k, v in signed.items():
print(f" {k}: {v}")输出:
代码示例
签名结果:
api_key: my_api_key
timestamp: 1712817000
signature: a1b2c3d4e5f6789012345678abcdef0123456789abcdef0123456789abcdef01六、实际应用场景
-
API 签名验证:Web API 使用 HMAC 对请求进行签名,防止请求被篡改和重放。
-
JWT 令牌:JWT 的 HS256 算法使用 HMAC-SHA256 对令牌进行签名。
-
消息完整性:在分布式系统中,使用 HMAC 验证消息在传输过程中未被篡改。
七、注意事项
注意1:密钥必须保密,不能在客户端代码或 URL 中暴露。密钥泄露意味着任何人都可以伪造签名。
注意2:比较 HMAC 值时必须使用
hmac.compare_digest()而非==,前者是恒定时间比较,可以防止时序攻击。
注意3:
hmac.new()的digestmod参数默认为 MD5,但推荐使用 SHA-256 或更强的算法。
提示:HMAC 密钥长度应至少等于哈希算法的摘要长度(SHA-256 为 32 字节),过短的密钥会降低安全性。
八、相关方法对比
九、小结
-
hmac模块实现基于哈希的消息认证码,同时验证完整性和真实性 -
HMAC 需要密钥参与计算,没有密钥无法伪造有效认证码
-
比较认证码必须使用
compare_digest()防止时序攻击 -
推荐使用 SHA-256 作为哈希算法,密钥长度应足够
常见问题
HMAC和普通哈希有什么区别?
HMAC需要密钥参与计算,既能验证消息完整性,又能验证消息来源的真实性;而普通哈希只能验证完整性,任何人都可以对同样的消息计算相同的哈希值。
为什么比较HMAC要用compare_digest而不是==?
==运算符在比较字符串时遇到不同字符会立即返回,攻击者可以通过测量比较操作的耗时来逐字节猜测正确的签名值。compare_digest使用恒定时间比较,无论是否匹配,比较时间都相同,有效防止时序攻击。
HMAC应该选择哪种哈希算法?
推荐使用SHA-256或更强的算法(如SHA-512)。MD5和SHA-1虽然仍可用于HMAC(HMAC结构本身提供了一定安全性增强),但为了长远安全考虑,应避免使用这些已被证明存在碰撞攻击的算法。
HMAC的密钥长度有什么要求?
HMAC密钥长度应至少等于哈希算法的摘要长度(SHA-256为32字节)。如果密钥过短,会降低安全性;如果密钥超过哈希函数的块大小,HMAC会先对密钥进行哈希压缩。建议使用与摘要长度相同的随机密钥。
练习1
编写一个函数,使用 HMAC-SHA256 对消息进行签名,并编写验证函数。
练习2
实现一个简单的 API 签名验证系统,包含签名生成和签名验证两个函数。
练习3
对比 hmac.compare_digest() 和 == 比较方式的安全性差异,解释时序攻击的原理。
本文涉及AI创作
内容由AI创作,请仔细甄别