개요
애플리케이션에서 데이터를 보호하고 무결성을 보장하기 위해 HMAC(Hash-based Message Authentication Code)를 활용할 수 있습니다. 본 글에서는 Spring Boot를 이용한 HMAC 기반의 전자서명 및 검증 API를 구현하는 방법을 설명합니다.
HMAC 이란?
HMAC은 키를 사용하여 데이터를 해싱하여 서명을 생성하는 방법입니다. HMAC을 사용하면 데이터가 변경되지 않았음을 검증할 수 있으며, 공유된 비밀 키를 통해 보안성을 유지할 수 있습니다.
HMAC-SHA256 알고리즘을 사용하여 JSON 데이터를 서명하고 검증하는 API를 구현합니다.
HMAC 서명 및 검증 API 구현
import org.springframework.web.bind.annotation.*;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api")
public class SecureSignatureController {
private static final String SECRET_KEY = "my-secret-key"; // 🔐 서버 내부에서만 관리
@GetMapping("/data")
public Map<String, String> getSignedData() throws Exception {
// 1. 응답 데이터
String responseData = "{\"username\": \"user123\", \"balance\": 100}";
// 2. HMAC SHA-256 서명 생성
String signature = generateHMAC(responseData, SECRET_KEY);
// 3. JSON 응답 반환
Map<String, String> response = new HashMap<>();
response.put("data", responseData);
response.put("signature", signature);
return response;
}
@PostMapping("/verify")
public Map<String, Object> verifyData(@RequestBody Map<String, String> requestData) throws Exception {
String receivedData = requestData.get("data");
String receivedSignature = requestData.get("signature");
// 서버에서 서명 다시 계산
String computedSignature = generateHMAC(receivedData, SECRET_KEY);
// 서명 검증 결과 반환
Map<String, Object> response = new HashMap<>();
response.put("valid", computedSignature.equals(receivedSignature));
return response;
}
private String generateHMAC(String data, String key) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "HmacSHA256");
mac.init(secretKeySpec);
byte[] hmacBytes = mac.doFinal(data.getBytes());
return Base64.getEncoder().encodeToString(hmacBytes);
}
}
클라이언트(JavaScript)에서 API 호출 및 검증
async function fetchData() {
// 서버에서 데이터 요청
const response = await fetch('http://localhost:8080/api/data');
const jsonResponse = await response.json();
console.log("서버 응답 데이터:", jsonResponse);
// 데이터를 서버로 다시 보내 검증 요청
const verifyResponse = await fetch('http://localhost:8080/api/verify', {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(jsonResponse)
});
const verifyResult = await verifyResponse.json();
if (verifyResult.valid) {
console.log("✅ 데이터 정상:", JSON.parse(jsonResponse.data));
} else {
console.error("⛔ 데이터 변조 감지!");
}
}
// 실행
fetchData();
동작 방식
- 클라이언트가 /api/data 엔드포인트를 호출하여 데이터를 요청합니다.
- 서버는 JSON 데이터를 생성하고, HMAC-SHA256을 사용하여 서명을 생성한 후 응답합니다.
- 클라이언트는 서버로부터 받은 데이터와 서명을 다시 /api/verify 엔드포인트에 보내어 검증합니다.
- 서버는 받은 데이터에 대해 서명을 다시 계산하고, 기존 서명과 비교하여 데이터 변조 여부를 판별합니다.
- 검증 결과를 클라이언트에 반환합니다.
'프로그래밍' 카테고리의 다른 글
높은 응집력과 느슨한 결합 (0) | 2024.10.29 |
---|---|
[mysql] 암복호화 방법 (0) | 2023.07.03 |