LabHub
배우기 러닝패스 코스

폐쇄망 현장 — 방산·국방 도메인 · 로그를 반출하기 전에 비식별하기 · 이론

지우면 분석이 죽는다 — 바꿔서 내보내는 기술

LabHub 에서 이어서 보기

한 줄 요약

로그를 밖으로 내보내야 하는데 그 안에 사람과 조직이 묻어 있다. 지우면 분석이 되지 않고 그냥 내보내면 반출이 되지 않는다. 그 사이에 있는 것이 결정적 가명화다 — 같은 값이 늘 같은 가명이 되어 상관 분석은 살아남고, 원본으로 되돌리는 열쇠는 안쪽에만 남는다.

왜 이게 필요했나

폐쇄망 현장에서 못 푸는 장애가 나면 결국 로그를 밖으로 보내게 된다. 본사 개발팀이든 제조사든, 그 코드를 아는 사람은 망 밖에 있기 때문이다. 그런데 운영 로그에는 사번, 계정, 내부 주소, 단말 식별자, 그리고 사람이 손으로 쓴 비고가 그대로 들어 있다. 반출 심사는 그것들을 근거로 반려한다.

첫 번째 반응은 대개 마스킹이다. 사번을 전부 별표로 바꾸고 주소를 잘라 낸다. 그러면 심사는 통과하는데 분석이 통과하지 못한다. 장애 분석에서 가장 자주 쓰는 사실은 "같은 사용자가 3분 사이에 같은 요청을 다섯 번 실패했다" 같은 것이고, 그 사실은 값 자체가 아니라 값이 같다는 관계에서 나온다. 전부 같은 별표로 만들면 다섯 줄은 서로 남남이 되고, 전부 다른 난수로 만들면 다섯 사람이 한 번씩 실패한 것처럼 보인다. 어느 쪽이든 원인은 찾을 수 없다.

