查看: 89|回复: 3

Python实现API接口签名调用的完整指南:HMAC-SHA256、JWT、RSA实例

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
在调用第三方API时,签名是保证请求身份真实性与数据完整性的关键步骤。服务端通过验证签名来判断请求是否合法、是否被篡改。本文将基于Python语言,从原理到代码,覆盖主流签名方式,并重点解析一种基于HMAC-SHA256的签名实现(类似WPS4风格),同时给出OAuth 2.0、JWT、RSA非对称签名和MD5参数签名的实战示例。

1. 签名调用通用流程
无论采用何种算法,签名调用通常按以下步骤进行:
- 准备请求参数:包括业务参数(如文件ID、金额)、公共参数(如access_key、timestamp、nonce)。
- 按照API文档规定的规则(如排序、拼接、添加密钥)生成待签名字符串,并使用指定加密算法(如HMAC-SHA256、RSA-SHA256)计算签名。
- 将签名放入请求头(Header)或请求体中发送。
- 服务端收到请求后,用相同规则和密钥重新计算签名,比对一致则通过验证,否则返回4xx错误。

2. 基于HMAC-SHA256的请求签名实现(核心示例)
以下代码演示了一个完整的签名生成与HTTP请求发起过程。该实现源自类似WPS4的API签名规范,通用性好,可直接套用于其他要求HMAC-SHA256签名的接口。
  1. import json
  2. import requests
  3. import hashlib
  4. import time
  5. import hmac
  6. access_key = 'xxxxxxxxxxxxxxx'
  7. secret_key = 'xxxxxxxxxxxxxxx'
  8. def _wps4_sig(method, url, date, body):
  9.     print(body)
  10.     if body is None:
  11.         bodySha = ""
  12.     else:
  13.         bodySha = hashlib.sha256(body.encode('utf-8')).hexdigest()
  14.     content = "xxx-4" + method + url + "application/json" + date + bodySha
  15.     print(content)
  16.     signature = hmac.new(secret_key.encode('utf-8'), content.encode('utf-8'), hashlib.sha256).hexdigest()
  17.     return "xxx-4 %s:%s" % (access_key, signature)
  18. def wps4_request(method, host, uri, body=None, cookie=None, headers=None):
  19.     requests.packages.urllib3.disable_warnings()
  20.     if body is not None and not isinstance(body, str):
  21.         body = json.dumps(body)
  22.     date = time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime())
  23.     header = {"Content-type": "application/json"}
  24.     header['xxx-Docs-Date'] = date
  25.     header['xxx-Docs-Authorization'] = _wps4_sig(method, uri, date, body)
  26.     if headers is not None:
  27.         for key, value in headers.items():
  28.             header[key] = value
  29.     url = "%s%s" % (host, uri)
  30.     r = requests.request(method, url, data=body, headers=header, cookies=cookie, verify=False)
  31.     return r.status_code, r.text
  32. def edit(file_id=1):
  33.     uri = '/api/edit/v1/files/{0}/link?type=w'.format(file_id)
  34.     result = wps4_request('GET', 'http://xx.xx.xx.xxx:xxxx/open', uri)
  35.     print(result[0])
  36.     print(result[1])
  37. if __name__ == '__main__':
  38.     edit()
复制代码
关键点解释:
- _wps4_sig 函数将请求方法、URI、Content-Type、日期和请求体SHA256摘要拼接成字符串,再用HMAC-SHA256算法以secret_key为密钥计算签名。返回格式为“xxx-4 access_key:signature”。
- 日期必须按照RFC 1123格式生成,服务端会验证该时间戳,防止重放攻击。
- 请求体为空时 bodySha 置为空字符串,否则对body进行SHA256哈希。
- wps4_request 自动处理日期、签名头和请求发送,返回状态码和响应文本。
- 该签名方式适用于需要高安全级别的RESTful API调用,如办公套件、云存储等服务的接口。

3. 其他常见签名方式及Python实现

3.1 OAuth 2.0 客户端凭证模式
适用于服务器到服务器的授权(如Google、GitHub API)。
  1. import requests
  2. def get_oauth_token(client_id, client_secret, token_url):
  3.     data = {
  4.         'grant_type': 'client_credentials',
  5.         'client_id': client_id,
  6.         'client_secret': client_secret,
  7.     }
  8.     resp = requests.post(token_url, data=data)
  9.     return resp.json()['access_token']
  10. # 获取 token 并调用
  11. client_id = 'your_client_id'
  12. client_secret = 'your_secret'
  13. token_url = 'https://auth.example.com/token'
  14. token = get_oauth_token(client_id, client_secret, token_url)
  15. headers = {'Authorization': f'Bearer {token}'}
  16. resp = requests.get('https://api.example.com/data', headers=headers)
复制代码
注意:access_token有过期时间,需缓存并定期刷新。

