붙여넣기 전에 비밀을 마스킹하세요

비밀을 마스킹한다는 것은 텍스트가 공유되기 전에 그 안의 자격 증명 — API 키, 토큰, 비밀번호, 개인 키 — 을 표식으로 교체하여 정보가 액세스 없이 이동할 수 있게 하는 것입니다. 비밀이 새는 가장 흔한 방법이 공격이 아니라 붙여넣기이기 때문에 중요합니다: 지원 티켓으로의 로그, 채팅으로의 설정 파일, 포럼 글로의 디버그 명령. 이 글은 그런 붙여넣기가 왜 되돌리기 어려운지, 시크릿 마스킹 도구 같은 스캐너가 무엇을 잡을 수 있고 무엇을 잡을 수 없는지, 그리고 도움이 되는 붙여넣기가 사고가 되지 않게 하는 흐름 — 로컬에서 마스킹하고, 마스킹된 복사본을 공유하고, 이미 빠져나간 것은 모두 교체하는 — 을 설명합니다.

왜 비밀은 티켓, 채팅, 로그에 있게 되는가

아무도 비밀을 일부러 붙여넣지 않습니다. 붙여넣는 것은 비밀 주변의 것입니다: 마침 요청 헤더를 포함하는 오류 로그, 마침 세 섹션 아래에 데이터베이스 비밀번호를 품은 설정 파일, 토큰이 Authorization 헤더 안에 앉아 있는 터미널에서 복사한 curl 명령. 문제 해결은 맥락으로 돌아가고, 자격 증명은 맥락 안에 삽니다 — 그래서 지원 데스크, 채팅 채널, 이슈 트래커는 오류 메시지를 보느라 그 위의 헤더를 보지 못한, 서두르는 조심스러운 사람들이 쓴 살아 있는 키, 세션 토큰, 개인 키를 조용히 쌓아갑니다.

그런 다음 받는 시스템은 그 붙여넣기를 보낸 사람이 결코 보지 못하는 방식으로 영구화합니다. 티켓은 검색을 위해 색인되고, 공급업체로 전달되고, 보고서로 내보내어지며 수년간 보관됩니다. 채팅 메시지는 알림으로 전화에 푸시되고, 스레드에서 인용되고, 봇이 요약합니다. 로그는 자체 보존 기간과 자체 액세스 목록을 가진 수집기로 보내집니다. 그런 시스템 안의 비밀은 한 곳에 있지 않습니다 — 시스템이 만든 모든 복사본, 백업, 미리보기, 알림 안에 있으며, 그 대부분은 보낸 사람이 열거할 수도, 삭제할 수도 없습니다. 붙여넣는 데 1초, 되돌릴 확실한 방법 없음이라는 이 비대칭이, 마스킹이 붙여넣기 후의 정리가 아니라 붙여넣기 전에, 보낸 사람의 기계에서 일어나야 하는 이유의 전부입니다.

스캐너가 잡을 수 있는 것: 형태, 체크섬, 구조

좋은 소식은 실제 자격 증명은 고도로 패턴화되어 있고, 패턴 스캔은 결정적이라는 것입니다: 같은 텍스트는 항상 같은 발견을 만들며, 그 사이에 모델의 추측은 끼지 않습니다. 공급자 키는 공개된 형태 — 접두사, 고정 길이, 제한된 문자 집합 — 를 지니므로, AWS 액세스 키, GitHub 토큰, Stripe 키, Slack 토큰은 단락 속의 전화번호를 사람이 알아보는 것처럼 한눈에 인식할 수 있습니다. 개인 키는 BEGIN 과 END 장갑 줄로 스스로를 알리고, JSON Web Token은 단단한 세 세그먼트 구조를 가지며, 처음 두 세그먼트는 항상 같은 방식으로 시작합니다. 항상 같은 종류의 JSON을 인코딩하기 때문입니다.

두 가지 검사가 패턴 층을 정직하게 유지합니다. 카드 번호는 모든 진짜 카드 번호에 내장된 산술 검사인 Luhn 체크섬을 통과할 때만 표시되며, 진짜 카드와 그저 닮았을 뿐인 훨씬 더 큰 긴 숫자 집단 — 주문, 송장, 타임스탬프 — 을 분리합니다. 그리고 형태가 겹치는 곳에서는 구체적인 패턴이 일반적인 패턴을 이기므로, 변수에 할당된 알려진 공급자 키는 실제 유형 아래에서, 올바른 교체 지침을 붙여, 한 번만 보고됩니다. 아래 첫 번째 출처인 GitHub 자체의 비밀 스캔은 플랫폼 규모에서 같은 원리로 동작합니다: 파트너가 토큰 형식을 공개하고, 플랫폼이 정확히 대조합니다. 로컬 스캐너는 같은 발상을, 그것이 아직 도움이 될 수 있는 마지막 순간에 실행한 것입니다 — 보내기를 누르기 전의 브라우저입니다.