그래서 필요한 것이 같은 값은 같게, 다른 값은 다르게, 그리고 되돌릴 수 없게 바꾸는 함수다. 이 세 조건을 한꺼번에 만족시키는 표준 도구가 열쇠 있는 해시, 곧 HMAC 이다. 구조는 [RFC 2104](https://www.rfc-editor.org/rfc/rfc2104) 가 정의하고 미국 연방표준은 [FIPS 198-1](https://csrc.nist.gov/pubs/fips/198-1/final) 로 같은 것을 고정해 두었다. 파이썬에서는 표준 라이브러리 [hmac](https://docs.python.org/3/library/hmac.html) 한 줄이면 된다.

어떻게 동작하나

첫째, 마스킹과 가명화를 가른다. 마스킹은 값을 없애는 것이고 가명화는 값을 바꾸는 것이다. 없애야 하는 것은 무엇이 들어 있는지 셀 수 없는 자리다. 사람이 자유롭게 쓴 비고 칸에는 전화번호도 이름도 들어갈 수 있고, 어떤 정규식을 짜도 다음 사람이 새로운 형태로 쓴다. 그런 칸은 통째로 지우는 편이 정직하다. 반대로 기계가 정해진 틀로 찍어 내는 필드는 무엇이 들어오는지 알 수 있으므로 가명화한다.

둘째, 가명은 열쇠에 매달아야 한다. 그냥 sha256(사번) 으로 만들면 안 된다. 사번은 형식이 좁아서 가능한 값이 몇만 개뿐이고, 받는 쪽에서 전부 해시해 표를 만들면 몇 초 만에 되돌아온다. 전화번호도 주민 구분자도 마찬가지다. 열쇠를 섞으면 열쇠를 모르는 사람은 그 표를 만들 수 없다. 열쇠는 자료와 함께 나가면 안 되고, 열쇠가 바뀌면 가명도 통째로 바뀌므로 언제 어떤 열쇠를 썼는지는 안쪽에 기록해 둔다.

셋째, 정규식이 놓치는 자리를 따로 센다. emp=E24-0101 처럼 이름표가 붙은 자리는 쉽다. 어려운 것은 세 가지다 — 로그 메시지 본문 안에 문장처럼 박힌 값, 자유 서술 칸에 사람이 적어 넣은 값, 그리고 base64 같은 인코딩 뒤에 숨은 값이다. 앞의 두 가지는 필드 단위 훑기로는 절대 나오지 않고, 세 번째는 어떤 정규식으로도 나오지 않는다. 먼저 디코딩한 다음에 찾아야 한다. 이 셋을 세어 보지 않고 "정규식으로 전부 처리했다" 고 말하는 순간 반출물이 샌다.

넷째, 지운 뒤에도 남는 위험을 본다. 직접 식별자를 전부 바꿔도 부서와 직급과 접속 시각을 함께 보면 한 사람으로 좁혀지는 행이 남는다. 이런 열을 준식별자라 하고, 같은 조합을 가진 행이 k개 미만인 상태를 위험으로 본다. 줄이는 방법은 지우는 것이 아니라 거칠게 만드는 것이다. 분 단위 시각을 시 단위로 버리면 같은 조합의 행이 뭉치면서 유일한 행 수가 줄어든다. 잃는 것은 정밀도이고 얻는 것은 반출 가능성이라, 이 둘의 교환을 숫자로 적어 두는 것이 이 단계의 산출물이다. 미국 표준기관의 탈식별 정리 문서 [NIST IR 8053](https://csrc.nist.gov/pubs/ir/8053/final) 과 [NIST SP 800-188](https://csrc.nist.gov/pubs/sp/800/188/final) 이 이 교환을 길게 다룬다.

다섯째, 매핑표는 반출물에 넣지 않는다. 가명을 원본으로 되돌리는 표는 조사에 꼭 필요하지만, 그것이 자료와 함께 나가면 가명화를 하지 않은 것과 같다. 표는 안쪽 금고에 남기고 밖으로는 가명만 내보낸다. 로그 관리 일반론은 [NIST SP 800-92](https://csrc.nist.gov/pubs/sp/800/92/final) 에 정리되어 있다.

현장에서 만나는 모습

한 번은 반출 심사를 두 번 반려당한 적이 있다. 첫 번째는 예상한 이유였다 — 사번이 그대로 있었다. 고쳐서 다시 냈더니 두 번째로 반려됐는데, 이유가 비고 칸이었다. 담당자가 "통화함" 뒤에 연락처를 적어 둔 줄이 한 줄 있었고, 그 줄은 우리가 만든 어떤 정규식에도 걸리지 않았다. 그 뒤로는 자유 서술 칸을 통째로 지우는 것을 원칙으로 삼았다. 분석에 정말 필요하면 사람이 다시 읽고 필요한 문장만 손으로 옮겨 적게 했다.

또 하나 기억에 남는 것은 인코딩이다. 인증 실패 로그에 토큰 조각이 base64 로 실려 있었는데, 디코딩해 보니 계정 주소였다. 반출물에서 계정 문자열을 찾는 검사는 전부 통과했다. 찾는 쪽이 원문으로만 찾았기 때문이다. 자기 검증을 만들 때 "원본에 있던 값이 반출물에 없는가" 만 보지 말고 "인코딩된 형태로도 없는가" 를 함께 보아야 하는 이유다.

다음 실습에서 할 것

접속 로그 96줄과 앱 로그 16줄, 그리고 18명 명부를 만들어 어떤 필드가 직접 식별자이고 어떤 것이 준식별자인지 가릅니다. 정규식으로 찾은 값과 놓친 값을 따로 세고, 열쇠에 매인 결정적 가명 함수를 구현해 같은 값이 같은 가명이 되는지, 열쇠를 바꾸면 달라지는지를 시험으로 보입니다. 그 다음 가명화와 마스킹을 갈라 적용하고, 준식별자 조합으로 유일해지는 행을 세어 일반화로 줄인 뒤, 반출 꾸러미를 기계로 자기 검증해 내보냅니다.