JWT에 대해 사용해보게 되었는데 JWT에서 시그니처 부분을 암호화하기 위한 방식으로 HMAC 암호화를 사용하였습니다. 그래서 정의 및 예제코드를 작성하여 정리하였습니다.

HMAC이란
HMAC(Hash-based Message Authentication Code)은
메시지의 **무결성(Integrity)**과 **인증(Authentication)**을 보장하기 위한 암호화 방식

•무결성: 메시지가 중간에 변조되지 않았음을 확인
•인증: 메시지가 신뢰할 수 있는 주체로부터 왔음을 확인

동작원리
1. 비밀 키 (Secret Key)
2. 해시 알고리즘 (예: SHA-256)

이 두 가지를 조합하여 고정된 길이의 해시값(MAC)을 생성하여
수신자가 동일한 키로 다시 계산하여 데이터 변조 여부를 검증

검증 시 동일한 키를 사용하여야 되므로 대칭키 방식이며 해시 함수가 충돌을 방지하여 안정성이 확보됨.

코드예제
import javax.annotation.PostConstruct;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import lombok.Synchronized;
import org.apache.commons.codec.binary.Base64;

public class SecurityUtil {

    // 대칭 키: 실제 운영에서는 안전한 난수 값으로 대체해야 합니다.
    private static final String SYMMETRIC_KEY = "symmetericKey";

    private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256";
    private static Mac mac;

    /**
     * 클래스 초기화 시 HMAC 해시 객체를 한 번만 생성하고 초기화합니다.
     */
    @PostConstruct
    public void init() throws Exception {
        mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
        mac.init(new SecretKeySpec(SYMMETRIC_KEY.getBytes("utf-8"), HMAC_SHA256_ALGORITHM));
    }

    /**
     * 메시지를 HMAC-SHA256 방식으로 해싱하고 Base64로 인코딩합니다.
     * 동기화로 멀티스레드 환경에서도 안전하게 동작합니다.
     */
    @Synchronized
    public static String encodeHMacSha256(final String message) {
        byte[] hash = mac.doFinal(message.getBytes());
        return Base64.encodeBase64String(hash);
    }
}

•@PostConstruct는 Bean 생성 후 호출되어 Mac 객체를 한 번만 초기화
•Mac 객체는 스레드에 안전하지 않기 때문에 @Synchronized로 doFinal() 호출을 보호합니다.
•실제 운영 환경에서는 SYMMETRIC_KEY를 고정된 문자열이 아니라 안전하게 관리되는 키 저장소 또는 환경변수로부터 주입받는 것이 좋음

Syncronized 사용이유
Mac 객체는 내부 상태를 갖고 있어서 doFinal()이 호출되면 상태가 변경된다.
여러 스레드가 동시에 doFinal()을 호출할 경우 충돌이 발생하거나 예외가 발생할 수 있으므로, 반드시 동기화 처리가 필요.


참고사항
https://docs.oracle.com/javase/8/docs/api/javax/crypto/Mac.html

Mac (Java Platform SE 8 )

Finishes the MAC operation. A call to this method resets this Mac object to the state it was in when previously initialized via a call to init(Key) or init(Key, AlgorithmParameterSpec). That is, the object is reset and available to generate another MAC fro

docs.oracle.com

java 8버전 기준으로 doFinal 에 대한 설명을 보면 같은 키에 대해서는 여러번 재사용이 가능하다고 명시되어 있어 재사용 하였고, doFinal 사용 시 내부 상태가 변경되기 때문에 동기화 처리를 추가하였음.

+ Recent posts