어떤 스캐너도 이해하지 못하는 권한 부여(Authorization) 버그
요약
권한 부여(Authorization)는 구문이 아닌 비즈니스 의도에 기반한 의미론적 속성이기에 기존 패턴 스캐너로는 탐지가 어렵습니다. 특히 AI가 생성한 코드는 그럴듯해 보이지만 실제 비즈니스 로직과 맞지 않는 잘못된 검사 로직을 포함할 위험이 큽니다.
핵심 포인트
- 권한 부여는 코드의 구조가 아닌 비즈니스 규칙(의도)에 의존함
- 패턴 스캐너는 구조적 결함은 찾지만 의미론적 오류는 식별 불가
- AI 생성 코드는 형식적으로 완벽해 보이지만 잘못된 권한 검사를 포함할 수 있음
- 존재하지만 잘못된 검사는 누락된 검사보다 탐지 및 식별이 더 어려움
권한 부여(Authorization)는 무엇에 누가 접근해야 하는지에 대한 사실, 즉 구문(Syntax)이 아닌 의도(Intent)에 관한 것입니다. 패턴 스캐너는 실행되는 코드 경로를 보지만, 그 경로가 강제하려고 했던 의도는 결코 보지 못합니다. 이것이 바로 취약한 접근 제어(Broken Access Control)가 OWASP의 #1 웹 리스크인 이유이며, 어떤 스캐너도 이를 안정적으로 잡아내지 못하는 이유입니다. BrassCoders는 구조적 패턴을 식별하지만, 접근 제어 검사가 데이터 모델에 맞게 올바른지 확인하는 작업은 코드가 무엇을 하려고 의도되었는지 알아야만 가능한 일입니다.
AI가 생성한 코드에서 이 버그가 위험하게 나타나는 버전은 검사(Check)가 누락된 경우가 아닙니다. 검사가 존재하고, 올바르게 보이지만, 실제로는 잘못된 것을 강제하는 경우입니다.
권한 부여가 의미론적 속성(Semantic Property)인 이유
BrassCoders는 구조를 읽지만, 권한 부여 규칙은 의미(Meaning)입니다. if user.id == resource.owner_id:라는 라인은 구문적으로 깔끔하며 정확할 수도 있지만, 만약 당신의 모델이 팀원이 동료의 리소스에 접근하는 것을 허용하거나 리소스에 단일 소유자가 없는 경우라면 완전히 틀린 것이 될 수도 있습니다. 검사가 올바른지 여부는 비즈니스 규칙에 달려 있으며, 그 규칙들은 스캐너가 읽을 수 있도록 코드 안에 들어있지 않습니다.
IDOR는 이러한 간극이 구체화된 사례입니다. 사용자가 요청했을 때 사용자가 41번 객체에 접근할 권한이 있는지 확인하지 않고 41번 객체를 반환하는 엔드포인트가 바로 그것입니다. 객체를 가져오는 코드와 안전하게 가져오는 코드는 거의 동일해 보입니다. 차이점은 권한에 대해 추론하는 검사 여부이며, 이 검사가 없으면 규칙이 일치할 수 있는 구조적 구멍조차 남지 않습니다.
AI 생성 코드가 이 문제를 더욱 날카롭게 만드는 이유
BrassCoders는 AI 생성 코드(AI-generated code)와 함께 이러한 실패 모드(failure mode)가 더욱 심화되는 것을 목격합니다. 그 이유는 어시스턴트가 그럴듯해 보이는 권한 부여 검사(authorization checks)를 작성하기 때문입니다. 사용자의 레코드를 반환하는 엔드포인트(endpoint)를 구축하라는 요청을 받으면, 모델은 검사가 그곳에 있어야 한다는 것을 알고 빈번하게 검사를 추가합니다. 하지만 그 검사가 귀하의 소유권 모델(ownership model)을 강제하는지 여부는 모델이 알 수 있는 방법이 없으며, 모델은 미묘하게 잘못되었지만 자신감 있고 형식이 잘 갖춰진 버전을 생성할 것입니다.
존재하지만 잘못된 검사는 누락된 검사보다 더 위험합니다. 누락된 검사는 최소한 주의 깊은 검토자가 알아챌 수 있는 눈에 띄는 부재이지만, if user.id == record.owner_id:가 필요한 곳에 if user.is_authenticated:라고 읽히는 검사는 마치 성실함을 보여주는 것처럼 보입니다. 그럴듯하지만 부정확한 권한 부여 검사는 AI 생성이 생성하기에 딱 좋은 결과물이며, 올바른 일을 수행하는 것처럼 보이기 때문에 검토를 통과해 버립니다.
패턴 스캐너(Pattern Scanner)가 이를 검증할 수 없는 이유
BrassCoders가 로직 버그(logic bug)를 찾아낼 수 없는 것과 동일한 이유로 잘못된 검사를 표시할 수 없습니다. 올바른 권한 부여와 잘못된 권한 부여는 구조적으로 동일하므로, 일치할 만한 '나쁜 형태(bad shape)'가 존재하지 않습니다. 모든 소유권 비교를 표시하는 규칙은 올바른 것과 잘못된 것을 똑같이 표시하게 되어 노이즈(noise)가 될 것이며, 아무것도 표시하지 않는 규칙은 패턴이 볼 수 있는 것에 대해 진실을 보고하는 스캐너일 뿐입니다.
OWASP는 이것이 바로 취약한 접근 제어(broken access control)가 목록 최상단에 위치하는 이유라고 명시하고 있습니다. 이는 취약점이 인식 가능한 패턴보다는 애플리케이션 특유의 의도(application-specific intent)에 의해 정의되기 때문에 자동화된 탐지가 가장 어려워하는 클래스이기 때문입니다. 규칙을 아무리 많이 작성하더라도 그 선을 넘을 수는 없습니다. 왜냐하면 결여된 지식은 코드 외부에 존재하는 귀하의 권한 부여 모델이기 때문입니다.
검증이 이루어지는 곳
실제로 깨진 접근 제어 (Broken Access Control)를 잡아내는 제어 장치들은 의도(intent)에 대해 추론합니다. 위협 모델링 (Threat modeling)은 코드가 존재하기 전에 누가 어떤 조건 하에 각 리소스에 접근해야 하는지를 열거합니다. 권한 부여 (Authorization) 테스트는 해당 모델을 어설션 (assertion)으로 인코딩합니다. 즉, 잘못된 사용자가 객체를 요청했을 때 반드시 403 응답을 받아야 한다는 식입니다. DAST 및 수동 테스트는 실행 중인 앱에 권한이 없는 요청을 보내고, 해당 요청이 거부되는지 확인합니다.
이 각각의 방식은 스캐너에 결여된 단 한 가지, 즉 '누가 접근 권한을 가져야 하는가'에 대한 명시를 포함하고 있습니다. OWASP의 A01 가이드라인과 테스트 리소스는 이러한 검증을 구축하는 방법에 대한 권위 있는 기준을 제공합니다. 귀하의 권한 부여가 올바른지 확인한다고 주장하는 스캐너가 있다면, 그것은 한 번도 전달받지 못한 소유권 모델 (ownership model)에 대한 지식을 주장하고 있는 셈입니다.
BrassCoders가 다루는 범위
BrassCoders는 접근 제어와 관련된 구조적 발견 사항들 — 하드코딩된 자격 증명 (hardcoded credentials), 안전하지 않은 세션 처리 (insecure session handling), 탐지 가능한 범위 내의 인증 누락 (missing-auth) 패턴 — 을 매 스캔마다 결정론적 (deterministically)으로 잡아냅니다. 이러한 것들은 일정한 형태를 가지고 있으며, AI 어시스턴트들도 정해진 비율로 이를 찾아냅니다. 권한 부여 체크의 의미론적 정확성 (semantic correctness)은 그 상위 계층에 있으며, BrassCoders는 이를 억지로 커버하는 척하는 대신 그 자체를 별개의 계층으로 명시합니다.
이 두 계층은 상호 보완적입니다. 스캐너가 구조적 보안 패턴을 정리하여 리뷰가 해당 패턴들에 파묻히지 않게 하고, 위협 모델링과 권한 부여 테스트는 체크 로직이 실제 모델을 강제하는지 검증합니다. 패턴을 찾기 위해 스캔을 실행하고, 어떤 패턴도 인코딩할 수 없는 '의도'를 확인하기 위해 권한 부여를 테스트하십시오.
pip install brasscoders
brasscoders --offline scan /path/to/your/project
스캔은 자격 증명 및 세션 버그를 잡아냅니다. 존재하지만 잘못된 권한 부여 체크를 잡아내는 것은 테스트 계층의 역할이며, 그 첫 번째 단계는 스캐너가 이를 결코 찾아낼 수 없었다는 사실을 인지하는 것입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기