BACK/Spring
Hmac를 사용하여 url 암호화 구현해 보기
dazz6
2024. 11. 25. 18:00
링크를 공유할 때 단순히 링크를 공유하게 되면 보안에 문제*가 있다고 하여, Hmac을 사용해 url 암호화를 구현해 보았다.
* 링크를 단순히 공유할 경우의 보안 문제
1. 링크 탈취 가능성
-> 예를 들어, 사용자 아이디나 세션 정보가 포함된 url이 노출될 경우 악용하여 다른 사용자의 데이터를 조작할 수 있음
2. Replay 공격
-> 링크를 통해 인증 등의 작업이 수행될 경우, 동일한 링크를 재사용하여 원치않는 작업을 반복 실행할 수 있음
3. URL 변조
-> 파라미터를 조작하여 허가되지 않은 데이터를 요청할 수 있음
HMAC은 key와 message를 조합해서 고정된 크기의 해시 값을 생성하는 방식으로, 데이터의 무결성을 확인하고 인증을 보장하기 위해 사용된다.
@Value("${komawatsir-pwd}")
private String secretKey;
// 보안을 위해 application.properties에 key를 입력해 두고 주입해 주는 방식을 사용
private static String SECRET_KEY = "";
@PostConstruct
public void init() {
SECRET_KEY = this.secretKey;
}
// application.properties에 저장된 값을 불러옴과 동시에
// key를 static으로 지정하면서, @PostConstruct annotation을 사용하여 실행될 때 key 값을 주입
/* 암호화하기 */
public String getUrl(Integer userId) {
try {
SecretKeySpec secretKey = new SecretKeySpec(SECRET_KEY.getBytes(), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(secretKey);
byte[] hmacBytes = mac.doFinal(String.valueOf(userId).getBytes());
return Base64.getUrlEncoder().withoutPadding().encodeToString(hmacBytes);
} catch (Exception e) {
System.out.println("getUrl ERROR : " + e.getMessage());
return null;
}
}
/* 검증하기 */
public Boolean validateUrl(Integer userId, String url) {
String userIdHmac = getUrl(userId);
/*
equals 메소드는 문자열 길이에 따라 수행 시간이 달라질 수 있으므로 타이밍 공격(실행 시간 차이로 비밀 키 추측)에 취약.
타임 인디펜던트 비교(입력 데이터의 길이와 내용에 관계없이 일정한 실행 시간을 유지하여 비교)를 구현함 (아래 코드)
*/
if (userIdHmac == null || url == null || userIdHmac.length() != url.length()) {
return false;
}
int result = 0;
for (int i = 0; i < userIdHmac.length(); i++) {
result |= userIdHmac.charAt(i) ^ url.charAt(i);
}
return result == 0;
}