Devin.KR

위협과 통제 연결

55분 안팎

학습 목표

위협의 전제와 영향·통제를 연결합니다.

개념

위협을 실행 가능한 질문으로 바꿉니다

위협 목록에 해킹·유출·악성코드라고만 적으면 어떤 개발 작업을 해야 할지 정할 수 없습니다. 위협은 특정 조건에서 특정 주체가 자산에 어떤 부정적 결과를 일으킬 수 있는지 설명해야 합니다. 현재 앱의 예는 로그인한 bob이 alice 자료 ID를 요청하고 소유자 비교가 누락되었을 때 본문을 읽는 상황입니다. 자산·흐름·경계와 조건을 같이 쓰면 기존 권한 회귀 시험이 왜 필요한지 이해할 수 있습니다.

위협과 확인된 결함을 분리합니다. 앞 미션 starter에서 권한 누락은 시험으로 재현했고 solution에서는 타인 접근을 거절합니다. 같은 시나리오는 이후 수정에서 다시 생길 위험으로 모델에 남길 수 있습니다. 이를 현재 solution의 확인된 취약점이라고 적으면 상태가 잘못 전달됩니다. 각 항목에 현재 통제와 관찰 근거, 아직 확인하지 않은 가정을 함께 기록합니다.

한 행에 연결할 정보

위협 T-owner에는 asset A-documents, boundary B-owner, flow F-read, 전제 로그인한 타인과 존재하는 자료 ID, 영향 본문 노출, 통제 canAccess의 소유자 비교, 검증 타인 404와 소유자 200, 담당 앱 담당자를 적습니다. 통제 이름이 보안 강화이면 어느 코드나 정책을 바꿀지 알 수 없습니다. 검증이 테스트면 어떤 주체·입력·기대 결과를 시험할지 더 구체적으로 씁니다.

변경 위협은 같은 소유자 비교를 사용해도 자료 무결성에 대한 영향을 따로 적습니다. 타인 PATCH 뒤 title과 content가 그대로이고 타인 DELETE 뒤 소유자 GET이 200인지 확인합니다. 응답 거절만 검사하면 처리 후 오류 응답을 반환하는 부작용을 놓칠 수 있습니다. 통제가 하나라고 위협도 하나여야 하는 것은 아니지만 같은 위협을 중복 등록해 우선순위를 부풀리지 않습니다.

빠짐을 찾는 분류 질문

신원 사칭은 세션을 다른 사용자의 것으로 믿게 만들 수 있는지, 변조는 owner나 자료 값을 바꿀 수 있는지, 부인은 누가 어떤 동작을 했는지 근거가 남는지 묻습니다. 정보 노출은 자료·쿠키·로그 원문을 읽는 경로, 서비스 거부는 요청 크기와 비용, 권한 상승은 일반 계정이 관리자 역할을 얻는 경로로 질문합니다. 이런 분류 질문은 생각을 돕는 도구이며 각 분류의 위협을 억지로 한 건씩 만들 필요는 없습니다.

이 앱에서 동기 비밀번호 검증 비용은 잔여 위험 후보입니다. 함수 검사로 로그인 결과가 맞아도 다수 동시 요청에 대한 가용성은 증명되지 않습니다. 입력 처리와 로그 원문 문제는 다음 모듈에서 자세히 검증할 계획으로 남깁니다. 현재 코드로 확인하지 않은 공격 성공을 사실로 적지 않고 필요한 조건과 검증 예정 범위를 설명합니다.

예방·탐지·복구를 구별합니다

소유자 비교는 타인 조회를 예방하는 통제이고 접근 실패 로그는 사후 탐지 근거입니다. 로그를 남긴다고 읽기 권한이 생기거나 유출이 취소되는 것은 아닙니다. 로그아웃은 세션 재사용을 줄이는 통제지만 이미 브라우저에 전달된 자료를 회수하지 않습니다. 통제 설명에는 어떤 단계에서 무엇을 막고, 어떤 결과는 막지 못하는지를 한 문장씩 적습니다.

검증 방법은 통제의 의도를 깨뜨리는 입력과 정상 대조로 구성합니다. 타인 거절만 통과하는 모든 요청 거절 구현은 업무 기능을 손상시킵니다. 반대로 정상 소유자 조회만 통과하면 인가 누락을 잡지 못합니다. 통제와 검증을 쌍으로 적고 두 결과를 함께 보아야 수정 근거가 됩니다. 자동 문서 검사는 이러한 내용의 빈 칸을 찾지만 보안 효과 전체를 증명하지 않습니다.

브라우저 검사 계약

