HMAC : Hash-based Message Authentication Code
해쉬 기반 메시지 신원확인 코드
클라이언트 👉 API 서버에 보내는 "요청자의 신원과 메시지의 무결성을 검증하기 위한 해쉬 문자열"
HMAC 만드는 방법
- HMAC는 인증을 위한 Secret Key와 임의의 길이를 가진 Message를 해시함수를 이용해서 생성
- 해시함수로 MD5, SHA-256등 일반적인 함수 사용가능
- 각 알고리즘에 따라 다른 고정 길이의 MAC(=해시문자열 = 코드)이 생성된다
만약 중간에 해커가 코드를 가로채서 동일한 요청을 계속 보낸다면 (Reply attack), 이를 방지하기 위해서 MAC을 생성할 때 timestamp를 추가해서 사용하는 방법이 있다
API 서버는 해당 메시지가 생성된 시간을 알 수 있고, 생성된 시간부터 일정 시간 이내의 호출만 정상적인 호출로 인식 가능
serial, nonce 등 다른 값들도 룰에 따라 추가 가능
HMAC 생성과 API 통신에서 사용방법
1. (Client) 해시 생성
- 클라이언트는 SHA-256(SecretKey, Message) = MAC 생성
2. 데이터 전송
- 생성된 MAC + Message 를 API 서버에 전송, MAC은 HTTP Header 또는 쿼리로 (URL)에 포함된다
3. (Server) 해시 생성
- API 서버는 클라이언트로부터 전달받은 Message 와 가지고 있던 SecretKey를 이용해 SHA-256(SecretKey, Message) = MAC 생성
4. 해시 비교
- API 서버에서 생성된 MAC과 클라이언트로부터 전달받은 MAC의 값이 같은지 비교 👉 무결성판단
구현 복잡도
Client_id & Client_secret < HMAC < PKI
예시
- AWS S3 REST API 기준 HMAC 서명 생성과검증
- 서명을 생성하는데 필요한 것은 API 서버가 정의한 룰 + 요청 자체에 담긴 여러 데이터(Message) + SecretKey 이다
- 다양한 룰이 있는데, DomainTools의 경우 Client_id + timestamp + request_uri 조합한 문자열 + client_secret을 이용한 HMAC 생성
- 서버도 동일한 방법으로 HMAC을 생성하여 클라이언트로 부터 받은 코드가 유효한지 검사
- AWS S3 REST API 기준 인증방법
- S3 REST API는 서버와 클라이언트 만이 공유하는 SecretKey를 사용하여 생성된 서명(HMAC)으로 매번 클라이언트로부터의 요청이 올바른지 매번 인증한다
- 서버 - 클라이언트 사이의 요청 - 응답 메시지에 대한 보안은 HTTPS 프로토콜을 사용하는 것으로 자연스럽게 수행된다
- 서명(Signature)은 단지 클라이언트가 진짜인지, 가짜인지 증명하는 역할만 수행
- HMAC 생성을 위한 해쉬함수로는 SHA256이 사용된다
- 생성된 Signature가 포함된 요청의 유효시간은 15분이다. 15분이 경과하면 유효하지 않은 요청으로 간주한다. timestamp의 포맷은 ISO8601에 타임존을 추가하여 정의한다
- [코드예시-JAVA]
String sharedSecret = "5pKRnC5MGNuqEdKkzYy4MA";
String algorithm = "HmacSHA256";
String message = "2017-11-07T18:00:00+09:00 GET http://jsonobject.com/posts/2017";
// HMAC 생성기 초기화, 공유키, 알고리즘, 원본 메시지 지정
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(sharedSecret.getBytes(), algorithm));
// Signature 바이트 배열 생성
byte[] signatureBytes = mac.doFinal(message.getBytes()));
// 생성된 Signature를 Base64 문자열로 변환, UMuelgDclhzNZPiNqF6NYkZtJnOFqlgu4i4t+4M1fJs=
String signature = Base64.getEncoder().encodeToString(signatureBytes);
- [코드예시 - Binance API]
Request Body에 담아서 전송할 경우
앞에 여러가지 key-value 쌍들은 특정 API 메소드에 필요한 params 값들 + SecretKey -> SHA512로 암호화 -> 나온 결과값이 HMAC => 서명
$ echo -n "symbol=LTCBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000×tamp=1499827319559" | openssl dgst -sha256 -hmac "NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j"
(stdin)= c8db56825ae71d6d79447849e617115f4a920fa2acdcab2b053c4b2838bd6b71
API 요청 메시지 (필요한 params = message + HMAC 서명)
(HMAC SHA256)
$ curl -H "X-MBX-APIKEY: vmPUZE6mv9SD5VNHk4HlWFsOr6aKE2zvsw0MuIgwCIPy6utIco14y7Ju91duEh8A" -X POST 'https://api.binance.com/api/v3/order' -d 'symbol=LTCBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000×tamp=1499827319559&signature=c8db56825ae71d6d79447849e617115f4a920fa2acdcab2b053c4b2838bd6b71'
'programming > Web' 카테고리의 다른 글
[Express] Post로 JSON 데이터 보내기 (미들웨어 설정) (0) | 2022.08.20 |
---|---|
Restfull 웹 API 디자인(1) (0) | 2022.08.20 |
AWS - EC2(EBS/AZ/ELB) (0) | 2022.04.06 |
[AWS] IAM 이란? (개념과 실습) (0) | 2022.04.05 |
API, SDK, Library, Framework (0) | 2022.03.10 |