Devin.KR

증거 목록과 무결성

80분 안팎

학습 목표

기록의 출처와 해시를 관리합니다.

개념

관찰을 보존하는 이유

점검 결과가 작성 뒤 바뀌었는지 알 수 없다면 수정 담당자는 보고서와 실제 근거를 비교하기 어렵습니다. 무결성 관리는 파일을 멋지게 정리하는 일이 아니라 수집 시점의 바이트를 기준으로 이후 변경을 탐지하는 작업입니다. 이번 실습은 hashlib.sha256으로 파일을 읽고 기준 해시와 비교합니다. 해시가 같다는 사실만으로 관찰이 진실이거나 허가된 사람이 수집했다는 결론을 내리지는 않습니다.

텍스트 대신 바이트를 읽습니다

파일 내용 abc와 abc 뒤 줄바꿈은 다른 바이트열입니다. read_text 후 strip으로 공백을 없애면 이 차이를 놓칩니다. digest.py는 read_bytes로 실제 파일을 읽고 sha256의 hexdigest를 반환해야 합니다. 해시 값은 64자리 16진 문자열입니다. 빈 파일도 정해진 해시가 있지만 없는 파일은 FileNotFoundError입니다. 둘을 같은 값으로 바꾸면 삭제된 증거를 정상 자료처럼 취급합니다.

독립적인 기대값을 사용합니다

구현한 digest 함수를 두 번 호출해 둘이 같으면 통과시키는 테스트는 상수 반환 결함을 놓칩니다. tests.py는 알려진 바이트 abc의 기준을 별도 hashlib 호출로 계산합니다. 이후 같은 파일 유지, 줄바꿈 추가, 빈 파일, 파일 삭제를 확인합니다. starter의 0 반복 반환은 처음 비교에서 known bytes mismatch로 실패합니다. 출력 문자열을 맞추기 위해 테스트 기대값을 바꾸지 않습니다.

목록의 완전성도 검사합니다

파일별 해시만 맞아도 중요한 파일을 목록에서 빼면 그 파일 변경은 탐지되지 않습니다. 미션 integrity.py는 FILES의 11개 경로와 manifest의 키 집합을 비교합니다. 승인 fixture, 같은 검사 코드, 취약·수정 코드와 저장소, 짝 결과, findings가 포함됩니다. manifest membership mismatch는 해시 알고리즘 오류가 아니라 목록에서 경로가 빠지거나 추가된 상황을 먼저 조사할 신호입니다.

봉인과 재검사를 구분합니다

node paired-check.cjs로 결과를 생성하고 findings를 작성한 뒤 python3 integrity.py seal로 기준을 만듭니다. 다음 검증에서는 python3 integrity.py로 기존 기준과 비교합니다. check.sh는 기준을 자동으로 다시 만들지 않습니다. 매 검사 때 seal을 실행하면 바뀐 증거도 새 기준과 같아져 변경 탐지 목적을 잃습니다. 학습자가 최초 봉인을 한 뒤 제출물 내용이 바뀌면 새 실행 묶음으로 관리합니다.

같이 바뀌는 목록의 한계

증거와 manifest를 함께 고칠 권한이 있으면 해시 검사를 우회할 수 있습니다. 그래서 기준 목록 사본을 별도 읽기 전용 보관 위치에 남기고 누가 언제 확정했는지 기록합니다. 이번 로컬 과제는 서명이나 독립 저장소를 구현하지 않습니다. 해시 검사가 제공하는 범위는 지정 기준 이후의 바이트 차이 탐지입니다. 수집자 인증과 악의적 목록 교체 방어가 필요하면 별도의 신뢰 경로를 설계합니다.

출처 메타데이터를 연결합니다

pair.json의 scope와 mode는 관찰이 어디서 허가되고 어떤 층에서 수집됐는지 설명합니다. verification-scope.json은 승인 기간과 합성 자료 정책을 가집니다. findings의 evidence 배열은 상대 경로로 증거를 가리킵니다. 경로와 해시를 함께 남기면 담당자가 올바른 파일을 찾고 바이트 동일성을 확인할 수 있습니다. 해시만 보고 어떤 요청과 연결되는지 추측하게 두지 않습니다.

민감 정보는 수집 전에 줄입니다

