전임자에게 인수인계를 받은 페이지에 신규 요구사항을 개발하려고 하다가 코드 한 줄을우연히 찾게 되었습니다.
잘못 본건가 싶었습니다.
설마 하는 마음으로 브라우저 개발자 도구를 확인해 봤는데, 아주 잘 보이더군요.
$.ajax({
url: 'https://some-api.com/items/recommendations',
data: JSON.stringify(data),
beforeSend: function(xhr){xhr.setRequestHeader('x-api-key', 'k8nSt...')},
...
})
곧바로 키를 폐기하고 서버로 로직을 이관하는 핫픽스를 진행했습니다.
이후 사용 기록을 보니 남용된 것으로 의심가는 흔적은 없었지만, 오래된 JSP 페이지에 노출되고 있던 터라 정확한 유출여부는 확인하기 어려웠습니다.
이번에는 운이 좋아 발견할 수 있었지만, 다른 페이지에도 같은 문제가 있을 수 있어 관련 레포지토리를 빠르게 전수조사하기로 했습니다.
숨어있는 API Key, 어떻게 찾아내지?
API Key는 공격자가 유추하는 것을 방지하기 위해 대체로 길고 다양한 문자가 불규칙하게 섞여 있습니다.

문자열이 얼마나 불규칙한지는 Shannon 엔트로피를 통해 수치화할 수 있는데요.
예를 들어 아래 두 문자열의 엔트로피를 계산해 보면, 첫 번째 문자열의 값이 더 높게 측정됩니다.
### Shannon 엔트로피 값 비교
1. A0D28bba7b1287ff432d0b : 3.5161 # 불규칙하게 섞인 문자열
2. aaaaaaabbbbbbbbccccccc : 1.5820 # 소문자 3개를 반복해서 사용
첫 번째 문자열은 두 번째 문자열보다 사용된 문자의 종류가 많고, 각 문자의 출현 빈도도 상대적으로 분산되어 있기 때문입니다.
하지만 Shannon 엔트로피 값이 높다고 무조건 API Key라고 단정지을 수는 없습니다.
이를테면 UUID도 상당히 높은 엔트로피를 가지고 있습니다.
c1b100db-f254-493f-8b53-f0fcab2437d0: 3.7391
따라서 엔트로피 값 만으로 API Key 여부를 판별하기는 어렵습니다. 하지만 의심이 가는 문자열 후보를 좁혀주는데에는 충분히 활용될 수 있을 것 같습니다.
간단한 점검을 위해 소스코드 내 문자열들의 엔트로피 값을 계산하여 보고서 형태로 출력해 주는 스크립트를 만들었습니다. 10개의 레포지토리에서 의심이 가는 문자열을 100개정도 추출했고, 외부에 노출되어있는 Key를 1개 더 발견하여 조치할 수 있었습니다.
================= 탐지된 문자열 목록 예시 ================
EXAMPLE-KEY-8bba7b1287ff432d0b7777532f52fd59ef75cc56d3818b8ed5a8d06 : 4.3197
5b8621ee0cf2475f66709a5d : 3.7721
eventEntry1Remark : 3.4548
1842692849310691 : 2.9056
P2018043031858 : 2.8424
...
검사 절차를 도입하자
이번에 만든 스크립트는 관련 레포지토리를 빠르게 전수조사하기 위한 임시성 도구였습니다.
당시에 마침 SonarQube를 활용한 정적분석 체계 도입을 검토하고 있었고, SonarQube에도 Secret 검사 기능이 있었습니다. 따라서 스크립트를 별도로 운영하기보다 기존 빌드 흐름에 해당 검사 절차를 포함시키기로 했습니다.
빌드 과정에서 소스에 대한 정적 분석을 수행하고, 내부 기준을 넘는 이슈가 발견되면 Quality Gate와 빌드가 실패하도록 구성했습니다. 앞으로 같은 유형의 문제가 발생하면 운영 환경에 반영되기 전에 발견하고 조치하는 데에 도움이 될 테죠.

회고
처음 API Key를 발견했을 때는 당장 눈앞의 문제를 없애는 것만 생각했습니다. 하지만 같은 문제가 재발하지 않도록 새로운 검사 절차를 정착시키는 것은 별개의 문제였습니다.
엔터프라이즈급 환경에서 안정적으로 오랜 기간 운영이 가능할지 검토하고, 새로운 절차의 필요성에 대해 팀원들을 설득하는 등 신경써야 할 부분이 많았습니다.특히 SonarQube는 모두에게 생소한 도구였기 때문에 바뀐 배포 흐름과 Quality Gate 적용값을 상세히 설명했습니다. 장애 상황에서 필요한 재기동 절차까지 문서로 남겨, 팀 내 지식으로 정착시키는 데에 초점을 두었습니다.
당장 잘 동작하면 된 것 아닌가 싶을 수도 있지만, 도입한 당사자가 없어도 구축된 시스템은 오랜 기간 잘 돌아가야 하니까요. 회사 입장에서 유지보수가 불가능한 시스템은 운영 리스크가 됩니다. 무언가를 새롭게 만들거나 도입하는 일에는 그에 대한 책임도 따라오는 것 같습니다.
긴 글 읽어주셔서 감사합니다.