본문으로 건너뛰기

메시지 인증 (Message Authentication)

메시지 인증이란 통신 중인 데이터가 전송 과정에서 변조되지 않았음(무결성)을 확인하고, 데이터 전송자가 신뢰할 수 있는 대상(인증)인지를 검증하는 보안 기술입니다.

API 개발, 특히 결제 시스템에서는 해커가 요청 금액을 10,000원에서 10원으로 조작하는 행위를 방지하기 위해 필수적으로 사용됩니다. 가장 널리 쓰이는 방식은 HMAC (Hash-based Message Authentication Code)입니다.


🔐 핵심 원리: HMAC

대부분의 최신 REST API는 HMAC-SHA256 알고리즘을 사용하여 메시지를 인증합니다.

  1. 공유 비밀키 (Secret Key): API 제공자와 사용자가 사전에 나누어 가진 비밀번호입니다. (절대 노출 금지)
  2. 서명 생성 (Signing): 데이터 본문(Body)과 비밀키를 섞어 해시값을 생성합니다. 이를 Signature라고 합니다.
  3. 검증 (Verification): 수신 측에서도 동일한 데이터와 비밀키로 해시값을 만듭니다. 전송받은 Signature와 직접 만든 해시값이 일치하면 데이터가 변조되지 않은 것으로 간주합니다.
암호화와의 차이
  • 암호화 (Encryption): 내용을 남이 못 보게 숨기는 것 (기밀성).
  • 메시지 인증 (Authentication): 내용이 바뀌지 않았고, 보낸 사람이 맞는지 확인하는 것 (무결성).
  • API 요청 시 데이터는 평문(JSON)으로 보내더라도, 위변조 방지를 위해 서명(Signature)은 반드시 함께 보냅니다.

📝 실무 구현 예시 (Signature 생성)

메시지 인증값(Signature)을 생성하기 위해서는 정해진 순서대로 데이터를 연결(Concatenation)한 후 해시 함수를 적용해야 합니다. 각 API 별로 연결해야 하는 필드 순서가 다르니 주의하세요.

1. 서명 데이터 구성 규칙 (Signing String)

데이터 연결 시 각 항목 사이에는 파이프 기호(|)를 구분자로 사용합니다.

상점이 이지페이로 API를 요청할 때, requestBodymsgAuthValue 필드에 담아 보내야 하는 값입니다.

카테고리API 구분서명 데이터 구성 (Plain Text)
온라인 결제취소 (환불)pgCno + | + shopTransactionId
에스크로 상태변경pgCno + | + shopTransactionId
간편결제거래등록customerKey + | + shopTransactionId + | + payMethodDetailCode + | + easypayVirtualNo + | + amount
결제 취소pgCno + | + shopTransactionId
해외 결제알리페이 취소pgCno + | + shopTransactionId
위챗페이 취소pgCno + `

2. 코드 구현 예시 (Java)

위 규칙에 따라 만든 문자열(Plain Text)을 Secret Key를 이용해 HMAC-SHA256으로 암호화하고, 이를 Hex(16진수) 문자열로 변환합니다.

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

public class SignatureGenerator {

public static String generateSignature(String plainText, String secretKey) {
try {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256_HMAC.init(secret_key);

byte[] hashBytes = sha256_HMAC.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
return bytesToHex(hashBytes); // Hex String 변환
} catch (Exception e) {
throw new RuntimeException("Signature generation failed", e);
}
}

// 예시: 간편결제 거래등록 서명 생성
public static void main(String[] args) {
String signString = "cust_12345|ord_20240101|CARD|99999999|1000"; // customerKey + ... + amount
String mySecretKey = "sk_live_xxxxxxxxxxxx";

String signature = generateSignature(signString, mySecretKey);
System.out.println("Generated Signature: " + signature);
}
}

⚙️ 기술 비교: HMAC vs 전자서명

비즈니스 요건에 따라 사용하는 기술이 다릅니다.

구분HMAC (대칭키)전자서명 (공개키)
키 관리하나의 비밀키(Secret Key)를 양쪽이 공유개인키(Private)로 서명, 공개키(Public)로 검증
속도연산 속도가 매우 빠름복잡한 수학 연산으로 인해 상대적으로 느림
특징구현이 쉽고 API 인증에 표준으로 사용됨부인 방지(Non-repudiation) 가능 (보낸 사실 부인 불가)

💻 개발자 팁 (Security Checkpoints)

1. Null 처리 주의

서명 데이터 구성 시, 값이 없는(Null) 필드가 있다면 빈 문자열("")로 처리해야 합니다. null 문자열 자체가 포함되지 않도록 주의하세요.

예: pgCno + | + (빈값) + | + amount

2. 비밀키 관리 (Secret Key)

Secret Key는 절대로 프론트엔드 코드(HTML, JS, Android/iOS 앱 소스)에 포함해서는 안 됩니다. 서명 생성은 반드시 서버 사이드(Backend)에서 이루어져야 합니다.