이미 모은 세션 토큰을 나중에 지우면 원본과 전달본이 달라져 해시를 다시 정해야 합니다. 가능한 한 관찰 결과 생성 단계부터 토큰·본문·비밀번호를 제외합니다. 필요해서 원본을 수집한 실제 업무라면 제한 접근 원본과 가린 전달본을 별도 증거로 관리하고 변환 관계를 기록합니다. 이번 결과에는 상태와 정책 검사 이름만 저장하며 합성 자료 본문도 전달 목록에 넣지 않습니다.

변경 검출을 실제 시험합니다

미션 verify-delivery.py는 임시 복사본에서 pair.json·범위 파일·findings 끝에 공백을 붙여 각 검사가 실패하는지 확인합니다. 이어서 결과 파일을 삭제해 누락도 거절하는지 봅니다. 원래 봉인 파일은 변경하지 않습니다. 이 음성 대조는 검증 함수가 언제나 성공을 반환하는 실수를 잡습니다. 테스트가 실패하면 변경한 경로와 stderr의 digest mismatch 메시지를 먼저 비교합니다.

경로 오류와 무결성 오류

No such file이나 FileNotFoundError는 파일 위치 또는 수집 누락을 뜻할 수 있습니다. ZIP 루트가 아닌 곳에서 명령을 실행했는지, pair.json을 생성했는지 확인합니다. digest mismatch는 파일은 있지만 기준과 바이트가 다르다는 뜻입니다. 내용을 읽어 합법적인 재수집인지 불명확한 변경인지 판단하고 기존 기준을 덮어쓰기 전에 이유를 기록합니다. 자동 검사는 변경의 원인을 판정하지 않습니다.

인계할 때의 확인 순서

받는 사람은 전달 목록의 파일 수와 상대 경로를 확인한 다음 기준의 출처를 확인하고 해시 검사를 실행합니다. 그 뒤 범위·수집 방식·결과 의미를 읽습니다. 통과 메시지 하나로 사실 검토를 생략하지 않습니다. 더 읽기의 sha256sum 장은 명령줄 체크섬 목록과 경로 처리 및 진위 확인의 차이를 확장합니다. 이 과제는 macOS와 Linux의 명령 이름 차이를 피하려고 Python 표준 라이브러리로 같은 바이트 검사를 수행합니다.

기준 목록을 확정하기 전에 모든 근거가 생성됐는지 확인합니다. pair.json이 없으면 seal은 파일 오류로 중단되며 빈 목록을 정상 결과로 만들지 않습니다. 실행 결과를 재수집할 때는 이전 결과와 새 결과를 섞지 않도록 별도 폴더를 사용합니다. 결과 파일에 현재 시각처럼 매 실행 달라지는 값을 추가했다면 기존 봉인과 비교 실패하는 것이 정상입니다. 새 실행에 새 기준을 남겨 두 기록의 관계를 설명합니다.

따라하기

줄바꿈의 차이를 실행합니다

import hashlib
a=hashlib.sha256(b'abc').hexdigest()
b=hashlib.sha256(b'abc\n').hexdigest()
print(len(a))
print(a==b)

실행 결과

64
False

실제 바이트 읽기를 구현합니다

security-evidence-integrity의 digest.py에서 read_bytes와 hashlib.sha256을 사용합니다. bash check.sh로 알려진 바이트·변경·빈 파일·삭제 검사를 확인합니다.

기준을 봉인합니다

누적 미션에서 node paired-check.cjs 실행과 findings 작성 후 python3 integrity.py seal을 실행합니다. manifest 사본을 별도 보호 위치에 보관합니다.

재검사와 음성 대조를 실행합니다

python3 integrity.py로 11개 해시를 검사하고 bash check.sh로 임시 복사본의 변경·삭제 거절을 확인합니다. 재검사 때 seal을 자동 실행하지 않습니다.

확인 문제

실습

digest.py TODO를 실제 바이트 SHA-256으로 완성합니다. 알려진 바이트·줄바꿈·빈 파일·삭제 경계 검사를 모두 통과시킵니다.

시작 코드·테스트 내려받기

실행 명령

bash check.sh

기대 결과

PASS: known bytes, unchanged, newline, empty and missing evidence

모범 답안모범 답안 내려받기

더 읽기

면접 질문

  • 취약점 수정 전후의 테스트 내용을 설명합니다.