일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 운영체제
- C
- design pattern
- mongoDB
- Proxy
- Heap
- 백준
- c언어
- Algorithm
- Data Structure
- 자바
- Spring
- 디자인 패턴
- IT
- 네트워크
- OS
- redis
- 알고리즘
- JPA
- MySQL
- spring webflux
- Java
- react
- 자료구조
- JavaScript
- MSA
- Kafka
- 파이썬
- Galera Cluster
- 컴퓨터구조
Archives
- Today
- Total
시냅스
Spring 예제로 보는 보안을 위한 HMAC 본문
HMAC, Hash-based Message Authentication Code
HMAC 은 메시지 인증 코드 (message authentication code) 를 생성하기 위한 알고리즘입니다.
송신자와 수신자만이 알고있는 secret key 값을 가지고 해싱하여 요청을 신뢰할 수 있는지 판단합니다.
checksum 의 아이디어에서 기인합니다.
- checksum
- 송신자는 데이터를 송신하면서 데이터의 일부분 혹은 전체의 합 또는 XOR 등의 연산으로 데이터와 함께 전송
- 수신자는 데이터를 받아 checksum 을 다시 계산하여 송신측에서 보낸 값과 일치하는지 확인한다.
- 다만 checksum은 오류 검출에만 사용되며 데이터의 정확성을 보장하지는 않는다.
다음과 같이 동작합니다.
- 송신할 메시지와 공유 비밀키를 함께 해싱합니다.
- 생성된 해시값과 메시지를 함께 전송합니다.
- 수신자는 요청으로 받은 메시지를 가지고 공유 비밀키와 함께 해싱합니다.
- 수신 받은 해시값과 수신자가 생성한 해시값이 동일한지 비교합니다.
- 해시값이 동일하다면 신뢰할 수 있는 것으로 판단합니다.
언제 사용할까?
서버 A 에서 서버 B 로 결제 요청을 보내는 상황을 가정하겠습니다.
만약 B 서버에서 제공하는 REST API 를 해커가 알아냈고,
요청을 보내며 authentication 이 jwt 밖에 없는 상황이고 jwt 또한 탈취 당했다면
다른 보안 절차가 없으므로 해커는 jwt와 함께 B 서버에 요청을 보내 이득을 취할 것입니다.
혹은 해커가 A 에서 B 로 보내는 결제 요청을 중간에 가로채
자신의 계좌로 변경하여 이득을 취할 수도 있을 것입니다.
그러므로 송수신자 간의 공유하고 있는 secret key 를 통해 해싱하는 방식으로
요청에 대한 변조, 신뢰성을 확인하여 보안을 강화할 수 있습니다.
이러한 방식은 대칭키 방식으로 분류할 수 있습니다.
대칭키방식은 대칭키가 탈취된다면 보안에 취약하다는 단점이 있습니다.
이를 보완하기 위해 비대칭키 방식을 사용하기도 합니다.
차후 비대칭키 방식 또한 살펴볼 수 있도록 하겠습니다.
예시
class Request {
String mac;
String message;
public Request(String mac, String message) {
this.mac = mac;
this.message = message;
}
public String getMac() {
return mac;
}
public String getMessage() {
return message;
}
}
- 데이터 송수신을 위한 예시 객체입니다.
@RestController
class HmacTestController {
// secret key
private static final String SECRET_KEY = "hmac";
// hash 알고리즘 규격
private static final String ALGORITHM = "HmacSHA256";
@PostMapping("/")
public String test(@RequestBody Request request) throws Throwable {
// key 생성
SecretKey secretKey = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), ALGORITHM);
// MAC 알고리즘 구현하는 MAC 객체
Mac hasher = Mac.getInstance(ALGORITHM);
// MAC 객체 init
hasher.init(secretKey);
// 데이터를 암호화
byte[] hash = hasher.doFinal(request.getMessage().getBytes());
// String 으로 변환
String hashed = HexUtils.toHexString(hash);
if (Objects.equals(hashed, request.getMac())) return "OK";
else return "false";
}
}
- message 와 mac 을 갖고 있는 request 객체가 요청으로 들어오면
- 서버에서는 요청을 토대로 위에서 설명한대로 진행합니다.
- 만약 요청이 신뢰할 수 있다면 OK 를 반환하고 아니라면 false를 반환합니다.
@SpringBootTest
class HamcApplicationTests {
private static final String SECRET_KEY = "hmac";
private static final String ALGORITHM = "HmacSHA256";
@Test
void 올바른_요청일시() throws Exception{
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
SecretKey secretKey = new SecretKeySpec(SECRET_KEY.getBytes(StandardCharsets.UTF_8), ALGORITHM);
Mac hasher = Mac.getInstance(ALGORITHM);
hasher.init(secretKey);
String message = "this is message";
byte[] hash = hasher.doFinal(message.getBytes());
String hashed = HexUtils.toHexString(hash);
HttpEntity<Request> requestHttpEntity = new HttpEntity<>(new Request(hashed, message), headers);
String url = "http://localhost:8080";
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, requestHttpEntity, String.class);
System.out.println(response.getBody());
}
}
- 이를 위해 restTemplate 로 요청을 보내어 확인합니다.
- 위의 예시는 올바른 요청일 때를 가정합니다.
- 원하는 OK sign이 떨어졌습니다.
- 실패하는 상황을 가정합니다.
- 위의 올바른 요청에서 message만 다른 것으로 바꿔 보냈습니다.
- hashing 할 때 쓴 message 와 httpentity 를 생성하며 만든 message가 다른 것으로 변조되었다는 것을 가정합니다.
- false 를 반환하며 우리가 기대했던 값임을 확인할 수 있습니다.
끝!
'Java, Spring' 카테고리의 다른 글
Java8 Parallel Stream 과 성능, 동시성 문제에 대해 (0) | 2023.03.25 |
---|---|
코드로 뜯어보는 System.out.println 대신 logger 를 사용해야 하는 이유 (0) | 2023.03.19 |
Java 코드 예시로 보는 CSRF 설명과 예방 (4) | 2023.03.09 |
JNI, Java의 Native Code 사용 설명 및 예제 (0) | 2023.03.05 |
Spring 과 Ulimit, Socket 자원 관리에 대해 (0) | 2023.03.05 |
Comments