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)

三、参数说明

参数 类型 说明
key bytes 密钥
msg bytes 消息数据
digestmod str/callable 哈希算法(默认'md5',推荐'sha256')
方法 说明
hmac.new() 创建HMAC对象
update(data) 追加消息数据
digest() 返回字节串认证码
hexdigest() 返回十六进制认证码
copy() 复制HMAC对象
compare_digest() 安全比较两个摘要

四、返回值

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() 而非 ==,前者是恒定时间比较,可以防止时序攻击。

注意3hmac.new()digestmod 参数默认为 MD5,但推荐使用 SHA-256 或更强的算法。

提示:HMAC 密钥长度应至少等于哈希算法的摘要长度(SHA-256 为 32 字节),过短的密钥会降低安全性。


八、相关方法对比

对比项 HMAC 普通哈希 数字签名(RSA) 对称加密
密钥 对称密钥 非对称密钥 对称密钥
完整性
认证性
保密性
速度 最快

九、小结

  • 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()== 比较方式的安全性差异,解释时序攻击的原理。

标签: HMAC 消息认证码 Python标准库 API签名 安全编程

本文涉及AI创作

内容由AI创作,请仔细甄别

list快速访问

上一篇: Python文件哈希计算详解 - 大文件完整性校验完整指南 下一篇: Python hmac.new详解 - HMAC对象创建与使用指南

poll相关推荐