测验:接收 Webhook
한국어 원문으로 표시합니다.
웹훅 서명을 검증할 때 본문을 JSON 으로 파싱한 뒤 다시 직렬화해 HMAC 을 계산했다. 무슨 일이 생기는가?
- 키 순서나 공백이 한 글자만 달라도 전혀 다른 서명이 되어 정상 배달이 거절된다
- 파싱 비용이 늘어 응답이 느려지고 상대의 타임아웃에 걸린다
- 본문에 한글이 있을 때만 서명이 어긋나고 영문만 있으면 문제가 없다
- 서명은 같게 나오지만 타임스탬프가 재계산되어 시각 창에서 걸린다
서명 비교를 got == want 로 했다. 이것이 왜 문제인가?
- 문자열 비교는 유니코드 정규화를 하므로 서로 다른 서명이 같다고 판정될 수 있다
- 비교가 첫 번째 다른 바이트에서 끝나므로, 걸린 시간이 '앞의 몇 글자가 맞았는지' 를 흘린다
- 길이가 다른 문자열을 비교하면 예외가 나서 검증이 통째로 실패한다
- 해시값은 대소문자가 섞여 있어 == 비교로는 절대 참이 될 수 없다
서명이 유효한 3시간 전 요청을 그대로 다시 보내는 공격을 막는 것은?
- 배달 번호를 기본키로 둔 중복 제거 표. 같은 배달은 두 번 적용되지 않는다
- 상대에게 재시도 횟수를 줄여 달라고 요청하는 운영 규칙
- 서명 재료에 들어 있는 타임스탬프와 지금 시각의 차이를 보는 시각 창
- 본문에 들어 있는 이벤트의 version 을 지금 저장된 값과 견주는 판 비교
중복 제거를 배달 번호(delivery id) 하나로만 했다. 어떤 중복을 놓치는가?
- 같은 배달 번호로 다시 오는 재전송. 배달 번호는 전송마다 새로 붙기 때문이다
- 서명이 틀린 가짜 배달. 중복 제거 표가 서명까지 보지는 않기 때문이다
- 시각 창 밖에서 들어온 오래된 배달. 배달 번호만으로는 시각을 알 수 없기 때문이다
- 배달 번호는 새것인데 이벤트 번호가 같은 배달. 같은 사건이 새 전송으로 다시 온 경우다
한 주문에 대해 shipped(version 3) 가 먼저 도착하고 paid(version 2) 가 나중에 도착했다. 올바른 처리는?
- 도착 순서가 곧 사건 순서이므로 paid 로 갱신한다. 상대가 순서를 지켜 보냈다고 보아야 한다
- 저장된 version 3 보다 작으므로 적용하지 않고 버린다. 상태는 shipped 로 남는다
- 두 이벤트를 모두 적용하되 마지막에 다시 shipped 를 적용해 순서를 되돌린다
- 순서가 깨진 것이므로 상대에게 400 을 돌려주어 다시 보내게 한다
받는 자리에서 원장 적용까지 끝낸 뒤 200 을 주도록 만들었다. 부하가 오를 때 무슨 일이 생기는가?
- 응답이 느려져 상대의 타임아웃에 걸리고, 상대가 재전송하면서 중복과 부하가 함께 는다
- 상대가 순서를 지켜 보내게 되어 판 비교가 필요 없어진다
- 서명 검증이 뒤로 밀려 가짜 이벤트가 큐에 먼저 들어간다
- 큐가 없으므로 중복 제거 표가 필요 없어지고 원장이 단순해진다