스캐너가 잡을 수 없는 것: 엔트로피와 맥락

공급자 형태 너머에서는 탐지가 확률적이 됩니다. 일반 규칙은 할당 — password나 api_key 같은 이름과 값의 나란함 — 을 찾고, 섀넌 엔트로피로 측정하여 값이 무작위해 보이도록 요구할 수 있습니다. 이는 변수에 할당된 생성 키를 잡고 문장 속의 password 라는 단어를 무시하지만, 그 경계는 숫자의 옷을 입은 판단입니다: 강한 사람의 비밀번호와 약한 기계 키는 같은 척도 위에 살고, 문구로 철자된 실제 비밀은 낮게 점수 매겨지며, 자리 표시자 문구가 없는 무작위처럼 보이는 빌드 해시는 높게 점수 매겨집니다. 엔트로피는 문자열이 놀랍다는 것을 알려줄 수는 있어도, 그 문자열이 자격 증명이라는 것은 알려줄 수 없습니다.

맥락은 더 큰 사각지대입니다. 값을 위험하게 만드는 것의 대부분은 값 밖에 있기 때문입니다. 세션 쿠키는 어떤 서비스를 여는지 알기 전까지는 그저 문자와 숫자입니다. 데이터베이스 비밀번호는 세 개의 환경 변수에 나뉜 연결 문자열 안에서는 무해해 보이고, 일회용 코드는 10분 동안만 민감합니다. 스캐너는 구조를 통해서도 보지 못합니다: 두 줄의 로그에 걸쳐 줄바꿈된 비밀, blob 안에 base64로 인코딩된 비밀, 이미지로 촬영된 비밀은 텍스트 패턴이 아무리 좋아도 보이지 않습니다. 정직한 요약은 스캐너가 문서화되고 형태가 좋은 대다수를 신뢰성 있게 잡는다는 것 — 그리고 적중을 그 자리에서 강조하여 보여주는 미리보기는 여전히 사용자 자신의 10초 훑어보기에 값한다는 것입니다. 사용자의 눈은 패턴이 알 수 없는 맥락을 알기 때문입니다.

스캐너가 의도적으로 보지 못하는 또 하나의 부류가 있으며, 그것은 함정 바로 옆에 있습니다: 자리 표시자입니다. example, test, dummy, your- 같은 단어를 포함하는 문서 값은 매뉴얼과 튜토리얼이 발견 표를 밝히지 않도록 제외됩니다. 그러나 모든 제외는 문입니다: 마침 그 단어 중 하나를 포함하는 실제 키, 또는 자리 표시자처럼 보이는 값으로 설정된 게으른 실제 비밀번호는 조용히 통과합니다. 제외 목록을 소음 제어로 취급하고, 결코 보장으로 취급하지 말며, 스캐너를 침묵시키기 위해 실제 자격 증명에 자리 표시자 문구를 표시하지 마세요.

정식 가짜 예시 문제

모든 공급자는 예시 자격 증명을 공개하는데, 가장 유명한 것 — AKIAIOSFODNN7EXAMPLE를 중심으로 만들어진 AWS 문서 쌍 — 은 실제 키와 정확히 같은 형태를 가집니다. 실제처럼 보이지 않는 예시는 아무것도 가르치지 못하기 때문입니다. 그래서 스캐너는 좋은 기본값이 없는 갈림길에 직면합니다. 정식 예시를 표시하면 모든 튜토리얼, 교과서, 교육 로그가 오경보가 되어 독자가 발견을 반사적으로 무시하도록 가르칩니다 — 경보 피로는 그 자체로 취약점입니다. 허용 목록에 넣으면, 어떤 스캐너도 결코 보고하지 않을 문자열 목록을 공개한 셈이 되어, 은신처를 찾는 이에게 초대장이 됩니다: 실제 키가 예시와 같을 수는 없지만, 실제 키를 둘러싼 메모, 파일 이름, 포장지는 예시의 위장을 빌릴 수 있습니다.

시크릿 마스킹 도구가 취하는 실용적인 답은 형태를 표시하고 발견 표가 대화를 시작하게 두는 것입니다. 정식 예시는 키 자체 안에 example이라는 단어를 포함하지만, 그래도 AWS 키로 표시됩니다. 공급자 형태의 문자열은 매번 사람의 한 번 보기에 값하기 때문입니다 — 그 보기는 싸고, 대안은 같은 형태의 모든 것에 대한 조용한 자유 통행입니다. 문서를 쓸 때는 독자의 스캐너와 자신의 스캐너도 도우세요: 명백히 합성인 값을 사용하고, 주변 할당에서 자리 표시자 문구로 표시하며, 실제 키를 문서에 붙여넣고 몇 문자를 편집하는 일은 결코 하지 마세요 — 부분적으로 편집된 실제 키는 추가 단계를 거친 자격 증명 유출이며, 스캐너도 그것을 진짜와 구별할 수 없습니다.

