06. 보안 약점과 개선 계획
6.1 작성 원칙
이 장에서는 Tiny Second-hand Shopping Platform의 실제 기능과 맞닿은 위험, 방어 조치, 검증 상태만 다룹니다.
저장소에는 설계와 구현 과정에서 확인한 위험에 대한 방어 조치와 음성·회귀 테스트를 반영해 두었습니다. 자동 검증을 마친 항목과 실제 배포·운영 환경에서 추가로 확인할 항목은 구분해 기록합니다. 각 표의 ‘발견 당시 상태’는 수정 전의 기록일 뿐 현재 상태를 뜻하지 않습니다.
VULN-01. 로그인 무차별 대입과 계정 정보 노출
| 항목 |
내용 |
| 식별자 |
VULN-01 |
| 발견 단계 |
요구사항·설계 |
| 위험 |
공격자가 반복 로그인으로 비밀번호를 추측하거나 응답 차이를 이용해 존재하는 아이디를 찾을 수 있습니다. |
| 영향 |
사용자 계정과 세션 |
| 발견 당시 상태 |
로그인 실패 제한이 없어 반복 추측과 계정별 응답 차이의 위험이 있었습니다. 초기 제한 구현은 차단된 IP에서도 임의 아이디별 상태 행을 계속 만들 수 있었고, 세션 epoch 누락을 허용했습니다. |
| 개선 조치 |
Django 비밀번호 해시·검증기를 사용하고, 계정과 비식별 HMAC IP 키별로 실패 횟수와 냉각 시간을 적용했습니다. 먼저 IP 제한을 확인하고 24시간이 지난 상태는 정리하며, 누락·변조·불일치한 세션 epoch는 로그아웃합니다. 성공하면 계정 실패 기록만 초기화하고, 아이디 존재 여부와 관계없이 같은 오류를 반환합니다. |
| 검증 |
5회·20회 경계, 동일 계정·IP 병렬 실패, 차단 뒤 임의 아이디 저장 증폭, 알 수 없는 아이디, 제한 만료와 세션 epoch 음성 테스트를 실행했습니다. |
| 잔여 위험 |
여러 계정·여러 네트워크를 이용한 저속 공격은 완전히 막을 수 없어 패턴 관찰이 필요합니다. |
VULN-02. 타인 객체 접근과 대량 할당
| 항목 |
내용 |
| 식별자 |
VULN-02 |
| 발견 단계 |
요구사항·설계·구현 |
| 위험 |
요청의 사용자·소유자 ID나 임의 필드를 그대로 신뢰하면 다른 사용자의 프로필·상품·신고를 변경하거나 권한 필드를 바꿀 수 있습니다. |
| 영향 |
프로필, 상품, 신고 |
| 발견 당시 상태 |
사용자·상품 서비스 골격에 변경 가능 필드와 금지 필드는 분리되어 있었지만 실제 HTTP 객체 권한 검사가 없었습니다. |
| 개선 조치 |
행위자는 세션으로 결정하고, 프로필 작업은 세션의 사용자 본인만 대상으로 하며 상품은 조회와 행 잠금 시 소유자를 다시 확인합니다. 입력은 Form allowlist만 받고, 존재를 숨겨야 하는 타인 상품과 채팅방에는 404를 반환합니다. |
| 검증 |
타인 상품 수정·삭제, 임의 권한 필드, 제3자 1대1 채팅 접근, 비인증 보호 URL과 CSRF 없는 변경 요청을 음성 테스트로 확인했습니다. |
| 잔여 위험 |
새 URL·WebSocket을 추가할 때 같은 정책을 누락할 수 있어 진입점별 회귀 테스트가 필요합니다. |
VULN-03. 위험한 상품 이미지 업로드
| 항목 |
내용 |
| 식별자 |
VULN-03 |
| 발견 단계 |
요구사항·설계·구현 |
| 위험 |
확장자만 확인하면 스크립트, 위장 MIME, 손상 이미지, 압축 폭탄, 메타데이터, 경로 조작 파일이 저장될 수 있습니다. |
| 영향 |
서버 자원, 미디어 저장소, 이미지를 보는 사용자 |
| 발견 당시 상태 |
허용 확장자와 5MiB·4096×4096 제한 계약만 있고 완전 디코딩·재인코딩은 없었습니다. |
| 개선 조치 |
JPEG·PNG·WebP만 받고 Pillow로 완전히 디코딩한 뒤 새 이미지로 재인코딩합니다. UUIDv4 파일명을 사용하고 메타데이터를 제거하며, 원본과 재인코딩 결과 모두에 크기 제한을 적용하고 소유자만 변경할 수 있게 했습니다. |
| 검증 |
확장자·MIME·서명 불일치, SVG, polyglot, 손상·과대·다중 프레임 이미지, 경로 문자열, 메타데이터 제거와 UUID 이름을 자동 테스트로 확인했습니다. |
| 잔여 위험 |
이미지 라이브러리 자체 취약점과 CPU·메모리 고갈 위험은 의존성 갱신과 자원 제한으로 계속 관리해야 합니다. |
VULN-04. 채팅 권한 우회·XSS·중복 메시지
| 항목 |
내용 |
| 식별자 |
VULN-04 |
| 발견 단계 |
설계·구현 |
| 위험 |
비인증 연결, 위조 Origin, 타인 방 접근, HTML 실행, 과도한 전송, ACK 유실 뒤 재전송이 권한 침해·XSS·중복 저장으로 이어질 수 있습니다. |
| 영향 |
채팅 참여자, 채팅 이력, 서비스 가용성 |
| 발견 당시 상태 |
방·참여자·메시지 모델과 client UUID 제약만 있었고 consumer가 없었습니다. 초기 구현에서는 nullable join에 방 잠금을 적용해 PostgreSQL 오류가 발생했고, Host userinfo와 휴면 뒤 기존 소켓 수신을 차단하지 못했습니다. |
| 개선 조치 |
연결 시 인증과 정확한 Origin을 확인하고, frame과 outbound 전달 때마다 참여자와 현재 계정 상태를 다시 확인합니다. 방 행만 잠그고 DB에 degraded를 먼저 커밋한 뒤 전달에 성공하면 live로 전환합니다. 본문은 text로 출력하며 UUIDv4 재전송은 중복 저장하거나 재발행하지 않습니다. |
| 검증 |
비인증·누락/위조 Origin·Host userinfo·제3자 방·2000/2001바이트·속도 경계·Redis 장애·재전송 충돌·휴면 뒤 수신 차단을 자동 테스트로 확인했습니다. |
| 잔여 위험 |
Redis 장애 동안 실시간 전달은 중단될 수 있으며, 이력 동기화가 누락되면 사용자 화면에 일시적인 차이가 남습니다. |
PR #43·#44에서 연결 성공 상태를 상품 대화 · 연결됨으로 명시하고, 4400·4403·1000 종료는 재시도하지 않도록 했습니다. 그 밖의 비정상 종료는 최대 5회 지수 백오프로 제한하며 10초 안정 연결 뒤에만 재시도 횟수를 초기화합니다. 실제 배포 프록시가 WebSocket upgrade와 close code를 보존하는지는 여전히 배포 환경에서 확인해야 합니다.
VULN-05. 신고 조작과 동시 제재 경합
| 항목 |
내용 |
| 식별자 |
VULN-05 |
| 발견 단계 |
요구사항·설계·구현 |
| 위험 |
자기·중복·신규 계정 신고를 그대로 세거나 동시 요청을 분리 처리하면 공격자가 상품을 숨기고 사용자를 휴면시키거나 중복 제재를 만들 수 있습니다. |
| 영향 |
상품 노출, 사용자 접근, 감사 기록 |
| 발견 당시 상태 |
신고자-대상 고유 제약과 제재 시각 모델은 있었지만 유효 신고 판정과 원자적 제재 서비스가 없었습니다. |
| 개선 조치 |
인증·활성·가입 7일·자기 신고 제외·최근 7일·독립 신고자 조건을 트랜잭션 안에서 확인합니다. 대상 행을 잠근 뒤 신고 소비, 임계 판정, 7일 단일 제재, 감사 기록, 사용자 auth_epoch 증가를 한 번에 저장하고 만료는 DB 시각으로 계산합니다. |
| 검증 |
4·5명 경계, 사용자 맥락 1·2개, 중복·자기·신규 계정 신고, 동시 다섯 신고, 소비 신고 재사용 방지와 만료 후 복구를 자동 테스트로 확인했습니다. |
| 잔여 위험 |
다수 계정을 이용한 공모를 완전히 식별할 수 없어 속도 제한과 담당자 검토가 필요합니다. |
VULN-06. 오류·로그의 민감정보 노출
| 항목 |
내용 |
| 식별자 |
VULN-06 |
| 발견 단계 |
요구사항·설계 |
| 위험 |
상세 예외, 비밀번호, 세션, 토큰, 내부 경로, 원문 채팅을 응답이나 로그에 남기면 추가 공격과 개인정보 노출에 이용될 수 있습니다. |
| 영향 |
모든 사용자와 운영 정보 |
| 발견 당시 상태 |
공개 보고서는 비밀값과 개인정보를 제외했지만 제품 오류·로그 경로의 자동 검증이 부족했습니다. |
| 개선 조치 |
로그인과 신고 응답은 일반화하고 비밀번호·세션·토큰·원문 IP는 로그에 기록하지 않습니다. 운영 환경에서는 디버그를 끄며, 명시적인 보안 설정이 없으면 시작을 거부합니다. |
| 검증 |
인증 실패, CSRF 403, 타인 객체 404, 잘못된 업로드·WebSocket 거부와 비밀번호 로그 비노출을 자동 확인했습니다. 의도적 운영 500 화면과 배포 로그 표본은 종합 검증에서 수동 확인합니다. |
| 잔여 위험 |
새 라이브러리와 예외 처리 코드가 민감값을 자동 출력할 수 있어 정기적인 로그 표본 점검이 필요합니다. |
VULN-07. 신뢰되지 않은 프록시 헤더
| 항목 |
내용 |
| 식별자 |
VULN-07 |
| 발견 단계 |
설계·구현·테스트 |
| 위험 |
애플리케이션이 모든 X-Forwarded-* 값을 신뢰하면 외부 사용자가 HTTPS 여부나 Host 정보를 위조해 리다이렉트·CSRF·출처 판단을 우회할 수 있습니다. |
| 영향 |
HTTPS 강제, Host 검증, CSRF 출처와 보안 쿠키 판단 |
| 발견 당시 상태 |
프록시 헤더 신뢰를 켜면 전달된 Host까지 사용했으며 실제 프록시 주소를 제한하는 설정이 없었습니다. |
| 개선 조치 |
전달된 Host는 사용하지 않으며, 프록시 헤더를 켤 때는 IP 리터럴 allowlist를 반드시 요구합니다. 첫 미들웨어는 허용된 프록시가 정확히 단일 https를 주장한 경우만 받아들이고 나머지 전달 헤더는 제거합니다. 운영 CSRF 출처에는 명시적인 HTTPS 값만 허용합니다. |
| 검증 |
tests/security/config/test_proxy_headers.py의 정상·비허용 IP·다중 프로토콜·잘못된 IP 테스트와 check --deploy를 실행했습니다. |
| 잔여 위험 |
실제 배포 프록시가 클라이언트 전달 헤더를 덮어쓰는지와 TLS 종단 IP가 allowlist와 일치하는지는 배포 환경에서 다시 확인해야 합니다. |
VULN-08. 운영 데이터베이스 TLS 설정 하향
| 항목 |
내용 |
| 식별자 |
VULN-08 |
| 발견 단계 |
구현·검토 |
| 위험 |
운영 설정이 PostgreSQL TLS 모드를 disable, allow, prefer로 받아들이면 데이터베이스 인증정보와 서비스 데이터가 평문 연결로 전송될 수 있습니다. |
| 영향 |
사용자·상품·채팅·신고 등 PostgreSQL에 저장되는 모든 데이터 |
| 발견 당시 상태 |
환경 변수의 값을 검증하지 않고 libpq sslmode에 그대로 전달했습니다. |
| 개선 조치 |
알려진 libpq 모드만 허용합니다. 운영 환경에서 허용하는 최소 수준은 require이며, 허용 목록은 require, verify-ca, verify-full뿐입니다. 개발·테스트 환경에서 명시한 disable은 로컬 격리 실행에만 남겼습니다. |
| 검증 |
세 가지 하향 모드를 각각 운영 설정에 넣었을 때 시작이 거부되는지 자동 테스트하고, 허용된 TLS 설정으로 check --deploy를 실행했습니다. |
| 잔여 위험 |
require는 암호화하지만 서버 신원까지 검증하지 않으므로 실제 운영에서는 CA와 호스트명을 검증하는 verify-full을 우선 적용해야 합니다. |
6.2 검증 과정에서 보완한 항목
| 항목 |
발견 당시 상태 |
조치와 확인 |
| 개발·검증 의존성 |
pytest 의존성에서 알려진 취약점이 확인되었습니다. |
pytest 9.0.3 적용 뒤 모든 의존성 그룹에서 알려진 취약점이 없음을 확인했습니다. |
| DEBUG 정적 자산 |
채팅 JavaScript 자산의 개발 환경 제공을 확인할 필요가 있었습니다. |
/static/chat/chat.js가 HTTP 200과 text/javascript로 응답함을 확인했습니다. |
| 미디어 저장 경계 |
정식 릴리스의 유효 이미지 등록이 쓰기 권한 오류로 500을 반환해 핵심 기능을 사용할 수 없고 DEBUG 오류 화면에 내부 경로가 표시됐습니다. |
앱 사용자 소유 미디어 디렉터리와 영속 볼륨을 추가하고 유효 이미지 등록·조회·재시작 지속성을 확인했습니다. |
| 준비 상태 실패 시간 |
PostgreSQL 중단 시 준비 상태 요청이 3초를 초과해 장애 판정이 지연됐습니다. |
호스트명 해석을 0.25초로 제한하고 모든 확인 주소를 시도하는 단일 비동기 PostgreSQL 쿼리에 1.5초 전체 제한을 적용해 0.271초 JSON 503과 복구 후 200을 확인했습니다. |
6.3 2차 위협 모델과 현재 통제
아래 세 항목은 2차 기능을 구현하기 전에 작성한 위협 분석을 현재 코드 기준으로 갱신한 것입니다. 제품 코드는 main에 반영됐지만, 모든 세부 경계·장애 시나리오를 같은 조건으로 재실행했다는 뜻은 아니므로 상태와 잔여 검증을 분리합니다.
VULN-09. 모의 이체의 중복·부분 처리와 잔액 불일치
| 항목 |
내용 |
| 식별자 |
VULN-09 |
| 발견 단계 |
2차 요구사항·설계 |
| 위험 |
재전송, 같은 멱등성 키의 변조, 잔액 확인과 차감 사이의 경합, 반대 방향 교착, 처리 중 종료가 중복 이체·음수 잔액·한쪽만 반영된 원장을 만들 수 있습니다. |
| 영향 |
모의 계정 잔액, 이체 결과, 감사와 복구 가능성 |
| 구현 상태 |
이체 모델·마이그레이션·서비스·화면이 구현되어 있습니다. 화면·HTTP 입력은 1~99,999,999 정수 원화이고 내부 원장·canonical payload는 Decimal(12,2) 둘째 자리를 유지합니다. |
| 개선 조치 |
세션 사용자를 송신자로 고정하고 양쪽 활성·미종료 상태를 잠금 안에서 재검사합니다. 초기 SEED_ISSUE는 사용자 +100,000.00과 비공개 SEED_RESERVE -100,000.00의 합계 0 journal이며 계정당 한 번만 발행합니다. |
| 동시성·불변성 |
safety shared lock 뒤 멱등 lock으로 저장 결과를 먼저 조회하고 새 키만 OPEN을 확인한 뒤 계정 PK lock을 얻습니다. 따라서 BLOCKED 중 저장된 같은-payload 201·422는 재현하지만 새 이체는 막습니다. deferred trigger는 모든 journal의 정확히 두 entry·합계 0을 검증하고 journal/entry UPDATE·DELETE trigger가 변경을 막습니다. |
| 실패·복구 |
대사·재개는 exclusive safety lock으로 이체·종료와 직렬화합니다. 불일치는 incident와 함께 시스템을 BLOCKED로 만들며 maintainer만 전체 불일치 0건을 확인해 재개합니다. |
| 구현 뒤 필수 검증 |
비정상 journal 커밋, journal/entry 변경, canonical/병렬 이체, BLOCKED barrier 경합, BLOCKED 중 저장 201·422 재현과 새 키 503, 총 4회 재시도, 무권한·불완전·정상 복구를 확인합니다. |
| 잔여 위험 |
DB 운영자 권한 탈취와 애플리케이션 밖의 직접 변경은 애플리케이션 통제만으로 완전히 막을 수 없어 최소 DB 권한, 백업·복원, 정기 reconciliation이 필요합니다. |
| 계정 수명 |
SEED_ISSUE 100,000.00은 계정당 한 번만 발행합니다. 인증된 소유자가 잔액 0에서 계정 행 잠금으로 닫고 원장·감사는 보존하며, 닫힌 계정의 송수신은 거부합니다. |
| 상태 |
구현됨·PR #43의 unit/integration/security CI PASS, 상세 경계·장애 재검증 필요 |
VULN-10. 검색을 통한 비노출 정보 유출과 자원 고갈
| 항목 |
내용 |
| 식별자 |
VULN-10 |
| 발견 단계 |
2차 요구사항·설계 |
| 위험 |
공개 여부보다 검색을 먼저 적용하거나 결과 수·페이지 경계를 잘못 계산하면 비노출 상품의 존재가 드러납니다. 임의 정렬, 주입 문자열, 긴 검색어와 큰 페이지는 DB 부하와 불안정한 결과를 만듭니다. |
| 영향 |
제재된 상품의 기밀성, 목록 무결성, PostgreSQL 가용성 |
| 구현 상태 |
검색 전용 서비스·URL·화면과 NFC migration·DB CHECK가 구현되어 있습니다. |
| 개선 조치 |
기존 상품 제목·설명을 NFC backfill하고 쓰기 서비스 정규화와 DB CHECK로 저장 NFC를 강제합니다. q도 trim→NFC·0~100자로 제한하고 공개 범위, allowlist, 1..500 페이지를 적용합니다. |
| 구현 뒤 필수 검증 |
저장/검색 NFC·NFD 네 조합, raw DB NFD 거부, 길이, 비노출, 필터·정렬, 500/501와 서비스 2-query 예산을 확인합니다. |
| 잔여 위험 |
여러 출처의 분산 저속 검색과 인기 검색 조합의 비용 증가는 완전히 제거할 수 없어 지연 시간·거부율·고비용 질의 지표를 관찰해야 합니다. |
| 상태 |
구현됨·PR #43의 unit/integration/security CI PASS, query budget·세부 경계 재검증 필요 |
VULN-11. 관리자 권한 상승과 감사 기록 훼손
| 항목 |
내용 |
| 식별자 |
VULN-11 |
| 발견 단계 |
2차 요구사항·설계 |
| 위험 |
is_staff만 확인하거나 기본 CRUD를 노출하면 역할 밖 객체 변경, CSRF, 탈취된 오래된 세션 사용, stale write, 영구 삭제, 감사 변조와 민감정보 열람이 가능합니다. |
| 영향 |
사용자·상품·신고 상태, 감사 무결성, 비밀번호·세션·채팅 개인정보 |
| 구현 상태 |
관리 모듈·권한 seed·관리 URL·화면이 구현되어 있습니다. |
| 개선 조치 |
일반 작업은 codename+대상 grant, scope 변경은 superuser+직접 permission을 요구합니다. scope도 재인증·사유·version을 검사하며 최초·복구 permission은 전용 DB 역할과 bootstrap advisory lock을 사용해 유효 최고관리자 0명 재검사, permission, 감사를 한 트랜잭션으로 처리합니다. grant 취소는 세션을 무효화하고 감사 역할은 SELECT·INSERT만 허용합니다. |
| 명시적 금지 |
비밀번호 hash·세션·비밀값·채팅 본문 열람, 잔액·원장·감사 수정·삭제, 영구 삭제와 break-glass 우회를 허용하지 않습니다. |
| 구현 뒤 필수 검증 |
codename·grant 교차, 정확한 query/form·302/403/404/409/503, grant 취소 세션, 299/300/301초, 정규화 사유 경계, stale version, 동시 bootstrap 단일 승자와 감사 실패 롤백, 성공·거부·충돌 감사 1건, 감사 INSERT 실패 503·업무/DB감사 0건, 병렬 적용/해제와 만료 직전/정확/직후 응답·기록 수를 확인합니다. |
| 잔여 위험 |
잘못된 범위 부여와 관리자 계정 탈취는 남으므로 강한 인증, 최소 grant 정기 점검, 반복 거부·권한 변경 경보가 필요합니다. |
| 상태 |
구현됨·PR #43의 unit/security CI PASS, 전체 HTTP·감사 장애·경합 재검증 필요 |
2차 보안 검증 계획
| 영역 |
계획된 음성·경계·경합 검증 |
필요한 근거 |
현재 상태 |
| 이체 |
초기 균형 발행, 금액·잔액 상한, canonical payload, 같은 키 병렬, 종료-이체, 허용 SQLSTATE 총 4회, 차단·복구 |
전후 잔액, journal 합계, incident/state, 이체·감사 수 |
구현됨·세부 재검증 필요 |
| 검색 |
NFC·code point 길이, 비노출, 필터·정렬, 500/501, 동률·페이지, 서비스 query budget |
상태 코드·결과 ID, 공개 fixture, 측정 범위와 질의 수 |
구현됨·세부 재검증 필요 |
| 관리자 |
codename/grant, 302/403/404, grant 취소, 299/300/301초, 사유, 제재 경합·만료, 감사 실패 |
역할·grant fixture, 고정 시각, 상태·기록 수, DB 권한 거부 |
구현됨·세부 재검증 필요 |
| 공통 상태 |
휴면 전환·만료 직전/직후의 이체·검색·관리 요청 |
DB 시각, 공통 상태 정책 호출 경로, HTTP 결과와 불변 데이터 |
미실행 |
| 복구·관찰 |
트랜잭션 kill·DB 재시작, 원장 reconciliation, 고비용 검색, 반복 권한 거부 |
오류 분류·correlation, rollback/복구 결과, 민감값 없는 로그·경보 |
미실행 |
각 증거에는 검증 대상 버전, 환경, 도구 버전, 실행 절차, 기대값·실제값, 실패 뒤 수정과 재실행을 함께 기록해야 합니다. 비밀번호·세션·원문 IP·검색어 원문·채팅 본문은 증거나 로그에 남기지 않습니다. 미해결 높은 위험, 잔액-원장 불일치, 권한 우회, 비노출 상품 유출 중 하나라도 있으면 해당 기능을 완료 상태로 표시하지 않습니다.
6.4 참고 기준
- KISA 소프트웨어 개발보안 가이드의 입력값 검증, 인증·권한, 오류 처리 원칙
- OWASP ASVS의 인증, 세션, 접근 통제, 검증·인코딩 요구사항
- OWASP File Upload Cheat Sheet와 WebSocket Security Cheat Sheet
공식 자료 링크는 참고 자료에서 확인할 수 있습니다.