LabHub
学习 学习路径 课程

银行现场的语言

抹去日志中的个人信息,仍能追查事件

在 LabHub 中继续学习

한국어 원문으로 표시합니다.

목표

이체 API 로그에서 개인정보 후보를 찾아 검사숫자로 오탐을 걸러 내고, 마스킹과 결정적 가명 토큰으로 반출본을 만든다. 그러고도 사고 고객의 사건을 토큰만으로 추적하고, 두 번 돌려도 같은 결과가 나오며 남은 누출이 없음을 증명한다.

왜 중요한가

장애 조사에 쓰는 로그에는 자유 문장이 섞여 있고 그 안에 계좌번호와 카드번호가 그대로 적혀 있다. 그대로 넘길 수는 없지만, 전부 별표로 덮으면 "같은 계좌에서 세 번 실패했다" 는 사실까지 사라진다. 정규식은 모양만 보므로 16자리 정산 일련번호까지 카드로 오해한다. 검사숫자를 한 번 더 걸면 오탐이 열 배 줄고, 조사에 필요한 식별자를 죽이지 않는다. 가린 값에 HMAC 결정적 토큰을 달면 같은 계좌는 언제나 같은 토큰이 되어 이어 볼 수 있고, 키가 없으면 되돌릴 수 없다. 스크러빙 파이프라인은 재시도되므로 두 번 돌려도 결과가 같아야 한다.

단계

  1. /root/mask/gen_logs.py 를 만들어 실행해 /root/mask/app.log(JSON Lines 500줄 이상)와 /root/mask/customers.csv(고객 30명 이상)를 만든다. 계좌 30개 이상, 검사숫자를 통과하는 카드 40개 이상, 통과하지 못하는 16자리 수 20개 이상을 섞고, 가장 많이 나오는 계좌 하나가 2위보다 3줄 이상 많게 한다.
  2. /root/mask/find_candidates.py 로 네 종류의 후보를 모두 찾아 /root/mask/candidates.json 에 적는다(total·by_kind·items).
  3. /root/mask/luhn.py 를 만들고(유효하면 종료 코드 0), 카드 후보를 /root/mask/candidates_luhn.json 의 card_verified·not_card 로 가른다.
  4. /root/mask/scrub.py/root/mask/app.scrubbed.log 를 만든다. 계좌·카드·전화·이메일을 아래 참고의 규칙대로 가리고, 카드가 아닌 16자리 수는 그대로 둔다.
  5. /root/mask/keys/scrub.key 를 만들고 scrub.py 가 각 줄에 tokens(acct·card)를 붙이게 한 뒤 /root/mask/app.scrubbed.log 를 다시 만든다.
  6. app.log 에서 가장 많이 나온 계좌의 토큰을 구해, 반출본만 보고 /root/mask/trace.json 에 top_account_token·event_count·req_ids·first_ts·last_ts 를 적는다.
  7. /root/mask/leakscan.py 를 만들고, scrub.py 를 반출본에 다시 돌려도 결과가 같은지 확인한 뒤 검사 결과를 /root/mask/leak_report.json 에 남긴다.
  8. /root/mask/policy.json/root/mask/scrub_report.json 을 만든다. 보고서의 숫자는 실제 파일에서 세고, policy_sha256 은 정책 파일을 sha256 으로 잰 값이다.

참고

합성 이체 로그 스냅샷 만들기

/root/mask/gen_logs.py 를 만들어 실행해 /root/mask/app.log/root/mask/customers.csv 를 만드세요.

현장에서는 데이터가 먼저 있지만 여기서는 우리가 만듭니다. 계좌·카드·연락처는 지어낸 값이어야 하고, 카드번호는 검사숫자가 맞아야 합니다. 16자리인데 검사숫자가 틀린 정산 일련번호도 섞으세요 — 다음 단계의 오탐이 바로 그것입니다.

정규식으로 후보를 하나도 빠짐없이 찾기