삭제만 하지 말고 교체하세요 — 그리고 안전하게 공유하세요

실제 비밀이 이미 마스킹 없이 붙여넣어졌다면, 작업 순서는 중요하고 삭제는 마지막에 오며, 아예 오지 않을 수도 있습니다. 그 값이 — 색인, 알림, 스크린샷, 동료의 인용으로 — 복사되었을 것으로 가정하고 공개된 것으로 취급하세요: 먼저 공급자에게 가서 자격 증명을 교체하고 예전 것을 폐기하여, 유출된 문자열이 어디에 살아남아 있든 작동을 멈추게 하세요. 그 후에야 원래 메시지를 삭제하거나 편집하는데, 이는 수리가 아니라 위생으로서입니다. 아래에 나열된 OWASP 비밀 관리 지침과 gitleaks 프로젝트는 이 교훈의 두 절반을 위해 존재합니다: 비밀을 수명이 짧고 범위가 제한되도록 관리하는 것과, 붙여넣기가 이미 일어났다는 가정으로 저장소와 기록을 스캔하는 것입니다. 브라우저 캡처에 대한 동반 문제는 그 HAR 파일을 보내기 전에에서 다룹니다.

안전한 공유 흐름은 습관이 될 만큼 짧습니다. 첫째, 원본을 결코 업로드하지 않는 도구로 로컬에서 마스킹하세요 — 스캔은 사용자의 기기에 속합니다. 원시 텍스트를 원격 마스킹 서비스로 보내는 것은 막으려는 바로 그 행위 안에서 유출을 반복하는 것이기 때문입니다. 둘째, 마스킹된 복사본을 티켓이나 채팅에서 공유하세요. 거기에는 문제 해결자가 필요로 하는 모든 것 — 엔드포인트, 타이밍, 오류 형태 — 이 액세스를 제외하고 들어 있습니다. 셋째, 상대방이 정말로 자격 증명 자체를 필요로 할 때는 시크릿 관리자나 만료되고 한 번만 볼 수 있는 공유 링크를 통해, 토론과는 별도의 채널로 보내고, 누구도 다시 붙여넣지 않도록 티켓에 그렇게 적어 두세요. 이 세 단계를 받아들인 팀은 경계심에 대한 의존을 멈추고 — 경계심은 결국 항상 실패하는 유일한 통제입니다 — 루틴에 의존하기 시작합니다. 그리고 루틴이야말로 지친 금요일의 붙여넣기에서도 조심스러운 월요일의 붙여넣기만큼이나 확실하게 비밀을 티켓 밖에 머물게 하는 것입니다.

출처와 더 읽을거리

자주 묻는 질문

실제 비밀을 이미 티켓에 붙여넣었습니다. 무엇을 먼저 해야 하나요?

교체가 먼저, 삭제는 그다음입니다. 공급자에게 가서 대체 자격 증명을 발급하고 유출된 것을 폐기하세요. 티켓은 이미 색인되고, 알림이 갔으며, 열거할 수 없는 방식으로 전달되었을 수 있기 때문입니다. 나중에 메시지를 삭제하거나 편집하는 것은 좋은 위생이지만 수리는 아닙니다 — 수리는 유출된 값의 작동을 멈추는 것입니다.

마스킹된 복사본이 텍스트를 완전히 안전하게 공유할 수 있게 하나요?

더 안전하지만, 안전하지는 않습니다. 마스킹은 자격 증명으로 작동하는 값을 제거하지만, 텍스트는 여전히 호스트 이름, 엔드포인트, 내부 이름, 마스킹하지 않기로 한 고객 이메일 주소, 그리고 시스템의 형태를 보여줍니다. 마스킹된 복사본은 일이 이미 사용하는 채널로 공유하고, 공개 게시물에는 두지 말며, 강조된 미리보기를 직접 훑어보세요 — 스캐너는 패턴을 알지만, 사용자는 맥락을 압니다.

AWS 예시 키는 가짜인데 스캐너는 왜 표시하나요?

실제 키와 정확히 같은 형태이기 때문입니다 — 그것이 좋은 예시가 되는 이유입니다. 문서 형태의 문자열을 모두 조용히 통과시키는 스캐너는 실제 자격 증명에 공개된 은신처를 건네는 셈입니다. 표시하는 비용은 발견 표를 한 번 보는 것입니다. 자리 표시자 제외는 이미 일반 할당에서 샘플로 표시된 값을 침묵시키고 있는데, 거기서는 형태가 아니라 문구가 그것들을 드러냅니다.