거절 경로의 회귀 테스트
60분 안팎
학습 목표
정상 기능과 금지된 접근을 함께 확인합니다.
개념
수정이 오래 유지되게 만듭니다
권한 누락은 고친 당일에는 잘 보이지만 새 라우트나 리팩터링 이후 다시 생길 수 있습니다. 회귀 테스트는 같은 결함의 재등장을 확인할 입력과 기대를 코드로 고정합니다. 보안 담당자는 단순히 테스트 수를 늘리는 대신 보호할 규칙, 실행 경로, 거절 뒤 상태를 연결해야 합니다. 이번에는 두 계정과 세 동작의 조합을 독립된 앱 상태에서 실행하여 정상 동작과 금지된 접근을 함께 검증합니다.
테스트 표의 독립성
각 조합은 새 createApp을 만들고 alice와 bob을 로그인시킨 뒤 alice의 자료 하나를 만듭니다. 이전 조합의 DELETE가 다음 GET 시험 자료를 지우지 않도록 별도 상태를 사용합니다. 같은 앱을 계속 쓰면 시험 순서에 따라 성공과 실패가 달라질 수 있습니다. 시간도 now: () => 0으로 고정하여 테스트가 길어져 실습용 세션이 만료되는 우연을 없앱니다. 만료 동작은 별도의 시계 경계 시험이 담당합니다.
기대 결과의 출처
actor가 alice이면 GET·PATCH·DELETE가 성공해야 하고 bob이면 모두 거절되어야 합니다. 이 기대는 접근표에서 얻으며 현재 canAccess를 호출하여 expected를 만들지 않습니다. 구현과 기대값이 같은 결함을 공유하면 테스트는 잘못된 상태에서도 통과합니다. 자료를 생성하는 준비 코드와 검증할 코드를 구분하고, 실패 메시지에 actor와 method를 남기면 어떤 권한 칸이 깨졌는지 빠르게 찾을 수 있습니다.
상태 코드만 비교하면 놓치는 것
bob의 PATCH가 404를 반환해도 title이 바뀌었다면 거절 경로에 부작용이 있습니다. bob의 DELETE 뒤 소유자의 GET이 404라면 자료가 사라졌습니다. 테스트는 요청 직후 alice의 재조회를 수행하고 응답 내용이나 존재 여부를 비교합니다. 허용된 alice PATCH 뒤에는 after, 거절된 bob PATCH 뒤에는 before가 기대 제목입니다. 같은 테스트에 응답과 후조건을 연결하면 성공 메시지로 상태 변경을 숨기는 구현을 잡을 수 있습니다.
거절만 하는 수정도 실패해야 합니다
return false로 모든 접근을 막는 수정은 타인 시험만 있는 테스트를 통과합니다. 하지만 자기 자료를 읽거나 고치지 못하는 앱은 요구를 만족하지 못합니다. 정상 소유자 작업과 관리자 읽기를 양성 대조로 함께 실행합니다. 입력 검증·health·자료 id 형식처럼 기존 기능도 유지합니다. 보안 회귀 테스트가 기능 시험을 대체하는 것이 아니라 기존 요구와 추가 제한의 교집합을 확인한다는 점을 설명합니다.
과거 누락으로 시험 강도 확인
starter는 역할·메서드가 정상이라면 소유 관계를 무시하고 허용합니다. 같은 테스트를 starter와 solution에 적용하면 첫 번째는 타인 조합에서 실패하고 두 번째는 통과해야 합니다. 기대값을 각각 다르게 두지 않습니다. 수정 전 코드가 실패한다는 결과는 이번 테스트가 그 누락을 실제로 검출한다는 근거입니다. 테스트를 많이 만들었다는 숫자보다 어떤 잘못된 구현을 구별했는지가 검토에 더 유용합니다.
누적 미션의 연결
미션 starter는 m03 solution 전체를 복사하여 Linux 파일 권한·범위 문서·요청 식별자·합성 DNS 기록을 유지했습니다. app.cjs는 세션과 자료 권한을 확장했고 server.cjs는 쿠키를 읽어 전달합니다. 이전 함수 기반 시험과 E01 생성기는 별도 authenticated-fixture에서 합성 로그인 후 호출합니다. 이 fixture는 테스트 준비 도구이며 실제 서버의 인증을 우회하지 않습니다. 서버는 원래 createApp을 그대로 사용합니다.
로컬 검사와 외부 검사
bash identity-check.sh는 세션·자료·회귀·기존 함수·허가 범위 시험, E04 생성, 보고서 참조 검사를 수행합니다. bash check.sh는 Docker로 기존 계정 경계와 파일 권한, 루프백 HTTP, 새 세션 전달까지 검사합니다. 이 환경에서는 Docker를 실행할 수 없어 verify=external로 표기합니다. PENDING은 전체 통과가 아니며 실패도 아닙니다. 외부에서 종료 코드 0과 각 검사 결과를 확인해야 미션 전체 완료라고 기록할 수 있습니다.
증거를 만들 때 비밀 제외
identity-evidence.json에는 E04와 scope-001, 함수 호출이라는 실행 방식, 타인의 세 동작 상태, 소유자 후속 조회 상태를 기록합니다. 세션 원문이나 로그인 입력은 저장하지 않습니다. 토큰이 없는 증거도 접근표·합성 계정·명령·검증 코드로 재현 조건을 설명할 수 있습니다. 코드에서 새 결과를 생성하므로 report.md의 수정 후 상태가 실제 실행과 맞는지 검증기가 읽습니다. 문서에 적힌 결과를 실행했다고 착각하지 않습니다.
오류를 세 부류로 읽기
AssertionError에서 expected 404, actual 200이면 권한 거절 누락을 먼저 확인합니다. expected before, actual after라면 거절 후 자료 보존이 깨졌습니다. MODULE_NOT_FOUND는 ZIP 루트나 파일 경로 문제이고 Docker 실행 불가는 외부 검증 조건입니다. 환경 문제를 권한 결함 수정으로 해결하려 하거나 기대값을 실행 결과에 맞춰 낮추지 않습니다. 실패한 조합만 재현하더라도 최종적으로 전체 검사 명령을 다시 실행해 정상 기능의 손상을 확인합니다.
보고서의 수정 전후 짝
보고서에는 동일 합성 자료와 두 계정, GET·PATCH·DELETE, 수정 전 타인 200과 수정 후 타인 404를 짝지어 씁니다. 수정 지점은 canAccess의 소유자 관계와 관리자 읽기 제한입니다. 이어서 소유자 조회 200 및 원문 보존을 기록합니다. 범위 scope-001과 증거 E04를 연결하고 실제 개인정보를 쓰지 않았음을 적습니다. starter에서 누락을 재현한 결과와 전체 Docker 검증 대기 상태를 분리하면 다음 담당자가 남은 확인을 알 수 있습니다.
인계할 남은 위험
메모리 세션과 자료는 재시작 때 없어지고 동기 KDF는 다수 동시 요청에 적합한 서버 설계가 아닙니다. HTTPS 전송, CSRF, 영속 저장, 권한 변경 즉시 반영, 세션 수 제한은 이번 테스트가 증명하지 않습니다. 후속 모듈에 넘길 때 이 한계를 구체적으로 적습니다. 최종 산출물은 수정한 코드, 동일한 회귀 테스트, E04, 수정 전후 보고서입니다. 신입은 이 네 자료를 근거로 무엇이 고쳐졌고 무엇이 아직 미검증인지 설명할 수 있어야 합니다.
따라하기
조합과 기대값 만들기
아래 코드를 실행하여 이 단계의 판단 결과를 확인합니다.
for(const actor of ['alice','bob'])for(const method of ['GET','PATCH','DELETE'])console.log(actor,method,actor==='alice'?200:404);실행 결과
alice GET 200 alice PATCH 200 alice DELETE 200 bob GET 404 bob PATCH 404 bob DELETE 404
응답 뒤 상태도 비교
아래 코드를 실행하여 이 단계의 판단 결과를 확인합니다.
const assert=require('node:assert/strict');
const before={title:'before'};
const after={title:'before'};
assert.deepEqual(after,before);
console.log('state preserved');실행 결과
state preserved
다음 시험 상태를 분리
아래 코드를 실행하여 이 단계의 판단 결과를 확인합니다.
function fresh(){return new Map([[1,{title:'before'}]]);}
const first=fresh();first.delete(1);
const second=fresh();console.log('first:',first.has(1));console.log('second:',second.has(1));실행 결과
first: false second: true
실습의 실패와 수정 대조
ZIP 루트에서 bash check.sh를 실행합니다. starter의 실패 시험 이름과 expected/actual을 읽고 구현을 수정합니다. solution에서도 같은 명령으로 전체 통과와 종료 코드 0을 확인합니다.
확인 문제
실습
app.cjs의 권한 누락을 수정합니다. 같은 회귀 테스트를 starter와 solution에서 실행하고 두 계정·세 동작의 상태와 자료 후조건을 설명합니다. 테스트 파일을 수정하지 않습니다.
실행 명령
bash check.sh
기대 결과
12개 테스트 묶음 통과, 종료 코드 0
모범 답안
모범 답안 내려받기더 읽기
면접 질문
- 취약점 수정 전후의 테스트 내용을 설명합니다.