표준 입력은 assets와 boundaries 문자열 배열, threats 객체 배열을 가진 JSON 한 개입니다. 위협 id는 비어 있지 않은 고유 문자열이고 asset·boundary·control은 문자열 또는 누락 값입니다. 이번 문제는 참조 자산과 경계가 목록에 존재하는지, control이 공백을 제거한 뒤 비어 있지 않은지 확인합니다. 위반 항목의 ID만 사전식으로 정렬하여 한 줄씩 출력하고 없으면 OK를 출력합니다.

get으로 누락 키를 받아들이되 값이 None이나 숫자일 때 strip을 직접 호출하지 않습니다. isinstance(value, str)로 유형을 먼저 확인합니다. 존재 검사는 set으로 수행하고 ID는 sorted로 정렬합니다. 같은 자산을 사용하는 위협 여러 건은 정상이며 중복 자산이라는 이유로 거절하지 않습니다. 빈 threats는 검사할 항목이 없으므로 OK입니다. 빈 자산 목록에 참조하는 위협은 거절 대상입니다.

실패 메시지와 사람의 최종 리뷰

AttributeError에서 strip이 없다고 나오면 문자열이 아닌 control을 먼저 다뤘는지 확인합니다. KeyError: control은 누락 필드를 직접 대괄호로 읽었다는 신호입니다. JSONDecodeError는 입력 형식 문제이고 모델의 논리 결함과 다릅니다. 출력 순서만 틀리면 입력 순서를 그대로 쓰지 않았는지 확인합니다. 풀이에서는 디버그 로그를 표준 출력에 섞지 않습니다.

프로그램이 OK를 출력해도 존재하는 경계가 실제로 그 위협의 경계인지는 보장하지 않습니다. 미션 검사에서는 flow와 boundary의 관계까지 확장하고 사람은 전제·영향·통제·검증의 타당성을 읽습니다. 표의 완전성과 실제 안전성을 구분하는 것이 이 레슨의 핵심입니다. 설명할 수 없는 통제는 빈 칸을 채웠더라도 검토 대상으로 되돌립니다.

실무 리뷰를 한 번 더 합니다

리뷰 질문은 통제 실패를 상상하는 데서 시작합니다. 소유자 비교가 빠졌다면 누가 어떤 자료를 얻는지, 세션 만료 비교가 달라졌다면 어느 시각부터 접근이 허용되는지 묻습니다. 답이 없으면 조건이 너무 추상적인 것입니다. 시험 가능한 경계 시각이나 사용자 조합으로 바꾼 뒤 목록에 남깁니다. 위협 모델은 공격 절차를 외부 시스템에 적용하는 안내가 아니라 소유한 교재 앱의 통제와 증거를 점검하는 작업입니다.

따라하기

빈 통제 판별

Python 3에서 다음 코드를 실행하고 판별에 사용한 조건을 확인합니다.

values=['owner check','  ',None,7]
for value in values: print(isinstance(value,str) and bool(value.strip()))

실행 결과

True
False
False
False

참조 존재 확인

Python 3에서 다음 코드를 실행하고 판별에 사용한 조건을 확인합니다.

assets={'A-documents'}
for asset in ['A-documents','A-unknown','']: print(asset or '(empty)', asset in assets)

실행 결과

A-documents True
A-unknown False
(empty) False

결과 순서 고정

Python 3에서 다음 코드를 실행하고 판별에 사용한 조건을 확인합니다.

invalid=['T-3','T-1']
print('\n'.join(sorted(invalid)))

실행 결과

T-1
T-3

제출물과 실행 결과 대조

브라우저 문제의 JSON을 입력하여 ID 정렬·빈 목록·공백 통제를 확인합니다. 미션에서는 각 위협에 전제·영향·검증·담당도 추가합니다.

확인 문제

실습

JSON 한 개를 읽고 asset·boundary 참조 누락 또는 존재하지 않는 참조, 비문자열·공백 control을 가진 위협 ID를 사전식 정렬하여 줄마다 출력합니다. 없으면 OK를 출력합니다. id는 고유한 비어 있지 않은 문자열이며 입력 배열과 객체 구조는 유효합니다. 디버그 출력은 제거합니다.

모범 답안
import json, sys
model = json.load(sys.stdin)
assets = set(model['assets'])
boundaries = set(model['boundaries'])
invalid = []
for threat in model['threats']:
    control = threat.get('control')
    if (threat.get('asset') not in assets or threat.get('boundary') not in boundaries
            or not isinstance(control, str) or not control.strip()):
        invalid.append(threat['id'])
print('\n'.join(sorted(invalid)) if invalid else 'OK')

더 읽기

면접 질문

  • 실습 앱에서 보호할 자산과 신뢰 경계를 설명합니다.