目字形布局结构的网站,有名的seo外包公司,微商的货源都从哪来,万网买网站HMAC-SHA256 简介
HMAC-SHA256 是一种基于 哈希函数 的消息认证码#xff08;Message Authentication Code, MAC#xff09;#xff0c;它结合了哈希算法#xff08;如 SHA-256#xff09;和一个密钥#xff0c;用于验证消息的完整性和真实性。
HMAC 是 “Hash-based M…HMAC-SHA256 简介
HMAC-SHA256 是一种基于 哈希函数 的消息认证码Message Authentication Code, MAC它结合了哈希算法如 SHA-256和一个密钥用于验证消息的完整性和真实性。
HMAC 是 “Hash-based Message Authentication Code” 的缩写它广泛应用于网络通信中用于保证消息在传输过程中未被篡改同时也可以校验消息是否来自可信方。 HMAC-SHA256 的组成
HMAC-SHA256 的运算公式如下
HMAC(key, message) SHA256((key ⊕ opad) || SHA256((key ⊕ ipad) || message))key一个秘密密钥用于认证消息只有通信双方知道。 message需要进行签名的消息内容。 SHA256一种安全的哈希函数用于生成固定长度的摘要值。 ⊕按位异或操作XOR。 opad 和 ipad opad外部填充字节 (0x5c)。ipad内部填充字节 (0x36)。
流程解释
将密钥与 ipad 结合并将其与消息一起进行第一次哈希。将密钥与 opad 结合并将其与第一次哈希的结果一起进行第二次哈希。最终输出 HMAC 值。 HMAC-SHA256 的特点
基于密钥 与普通的 SHA256 不同HMAC-SHA256 引入了密钥只有通信双方知道密钥保证了消息的认证性。 抗篡改 如果消息在传输过程中被篡改HMAC 认证将失败。 抗重放攻击 通常结合时间戳timestamp或随机数nonce防止消息被恶意重放。 性能高效 基于哈希函数的算法速度快适合高并发场景。 简单易用 常用于 REST API、签名验证和网络协议中。 HMAC-SHA256 的应用场景
API 鉴权 许多云服务和 API 平台如 AWS、阿里云等使用 HMAC-SHA256 来验证 API 请求的真实性和完整性。 消息完整性校验 用于验证消息在传输过程中未被篡改。 数据完整性校验 用于验证文件或数据传输的完整性结合密钥防止恶意伪造。 通信协议 用于加密通信协议如 TLS的消息认证。 Token 签名 用于生成和验证基于密钥的 Token如 JWTJSON Web Token的签名部分。 HMAC-SHA256 的优点
安全性强 基于 SHA-256 的安全性结合密钥使用安全性更高。 对抗攻击 有效抵抗暴力破解、哈希碰撞和中间人攻击。 跨平台支持 各种编程语言和库都支持 HMAC-SHA256。 性能优越 计算量小适合高性能需求的场景。
HMAC 与其他加密算法的对比
特性HMAC-SHA256RSA 签名普通哈希是否需要密钥是是否加密/认证用途认证认证和加密数据完整性校验性能高效较慢高效应用场景API 鉴权、消息验证数字签名、PKI文件校验、数据校验
常见问题
HMAC-SHA256 与普通 SHA-256 有什么区别 SHA-256 是一种单向哈希算法用于生成固定长度的摘要值HMAC-SHA256 是基于 SHA-256 和密钥的消息认证码除了生成摘要外还能验证消息来源和完整性。 HMAC-SHA256 的密钥如何管理 密钥必须严格保密通常存储在安全的配置文件或密钥管理服务如 AWS KMS中。 是否需要 HTTPS HMAC-SHA256 可以防止消息篡改但不能保护消息的机密性。建议配合 HTTPS 使用。 可以用 HMAC-SHA256 替代 RSA 签名吗 如果双方共享密钥HMAC-SHA256 是更高效的选择如果需要非对称签名或验证应该使用 RSA。
代码示例
客户端示例
假设这是一个Java客户端可能是后端服务或桌面应用等要调用你的服务接口 /api/secure并用 HMAC-SHA256 做签名。
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;public class HmacClientExample {public static void main(String[] args) throws Exception {// 1) 准备必要参数String accessKeyId myKeyId;String accessKeySecret myKeySecret; // 保密String method POST;String path /api/secure;// 例如携带一个 timestamp (yyyyMMddHHmmss)String timestamp LocalDateTime.now().format(DateTimeFormatter.ofPattern(yyyyMMddHHmmss));// 2) 如果有请求体需要计算 bodyHash (这里只是示例)// 实际可对 JSON 字符串做 MD5 或 SHA256再 Hex 或 Base64String requestBody {\foo\:\bar\}; // JSONString bodyHash sha256Hex(requestBody);// 3) 拼装 StringToSign (示例逻辑可自定义)// 这里用换行分隔 method, path, timestamp, bodyHashString stringToSign method \n path \n timestamp \n bodyHash;// 4) 做 HMAC-SHA256String signature hmacSha256Base64(stringToSign, accessKeySecret);// 5) 将签名和 keyId、timestamp 放到 HTTP 头部// 伪代码: 构建 HTTP 请求System.out.println(X-AccessKeyId: accessKeyId);System.out.println(X-Timestamp: timestamp);System.out.println(X-Signature: signature);// 之后再把 requestBody 当作 JSON 发出 (POST)// ...// 这是示例演示真实项目中可用 HttpClient、OkHttp 等发请求}/*** 计算字符串的 SHA-256 再转 hex (可选也可用 Base64)*/private static String sha256Hex(String data) throws Exception {MessageDigest digest MessageDigest.getInstance(SHA-256);byte[] bytes digest.digest(data.getBytes(StandardCharsets.UTF_8));return bytesToHex(bytes);}/*** HMAC-SHA256 Base64*/private static String hmacSha256Base64(String data, String secret) throws Exception {Mac mac Mac.getInstance(HmacSHA256);SecretKeySpec keySpec new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), HmacSHA256);mac.init(keySpec);byte[] rawHmac mac.doFinal(data.getBytes(StandardCharsets.UTF_8));return Base64.getEncoder().encodeToString(rawHmac);}private static String bytesToHex(byte[] bytes) {StringBuilder sb new StringBuilder(bytes.length * 2);for (byte b : bytes) {sb.append(String.format(%02x, b));}return sb.toString();}
}核心StringToSign 拼装 HMAC-SHA256 计算签名 在请求头中带上 accessKeyId、timestamp、signature。bodyHash 的计算方式可自行定义也可以用 MD5、直接放明文 body 等。只要客户端和服务端保持一致即可。 服务端示例 (Spring Boot)
下面以 Spring Boot Controller 为例展示如何验证签名。主要逻辑
从 HTTP 头中取 X-AccessKeyId, X-Timestamp, X-Signature。根据 accessKeyId 找到 secret用相同的方式拼装 StringToSign做同样的 HMAC-SHA256 计算比对与客户端传来的 signature 是否相同。
2.1 Controller 示例
RestController
RequestMapping(/api)
public class SecureApiController {// 示例内存中保存 keyId - keySecret 映射private MapString, String keyStore new HashMap();public SecureApiController() {// 假设这里初始化了一个myKeyId - myKeySecretkeyStore.put(myKeyId, myKeySecret);}PostMapping(/secure)public ResponseEntity? secureEndpoint(HttpServletRequest request,RequestBody(requiredfalse) String body // raw JSON) {try {// 1) 从header读取String accessKeyId request.getHeader(X-AccessKeyId);String timestamp request.getHeader(X-Timestamp);String clientSignature request.getHeader(X-Signature);if (accessKeyId null || timestamp null || clientSignature null) {return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(Missing auth headers);}// 2) 查找keySecretString keySecret keyStore.get(accessKeyId);if (keySecret null) {return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(Invalid accessKeyId);}// 3) 计算 bodyHash(可选)// 假设客户端用了 sha256Hex(body)String bodyHash sha256Hex(body null ? : body);// 4) 与客户端相同的拼接方式String method request.getMethod(); // POSTString path request.getRequestURI(); // /api/secure// StringToSignString stringToSign method \n path \n timestamp \n bodyHash;// 5) 服务端做 HMAC-SHA256String serverSignature hmacSha256Base64(stringToSign, keySecret);// 6) 比对签名if (!serverSignature.equals(clientSignature)) {return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(Signature mismatch);}// 7) 可选校验: timestamp 是否过期if (!checkTimestampValid(timestamp)) {return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(Timestamp expired or invalid);}// 8) 一切正常return ResponseEntity.ok(Success! Request body was: body);} catch (Exception e) {return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(Auth error: e.getMessage());}}// 计算 SHA256Hexprivate String sha256Hex(String data) throws Exception {MessageDigest md MessageDigest.getInstance(SHA-256);byte[] digest md.digest(data.getBytes(StandardCharsets.UTF_8));return bytesToHex(digest);}// HMAC-SHA256 Base64private String hmacSha256Base64(String data, String secret) throws Exception {Mac mac Mac.getInstance(HmacSHA256);SecretKeySpec keySpec new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), HmacSHA256);mac.init(keySpec);byte[] rawHmac mac.doFinal(data.getBytes(StandardCharsets.UTF_8));return Base64.getEncoder().encodeToString(rawHmac);}private String bytesToHex(byte[] bytes) {StringBuilder sb new StringBuilder(bytes.length * 2);for (byte b : bytes) {sb.append(String.format(%02x, b));}return sb.toString();}// 时间戳校验 (±15分钟示例)private boolean checkTimestampValid(String timestampStr) {try {// 这里假设 timestampStr 是 yyyyMMddHHmmssDateTimeFormatter fmt DateTimeFormatter.ofPattern(yyyyMMddHHmmss);LocalDateTime reqTime LocalDateTime.parse(timestampStr, fmt);LocalDateTime now LocalDateTime.now();return !reqTime.isBefore(now.minusMinutes(15)) !reqTime.isAfter(now.plusMinutes(15));} catch (Exception e) {return false;}}
}注意上面为了演示方便用 RequestBody(requiredfalse) String body 直接拿到原始 JSON 字符串再做 sha256Hex如果是对象映射你要注意读取流和计算摘要的先后顺序。你也可以在 Filter 或 Interceptor 里做这个签名验签逻辑避免在每个 Controller 里写。timestamp 校验 可能的 nonce 防重放可用 Redis 记录 5 分钟内出现过的 (accessKeyId,timestamp,nonce)以更好地防御重复调用。 总结
客户端 准备 accessKeyId, accessKeySecret拼出 StringToSign通常包含 method、path、timestamp、bodyHash 等HMAC-SHA256( StringToSign, accessKeySecret ) → signature在 HTTP 请求头里带上 accessKeyId, signature, timestamp用 JSON 作为请求体时别忘了和服务端在 bodyHash 算法上保持一致。 服务端 通过 accessKeyId 找到对应的 accessKeySecret按同样规则构造 StringToSign计算 HMAC-SHA256 并和客户端的 signature 对比一致则通过不一致则 401/403可加时间戳、nonce、限流 等加强安全性。 优点 不需要公钥/私钥也不需要RSA 加解密计算速度快、实现相对简单通用性强许多云厂商、API网关都采用类似 HMAC 签名模式。 注意 一定要保护好 accessKeySecret客户端泄露就会被冒用。使用 HTTPS 来保证传输安全防止中间人截获签名或篡改。若对大文件、流式上传等需要在数据处理上稍作适配hash可能需分段计算。
这套 HMAC-SHA256 签名鉴权就是在很多云服务阿里云、AWS、腾讯云都在用的模式。只要客户端与服务端约定好StringToSign 的拼装方式、accessKeyId → secret 映射、时间戳/nonce防重放就能形成一套轻量、高效的对外接口鉴权机制。