"URL에서 id=124를 125로 바꿨더니 남의 청구서가 나타났다" — 그것이 IDOR(취약한 접근 제어)입니다. 작동 원리와 확실히 막는 법을 살펴봅니다(공격 절차는 다루지 않습니다).
왜 일어나는가
인증(당신이 누구인가)은 통과하지만, 인가(이것을 해도 되는가)가 빠진 것입니다. 인증과 인가는 다릅니다 — 로그인할 수 있다고 해서 그 데이터를 봐도 된다는 뜻은 아닙니다.
| 흔한 빈틈 | 결과 |
|---|---|
| 로그인 후 ID를 그대로 신뢰 | 다른 사용자의 ID로 바꾸면 그대로 통과 |
| "UI에 안 보임 = 안전" 오해 | API를 직접 치면 활짝 열려 있음 |
| 생성/수정/삭제에 권한 검사 없음 | 조회뿐 아니라 — 변조와 삭제까지 |
왜 통하는가
방어: 매번 서버 측에서 소유권/권한을 검증하라
객체별 소유권/권한 검사(가장 중요)
데이터를 반환하거나 수정하기 직전에, 로그인된 사용자가 그 객체를 소유하거나 권한이 있는지를 서버 측에서 검증하세요. 아니면 거부합니다. 예를 들어 청구서 125를 불러올 때, "125가 존재하는가"만이 아니라 "125가 지금 로그인된 사용자의 것인가"까지 같은 요청 안에서 확인해야 합니다.
기본 거부
새 엔드포인트는 "명시적으로 허용된 것 외에는 전부 거부"에서 출발해, 잊은 검사가 열린 채가 아니라 닫힌 채로 실패하게 하세요.
'자기 것'인 행만 조회
소유자 조건을 쿼리 자체에 녹이세요(예: 현재 사용자 id로 필터). 이렇게 하면 권한 없는 행은 애초에 결과에 포함되지 않으므로, 검사를 빠뜨려도 데이터가 새지 않습니다. 모든 것을 하나의 공유 인가 헬퍼로 통과시켜 어느 호출 지점도 빠뜨리지 않게 하세요.
UI 제어를 방어로 착각하지 않기
버튼을 숨기는 것은 UX이지 보안이 아닙니다. API가 직접 호출된다고 가정하고 서버에서만 결정하세요. 랜덤 ID는 보조로 두되, 통제 수단으로 두지 마세요.
본 사이트의 견해: 수수하지만 영향은 최대 — 테스트로 지켜라
IDOR은 기술적으로 밋밋해 코드 리뷰에서 놓치기 쉽지만, 영향은 최상급입니다("한 번의 클릭으로 모두의 개인 데이터가 드러남"). 그래서 실용적인 동작은 자동화된 테스트를 못 박는 것입니다: 다른 사용자로서 남의 ID를 치면 반드시 403을 반환해야 한다. 본 사이트의 원칙은 "클라이언트 UI에서 절대 방어하지 않고, 서버에서만 결정한다"입니다. 인가는 매 요청마다 메커니즘으로 강제되어야 하며 — 결코 사람의 주의력에 맡겨서는 안 됩니다.
다음으로 읽기
- 용어집: CSRF란(인증 vs 인가)
- 기초: 보안 기초 · 무료 보안 도구
FAQ
QIDOR로 무슨 일이 일어나나요?
로그인된 사용자가 URL이나 API의 ID(?id=124를 다른 값으로)를 바꿔 남의 청구서, 주문, 개인 데이터, 파일을 보거나 편집하거나 삭제합니다. 가장 흔한 결함 범주(취약한 접근 제어)의 대표 격이며, 특별한 도구가 필요 없다는 점에서 무섭습니다.
Q최우선 방어책은 무엇인가요?
매 요청마다 서버 측에서 '이 로그인된 사용자가 이 객체에 대해 행동해도 되는가?'를 검증하세요. ID의 형식이 올바르더라도 소유권/권한을 확인하고, 없으면 거부하세요(기본 거부). 클라이언트 측 UI 숨김에 절대 의존하지 마세요.
QUUID나 랜덤 ID로 막을 수 있나요?
ID를 추측하기 어렵게 만들 뿐 — 진짜 해결책은 아닙니다. ID가 유출되거나 공유되면 그대로 통과합니다. 무작위화는 보조로 두고, 진짜 방어는 항상 서버 측 소유권/권한 검사입니다.