안전한 증거 수집
160분 안팎
학습 목표
비밀번호와 세션 값을 요청하지 않고 문의를 분류합니다.
개념
증거를 많이 받는 것과 원인을 좁히는 것은 다릅니다
“로그인이 안 됩니다”라는 문의에 전체 화면, 개발자 도구 기록, 쿠키 값을 보내 달라고 답하면 계정 비밀과 다른 신청자의 정보까지 받을 수 있습니다. 지원의 목적은 사용자를 대신해 로그인하는 일이 아니라 실패한 행동과 확인 지점을 좁히는 일입니다. 이 레슨에서는 세션 만료, 권한 거부, 통신 결과 미확인을 구별하는 질문과 안내를 작성합니다. 문의자의 말을 오류 원인의 확정 증거로 바꾸지 않고 확인 사실·후보 원인·다음 확인을 나눕니다.
첫 질문은 실패한 행동을 묻습니다
로그인 화면에서 사용자 확인이 안 되는지, 로그인 후 신청 내역이 안 보이는지, 운영자 승인 버튼에서 거부되는지 먼저 묻습니다. “마지막으로 성공한 행동과 실패한 화면은 무엇인가요”라는 질문이 한 번에 전체 계정 자료를 요청하는 것보다 비교 범위를 줄입니다. 이어 발생 시각과 시간대, 브라우저 종류·버전, 화면의 오류 문구나 코드, 보이는 요청 번호를 묻습니다. 요청 번호가 없으면 없다고 기록하고 새로 만들어 기존 요청을 확인한 것처럼 적지 않습니다.
시간에는 2026-10-09 14:00 KST처럼 시간대를 함께 적는 연습을 합니다. 사용자 설명이 대략 오후라면 대략이라고 남기고 정밀한 로그 시각으로 꾸미지 않습니다. 재현 환경도 “최신 브라우저” 대신 확인한 제품과 버전을 적습니다. 오류 코드는 표시된 값을 그대로 기록하고 표시가 없으면 미표시라고 씁니다. 필요한 질문을 한꺼번에 과하게 요구하기보다 첫 답으로 다음 질문이 필요한지 결정하면 자료와 사용자의 부담을 함께 줄일 수 있습니다.
세션 만료에는 조회 복구를 안내합니다
계약된 SESSION_EXPIRED 문구가 표시된 제안 사례는 session-expired로 분류합니다. 안내는 “로그인 확인이 필요합니다. 재로그인 후 신청 내역을 다시 확인해 주세요”입니다. 비밀번호를 알려 달라는 요청이나 비밀번호가 틀렸다는 단정은 넣지 않습니다. 다음 확인은 재로그인 창을 열었는지가 아니라 재로그인 뒤 신청 내역 조회가 성공했는지입니다. 같은 문구가 반복되면 발생 시각과 요청 번호로 내부 담당자가 세션 판정을 확인하는 경로를 남깁니다.
재로그인 도중 사용자가 취소하면 해결 완료라고 기록하지 않습니다. 다른 계정으로 돌아왔으면 본인 신청 관계도 바뀔 수 있으므로 계정의 표시 이름을 공개 첨부로 받기보다 내부 확인 절차를 사용합니다. 제출 도중 발생한 문의에서는 접수 여부를 신청 내역에서 확인하도록 안내하고 새 신청을 반복하라고 하지 않습니다. 세션 만료를 해소하는 행동과 신청 저장의 사실을 확인하는 행동이 다르다는 점을 지원 문장에도 반영합니다.
권한 거부에는 필요한 범위를 확인합니다
permission-denied 사례에서는 “조회와 승인 중 어떤 행동이었나요”, “본인 신청인가요, 담당 행사 운영 업무인가요”를 묻습니다. “현재 계정으로 이 작업을 할 수 없습니다. 본인 신청 내역 또는 담당 행사인지 확인해 주세요”라고 안내합니다. 개발 담당자는 역할 배정과 담당 행사 및 서버 판정 기록을 제한된 내부 환경에서 대조합니다. 지원 담당자가 문의를 빨리 닫으려고 운영자 권한을 주거나 전체 신청 자료를 보내는 절차는 제안하지 않습니다.
권한 문제는 사용자 오류일 수도 있지만 역할 배정 누락이나 서버 정책 결함일 수도 있습니다. 화면의 거부 문구만으로 사용자가 잘못했다고 결론내리지 않습니다. 업무 담당자가 확인한 역할과 실제 요청 판정이 일치하는지 비교합니다. 정상 담당 운영자도 담당 범위 밖 행사에 접근했으면 거부가 기대 동작입니다. 기대 거부와 결함을 구별하려면 행동·대상·역할·범위가 모두 필요하며 “로그인 성공” 한 가지 증거만으로 판단하지 않습니다.
응답이 없으면 저장 여부를 확정하지 않습니다
network-unknown은 상태나 응답을 확인하지 못한 경우의 임시 분류입니다. 안내는 “응답을 확인하지 못했습니다. 접수 여부를 신청 내역에서 확인해 주세요”입니다. 네트워크가 원인이라고 확정한 이름이 아니며 연결, 서버 처리, 응답 유실 같은 후보를 남깁니다. 신청 저장 여부는 요청 기록과 후속 조회로 확인합니다. 이전 모듈의 503 모의 저장 전 실패와 실제 응답 부재는 다르므로 행이 증가하지 않았다고 옮겨 적지 않습니다.
통신 결과 미확인 질문에는 발생 시각, 브라우저 환경, 표시 문구, 요청 번호 유무를 넣습니다. 지원팀이 개발자에게 전달할 때는 기대 결과 “접수 후 A001 상태 표시”와 관찰 결과 “응답을 확인하지 못함”을 나누어 적습니다. 아직 없는 A001을 확정된 ID처럼 만들어 쓰지 않습니다. 신청 번호가 확인된 경우에도 공개 공유하지 않고 해당 문의의 내부 조회 범위로 제한합니다. 개발자의 후속 확인 결과를 받은 뒤에만 저장됨·미저장됨·계속 미확인을 구별합니다.
허용 목록으로 자료를 줄입니다
문의 기록의 evidenceFields에는 timeWithZone·browserVersion·action·errorCode·requestId만 허용하는 연습 기준을 씁니다. neverCollect에는 password·cookie·authorization·token·otp를 둡니다. OTP 같은 일회용 코드도 사용자 인증을 돕는 비밀이므로 지원 질문에 넣지 않습니다. 금지 단어만 지우는 방식으로 안전을 보장했다고 말하지 않습니다. “헤더 전체를 복사해 주세요”처럼 간접 요구하는 표현까지 동료가 검토해야 합니다. 허용 목록 밖에 필요한 자료가 있으면 필요 이유와 제한 범위를 먼저 검토합니다.
스크린샷이 필요한 경우 실패한 부분만 잘라 별도 사본을 만듭니다. 이름·연락처·신청 식별자·주소의 쿼리와 인증 비밀이 보이지 않는지 확인한 뒤 공유합니다. 브라우저 네트워크 내보내기 파일은 헤더와 본문이 들어갈 수 있어 기본 요청 자료로 받지 않습니다. 자동 가림은 키 이름이 달라지거나 자유문에 포함된 비밀을 놓칠 수 있습니다. 가림 도구의 유무보다 무엇을 수집하지 않을지와 공유 전 확인 책임을 먼저 문서화합니다.
자료가 이미 들어왔다면 유통부터 줄입니다
사용자가 실수로 비밀값을 첨부했다면 답변에 그 값을 인용하거나 다른 채널로 재전달하지 않습니다. 내부 절차에 따라 접근을 제한하고 첨부 삭제·인증 수단 무효화 필요를 보안 담당자에게 전달합니다. 실제 폐기 여부를 모른 채 “안전하게 삭제됨”이라고 답하지 않습니다. 사용자에게는 비밀값 없이 문제 설명을 다시 받는 경로를 안내합니다. 이 레슨은 실제 유출 대응을 실행하는 실습이 아니라 제품 지원 절차에 담당자와 확인 결과 기록을 포함하는 문서 연습입니다.
첨부 자료에도 종료 조건이 필요합니다. 문의 종료 후 14일 삭제는 교육용 제안으로 적고 내부 담당자만 열람하며 첨부와 내보내기에도 적용하도록 씁니다. 실제 기간과 적용 요건은 개인정보·지원 담당자와 검토합니다. 문의 완료 여부는 사용자에게 조회나 승인 결과가 기대와 같아졌는지 물어 확인합니다. 안내를 보냈다는 사실과 사용자가 해결했다는 사실을 별도 칸에 남기면 아직 해결되지 않은 문의를 완료 지표에 섞는 실수를 줄입니다.
기계 검사와 문장 검토를 함께 사용합니다
access-policy.json의 support 세 분류를 작성한 뒤 python3 check.py --submission access-policy.json을 실행합니다. FAIL support.permission-denied: 분류 하나 필요는 category 철자 또는 해당 객체 누락을 확인하라는 뜻입니다. FAIL json의 line·column은 JSON 구문 위치이며 앞줄 쉼표와 따옴표도 봅니다. PASS는 근거 보존과 목록·판정의 일치이지 질문 의미의 안전성이나 실제 서버 보호의 증명이 아닙니다. 동료가 비밀을 간접 요구하는 문장, 분류별 다음 확인, 불확실성 표현을 읽습니다.
로그에서 인증 비밀을 제외하는 기준은 OWASP 로깅 지침에서 확인할 수 있습니다. 더 읽기의 로깅 장은 요청 번호로 사건을 묶고 가림 코드의 한계를 이해하는 보충입니다. 지원 문서에는 구현 코드 대신 최소 증거, 제한된 열람, 확인된 해결 행동을 남깁니다. 이렇게 작성한 정책은 다음 모듈의 오류 화면과 인수 기준에서 사용할 출발점이 됩니다.
따라하기
문의 한 줄을 행동으로 나눕니다
“로그인이 안 됨”을 로그인 입력·신청 조회·승인 행동으로 나눈 질문을 씁니다. 시각·시간대·오류 코드·요청 번호 유무를 기록하고 후보와 확인 사실을 별도 칸에 둡니다.
분류별 두 질문과 복구 행동을 씁니다
support의 session-expired·permission-denied·network-unknown에 질문 두 개 이상을 적습니다. 재로그인 후 조회, 담당 행사 대조, 저장 여부 미확인 뒤 기록 조회를 각각 다른 안내로 연결합니다.
자료 경로를 제한합니다
neverCollect와 evidenceFields 목록을 README대로 작성합니다. screenshot에 필요한 부분만 자르고 이름·연락처·쿼리·식별자를 가린 사본을 공유하는 기준을 쓰고 retention에 문의 자료의 종료·열람 조건을 제안합니다.
미션을 검사하고 동료와 검토합니다
미션 루트에서 실행합니다. 아래 출력은 solution에서 직접 실행한 결과입니다. 자신의 제출이 통과하면 비밀 간접 요구·삭제 조건·실제 구현 미확인을 동료와 검토합니다.
python3 check.py --submission access-policy.json실행 결과
검사 실패: 0 PASS 이전 근거·11권한 사례·5필드·3지원 분류; 내용은 동료 검토
확인 문제
실습
지원 카드 세 개를 access-policy.json의 support에 제출합니다. 각 카드에 분류·민감정보 없는 질문 두 개 이상·서로 다른 안내·다음 확인·증거 허용 목록·수집 금지 목록·스크린샷 가림·보관 종료를 포함합니다. 자동 검사 후 동료는 간접 인증 비밀 요구, 응답 부재를 저장 실패로 단정하는 표현, 안내 전송을 해결 완료로 처리한 부분을 검토합니다. 미션은 앞 근거와 권한·필드 표까지 함께 제출합니다.
더 읽기
면접 질문
- 사용자가 로그인이 안 된다고 할 때 확인할 순서를 설명해 주시면 됩니다.