/root/mask/find_candidates.py 로 계좌·카드·전화·이메일 후보를 찾아 /root/mask/candidates.json 에 적으세요.

읽을 파일은 1단계에서 만든 /root/mask/app.log 입니다. 이 단계는 재현율이 전부입니다. 오탐은 다음 단계에서 걷어 내니 16자리 숫자는 일단 전부 카드 후보로 넣으세요. line 은 1부터 세고, value 는 그 줄에 실제로 있는 문자열이어야 합니다.

검사숫자로 카드와 일련번호 가르기

/root/mask/luhn.py 를 만들고, 카드 후보를 /root/mask/candidates_luhn.json 의 card_verified 와 not_card 로 가르세요.

가를 대상은 2단계에서 만든 /root/mask/candidates.json 의 card 후보입니다. 오른쪽 끝에서 두 번째 자리부터 한 칸 걸러 두 배로 만들고, 두 배가 10 이상이면 9를 뺍니다. 모두 더해 10으로 나누어떨어지면 통과입니다. 채점기는 자기가 만든 번호로 luhn.py 를 직접 실행하므로 종료 코드 계약을 지켜야 합니다.

규칙대로 가리고 일련번호는 남기기

/root/mask/scrub.py 를 만들어 /root/mask/app.scrubbed.log 를 만드세요. 카드가 아닌 16자리 수는 그대로 둡니다.

읽을 파일은 /root/mask/app.log 이고 결과는 /root/mask/app.scrubbed.log 입니다. 지시문 참고의 네 가지 치환 모양을 정확히 지키세요. 줄 수는 원본과 같아야 하고, amount 같은 숫자 필드는 건드리지 않습니다. 채점기는 원본에서 기대값을 다시 계산해 한 글자까지 대조합니다.

같은 계좌에 같은 가명 토큰 달기

/root/mask/keys/scrub.key 를 만들고 scrub.py 가 각 줄에 tokens 를 붙이게 한 뒤 /root/mask/app.scrubbed.log 를 다시 만드세요.

4단계에서 만든 /root/mask/scrub.py 를 고쳐 씁니다. 값만 해시하면 경우의 수가 적어 사전 공격으로 되돌아옵니다. 비밀 키를 쓰는 HMAC 이어야 합니다. 용도를 메시지에 넣지 않으면 계좌와 카드가 같은 숫자일 때 같은 토큰이 됩니다.

토큰만으로 사고 고객의 사건 따라가기

가장 많이 나온 계좌의 토큰으로 반출본을 조사해 /root/mask/trace.json 을 만드세요.

계좌를 고르는 일까지만 원본을 봅니다. 그다음부터는 app.scrubbed.log 의 tokens.acct 만 보고 셉니다. 결과 파일에 계좌번호를 다시 적으면 지금까지 한 일이 무의미해집니다.

두 번 돌려도 같은지, 남은 누출이 없는지

/root/mask/leakscan.py 를 만들고, scrub.py 를 반출본에 다시 돌려 결과가 같은지 확인한 뒤 /root/mask/leak_report.json 을 남기세요.

이미 가린 값이 규칙에 다시 걸리지 않는지, 토큰이 이미 있으면 다시 계산하지 않는지 보세요. 검사기는 16자리라고 다 잡으면 안 됩니다 — 일련번호까지 누출로 세면 아무도 쓰지 않습니다.

반출 정책과 스크러빙 보고서 남기기

/root/mask/policy.json/root/mask/scrub_report.json 을 만드세요. 보고서의 숫자는 실제 파일에서 셉니다.

정책의 mask 값은 남길 글자 수이고 key_id 는 /root/mask/keys/scrub.key 의 sha256 앞 12자리입니다. 보고서의 masked 는 중복을 포함한 건수, tokens 는 서로 다른 토큰의 수이며, policy_sha256 은 정책 파일 전체를 잰 값입니다.