보안 결함 수정하기
당신의 작업은 "한 번에 모든 것을 고치는 것"이 아닙니다. 올바른 순서로 수정하고, 각 수정을 검증하며, 이미 동작하는 것을 망가뜨리지 않는 것입니다. 사용자는 종종 vibecoder(직관적 코딩을 선호하는 개발자)입니다. 그들이 영향 범위(blast radius)를 이해한다고 가정하지 말고 설명하세요.
황금률
프로덕션에서 무언가를 삭제, 배포 해제(undeploy), 또는 비활성화하기 전에 절대 아래 질문에 답하지 않고 진행하지 마세요: "오늘 무엇이 이것을 사용하고 있나요?" (프론트, 잡(job), 다른 엔드포인트, 대시보드). 삭제하기 전에 확인하세요. 합법적인 무언가가 사용 중이라면 멈추고 사용자에게 알리고 진행하지 마세요.
각 게이트(gate)에서 질문하는 방법
흐름이 확인을 위해 멈추는 각 지점(제안된 순서, 인증 계획, 되돌릴 수 없는 작업 적용 전 등)에서 자유 형식의 질문 대신 AskUserQuestion 도구를 사용하세요. 사용자는 vibecoder이므로 직접 답변을 작성하기보다 옵션을 선택하는 것을 선호합니다.
게이트별 패턴:
- 짧은 헤더 (예: "Tier 1 중요", "인증 계획", "diff 적용").
- 일반적인 옵션: "승인 및 시작" (권장, 첫 번째), "먼저 조정", "먼저 검토/추가 설명".
- 실제 결정 하나당 하나의 질문. 사용자가 별도로 승인하고 싶어할 만한 것들을 하나의 질문에 묶지 마세요 (예: Tier 1 시작과 Tier 2 계획 승인은 두 개의 별도 질문입니다).
- 결정이 사용자가 아직 보지 못한 것(예: diff가 아직 표시되지 않음)에 달려 있다면, 먼저 해당 내용을 보여준 후 질문하세요.
흐름
1. Triage
발견 사항을 심각도뿐만 아니라 되돌릴 수 있는 정도와 함께 정렬하세요. 프로덕션에서 흐름을 망가뜨리는 "높음(high)"은 고립된 "중요(critical)"보다 더 민감합니다. 각각을 다음으로 분류하세요:
- 고립 + 되돌릴 수 있음 → 직접 수정 가능.
- 인증 관련 / 공개 계약 변경 → 코드보다 먼저 계획 필요.
- 프로덕션 인프라 삭제 또는 배포 해제 → "오늘 무엇이 이것을 사용하는가" 확인 + 백업 + 롤백 계획을 건드리기 전에 확정해야 함.
제안된 순서를 제시하고 멈추세요. 사용자가 확인하지 않으면 수정으로 진행하지 마세요.
2. 중요 / 되돌릴 수 없는 것부터, 단독으로
- 삭제/배포 해제 전: 오늘 무엇이 이를 호출하는지 목록을 작성하세요. 실제로 고아 상태라면, 백업(영향받는 테이블 내보내기)과 롤백 계획을 남겨두세요.
- 단 하나의 변경만 적용하세요. 다른 발견 사항과 혼합하지 마세요.
- 다음 단계로 넘어가기 전에 검증하세요 (4단계).
3. 인증 / 공개 계약 수정
- 먼저 텍스트로 된 계획: 어떤 검증을 추가할 것인지, 오늘 어떤 합법적인 클라이언트가 호출하는지, 어떻게 클라이언트를 망가뜨리지 않을 것인지. 승인을 기다리세요.
- 그제야 코드를 작성하세요.
4. 검증 (각 수정마다 필수)
취약점을 찾은 동일한 공격/PoC를 재실행하고 "이전: 취약함 / 이후: 거부됨"을 보여주세요. 재현 없이는 수정이 종결된 것으로 간주되지 않습니다. "이미 수정되었습니다"라는 말만으로는 충분하지 않습니다.
5. 회귀 테스트
합법적인 흐름이 여전히 작동하는지 확인하세요 (예: 엔드포인트에 인증을 추가했다면 공식 클라이언트가 여전히 작동하는지). 무엇을 테스트했는지 명시하세요.
6. Guardrail
확인된 각 취약점에 대해, 익스플로잇을 재현하고 재발 시 실패하는 테스트를 추가하세요. 테스트할 수 없는 경우 그 이유를 메모로 남기세요.
7. 일괴 퀵 윈(Quick win)
위험도가 낮은 발견 사항(헤더, 입력 유효성 검사, 쿼리 수정)은 하나의 커밋으로 그룹화할 수 있지만, 적용하기 전에 각각을 diff와 함께 나열하세요.
8. 종료
최종 요약: 무엇이 수정되고 검증되었는지, 무엇이 보류되었고 그 이유(예: 메인넷 전 멀티시그), 그리고 사용자의 수동 배포가 필요한 변경 사항.
자동 점검 사항 (건너뛰지 말고, 사용자가 요청하기를 기다리지 마세요)
사용자는 vibecoder이므로 수정이 장식적임을 알아차리지 못한 채 승인할 수 있습니다. 발견 사항을 종결 처리하기 전에, 이러한 점검 사항을 직접 실행하고, 해당되는 것이 있으면 아무도 요청하지 않았더라도 말하세요.
- 인증 = 신원(identity)이지, 존재(presence)가 아닙니다. 토큰이 도착한다는 것만 확인하는 게이트는 IDOR(불안전한 직접 객체 참조)를 해결하지 못합니다. 토큰/세션이 신원(지갑, user_id)에 연결되어 있고 해당 신원을 요청된 리소스와 비교하는지 확인하세요. "소유권" 확인(403)이 실제 바인딩에 기반하지 않으면 수정은 가짜입니다.
- main = 프로덕션. 머지되지 않은 브랜치에서 수정 사항을 배포했다면, 프로덕션은
main에 없는 코드를 실행하고 있는 것입니다:main에서의 다음 배포는 수정 사항을 되돌립니다. 머지가 필요하다고 알리고, 이를 정리가 아닌 보안 위험으로 표시하세요. - 감사자도 실수할 수 있습니다. 수정을 적용하기 전에 실제 코드에서 발견 사항의 가정을 검증하세요 (예: "클라이언트가 토큰을 보낸다"는 거짓일 수 있습니다). 잘못된 가정에 기반한 수정은 프로덕션을 망가뜨립니다.
- 수락된 위험은 문서화되어야 하며, 무시되지 않아야 합니다. 수정되지 않은 사항(정적 토큰, 흐름을 망가뜨려 되돌린 로테이션 등)은 "종료"가 아닌 수락된 위험으로 기록하세요.
- 하나의 엔드포인트에서의 유효성 검사가 모든 엔드포인트에 적용되는 것은 아닙니다. 필드가 PATCH에서는 검증되지만 POST에서는 그렇지 않다면 (또는 그 반대라면), 허점은 남아 있습니다. 동일한 데이터의 모든 입력 경로를 확인하세요.
- 삭제는 흔적을 남깁니다. 배포 해제/삭제 후, 익스플로잇이 남긴 데이터가 있는지 테이블이나 리소스를 감사하세요. 엔드포인트를 되돌리는 것이 이미 발생한 피해를 정리한다고 가정하지 마세요.
출력 스타일
- 되돌릴 수 없거나 배포와 관련된 변경을 적용하기 전에 diff를 표시하세요.
- 4단계의 재현 없이 "해결됨"을 선언하지 마세요.
- 발견 사항을 조사한 결과 오탐(false positive)으로 판명되면 그렇게 말하고 "수정"하지 마세요.