HmacSHA256(해쉬함수)
HMAC-SHA256은 Hash-based Message Authentication Code와 SHA-256 해시 알고리즘을 결합한 암호화 기술입니다.
결제 시스템에서는 주로 결제 데이터의 위변조를 방지(무결성 검증)하고, API 요청자가 정당한 가맹점인지 인증(Authentication)하기 위한 전자 서명(Signature) 생성에 사용됩니다.
🛡️ 왜 사용하는가?
결제 요청 시 악의적인 해커가 중간에서 데이터를 가로채 금액을 10,000원에서 100원으로 조작하여 서버로 보낸다면 심각한 문제가 발생합니다.
HMAC-SHA256을 사용하면 이 문제를 막을 수 있습니다.
- 가맹점과 Easypay는 서로만 아는 비밀 키(Secret Key)를 공유합니다.
- 가맹점은
주문정보 + 비밀키를 조합하여 HMAC-SHA256으로 암호화한 서명(Signature) 값을 함께 보냅니다. - 데이터가 조금이라도 변경되면 생성되는 서명 값이 완전히 달라지므로, 서버는 이를 즉시 감지하고 결제를 거단할 수 있습니다.
일반 SHA-256과의 차이
일반 SHA-256은 단순히 메시지를 해싱하지만, HMAC은 비밀 키(Secret Key)를 함께 사용하여 해싱합니다. 따라서 비밀 키를 모르는 제3자는 유효한 서명 값을 절대 생성할 수 없습니다.
💻 언어별 구현 예제
주문 데이터 문자열(message)과 가맹점 비밀 키(secretKey)를 사용하여 HMAC-SHA256 서명(Hex String)을 생성하는 예제입니다.
Java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
public class HmacExample {
public static String generateSignature(String message, String secretKey) throws Exception {
Mac hmacSha256 = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
hmacSha256.init(secretKeySpec);
byte[] hash = hmacSha256.doFinal(message.getBytes(StandardCharsets.UTF_8));
// Byte Array -> Hex String 변환
StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
}
Node.js
const crypto = require('crypto');
function generateSignature(message, secretKey) {
return crypto
.createHmac('sha256', secretKey)
.update(message)
.digest('hex'); // Hex String으로 출력
}
const message = "orderId=12345&amount=1000";
const secret = "my_secret_key";
console.log(generateSignature(message, secret));
Python
import hmac
import hashlib
def generate_signature(message, secret_key):
# 키와 메시지는 bytes 타입이어야 함
key_bytes = bytes(secret_key, 'utf-8')
message_bytes = bytes(message, 'utf-8')
signature = hmac.new(key_bytes, message_bytes, hashlib.sha256).hexdigest()
return signature
print(generate_signature("orderId=12345&amount=1000", "my_secret_key"))
PHP
<?php
$message = "orderId=12345&amount=1000";
$secret_key = "my_secret_key";
// true를 주면 binary, false(기본값)를 주면 hex string 반환
$signature = hash_hmac('sha256', $message, $secret_key);
echo $signature;
?>