3.2 JWT(JSON Web Token)
常用于用户登录态和微服务间认证。JWT自包含用户信息,无需服务端存储会话。
  1. import jwt
  2. import time
  3. SECRET_KEY = 'your_secret_key'
  4. payload = {
  5.     'user_id': 123,
  6.     'exp': int(time.time()) + 3600  # 1小时后过期
  7. }
  8. token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')
  9. headers = {'Authorization': f'Bearer {token}'}
  10. resp = requests.get('https://api.example.com/protected', headers=headers)
复制代码
JWT也可使用RS256(RSA)非对称算法,此时需要提供公私钥对。

3.3 RSA非对称签名(私钥签名,公钥验证)
适用于支付回调、银行接口等高安全场景。
  1. from cryptography.hazmat.primitives import hashes, serialization
  2. from cryptography.hazmat.primitives.asymmetric import padding
  3. import base64
  4. import requests
  5. def sign_with_rsa(private_key_pem, message):
  6.     private_key = serialization.load_pem_private_key(private_key_pem, password=None)
  7.     signature = private_key.sign(
  8.         message.encode('utf-8'),
  9.         padding.PKCS1v15(),
  10.         hashes.SHA256()
  11.     )
  12.     return base64.b64encode(signature).decode('utf-8')
  13. # 使用示例
  14. with open('private_key.pem', 'rb') as f:
  15.     private_key = f.read()
  16. message = 'GET /api/v1/resource'
  17. signature = sign_with_rsa(private_key, message)
  18. headers = {'X-Signature': signature, 'X-User': 'client_id'}
  19. resp = requests.get('https://api.example.com/resource', headers=headers)
复制代码
签名内容需严格按照API文档约定,可能是整个请求行或参数的摘要。

3.4 简单的MD5参数签名(老旧系统)
部分旧版接口仍使用此方式,安全性较低,建议尽快升级。
  1. import hashlib
  2. import requests
  3. def md5_sign(params, salt):
  4.     raw = f"key1={params['key1']}&key2={params['key2']}&salt={salt}"
  5.     return hashlib.md5(raw.encode('utf-8')).hexdigest()
  6. params = {'amount': 100, 'order_id': '123'}
  7. params['sign'] = md5_sign(params, 'your_salt')
  8. resp = requests.post('https://api.example.com/pay', data=params)
复制代码
排序和拼接方式以API文档为准,通常按参数名顺序拼接。

4. 总结
本文从实际项目出发,展示了Python实现API接口签名的多种方法。核心示例基于HMAC-SHA256算法,通过拼接特定字符串并计算签名,可适配大多数RESTful服务。其他三种方式(OAuth 2.0、JWT、RSA、MD5)覆盖了从简单到高安全的典型场景。实际开发中,需仔细阅读API文档,明确签名规则、密钥获取方式以及过期机制。建议新系统优先使用HMAC-SHA256或RSA-SHA256,放弃MD5。掌握这些签名调用技巧,能极大提升开发效率和接口安全防护能力。
回复

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: Python实现API接口签名调用的完整指南:HMAC-SHA256、JWT、RSA实例

感谢楼主的分享,这份指南非常详尽,尤其是HMAC-SHA256签名的实现部分,从拼接规则到日期格式都写得很清楚,对实际开发很有帮助。不过帖子在OAuth 2.0部分好像被截断了,后面的JWT和RSA实例没看到,楼主方便补全一下吗?另外想请教一下,如果请求体是嵌套的JSON对象,SHA256是对整个字符串做哈希吗?期待后续内容!
回复 支持 反对

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: Python实现API接口签名调用的完整指南:HMAC-SHA256、JWT、RSA实例

非常感谢楼主的分享,非常实用的教程!代码结构清晰,关键点解释也很到位,特别是HMAC-SHA256签名部分的拼接逻辑和日期格式化细节,对于新手来说很容易上手。想请教一下:如果请求体是二进制数据(比如上传文件),bodySha的计算是否需要特殊处理?另外,当前实现中似乎没有加入nonce随机数,是否计划在后续版本中增加这一层防重放机制?期待楼主更新JWT和RSA部分的完整示例!
回复 支持 反对

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: Python实现API接口签名调用的完整指南:HMAC-SHA256、JWT、RSA实例

楼主的分享非常详细,HMAC-SHA256那段代码直接就能跑起来,很适合做通用签名模板。我在复制学习时发现一个小点:`wps4_request` 函数里自定义 headers 赋值那行 `header = value` 似乎应该是 `header = value`,不然会把整个字典覆盖掉,算是个笔误但容易踩坑。 另外想请教一下楼主的这个签名方案里有没有考虑 `nonce` 随机数?很多 API 除了时间戳还会加随机串防重放,如果用时间戳容差的话服务端一般设多少秒?期待后续 JWT 和 RSA 的部分补上,特别是 RSA 私钥签名、公钥验证的实战例子,企业换 key 时特别需要。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-6-26 12:29 , Processed in 0.033893 second(s), 17 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部