LabHub

Keycloak 과 기업 인증 · 인증과 인가의 차이 · 이론

IDOR 은 인증이 아니라 인가의 실패다

LabHub 에서 이어서 보기

한 줄 요약

인증은 "당신이 누구인지 확인"이고 인가는 "이 사람이 이 자원에 이 동작을 해도 되는지 판단"이다. 대부분의 실무 사고는 후자에서 난다.

왜 이게 필요했나

로그인은 잘 만들어 놓고 사고가 나는 경우가 많습니다. 사용자는 정상적으로 인증됐고 토큰도 유효합니다. 그런데 /api/orders/1042 의 숫자를 1043 으로 바꾸면 남의 주문이 보입니다.

이것이 IDOR(Insecure Direct Object Reference)입니다. 인증은 통과했지만 인가를 안 한 것입니다. "이 토큰의 주인이 이 주문의 소유자인가"를 아무도 확인하지 않았습니다.

어떻게 동작하나

두 질문을 코드에서 분리해서 생각하는 습관이 필요합니다.

인증은 요청 진입점에서 한 번 합니다. 토큰 서명을 검증하고, 만료를 보고, 주체(sub)를 꺼냅니다. 이 단계는 미들웨어로 처리할 수 있고 자원과 무관합니다.

인가는 자원에 접근하는 지점마다 합니다. 그리고 자원의 소유자나 속성을 알아야 판단할 수 있으므로 미들웨어만으로는 부족합니다. "주문 1043 의 owner_id 가 현재 사용자의 sub 와 같은가"는 그 주문을 읽은 뒤에야 판단할 수 있습니다.

여기서 실무의 규칙이 하나 나옵니다. 조회 쿼리 자체에 소유자 조건을 넣는 것입니다. SELECT * FROM orders WHERE id=? AND owner_id=? 로 쓰면 남의 주문은 애초에 결과가 없습니다. 읽은 뒤 비교하는 방식보다 실수하기 어렵습니다.

역할과 권한도 구분할 만합니다. 역할은 사람에 붙는 이름표(예: order-admin)이고, 권한은 동작에 붙는 이름(예: order:refund)입니다. 역할만으로 인가를 짜면 역할 수가 폭발하고, 권한만으로 짜면 관리가 어렵습니다. 실무는 대개 역할에 권한을 묶고 사용자에게 역할을 줍니다.

현장에서 만나는 모습

토큰에 역할을 담는 것과 매 요청 서버에서 조회하는 것 사이에도 선택이 있습니다. 토큰에 담으면 빠르지만, 역할을 회수해도 토큰이 만료될 때까지 유효합니다. 그래서 액세스 토큰을 짧게 두는 것이 인가 측면에서도 중요합니다.

또 하나 자주 틀리는 곳. 프런트엔드에서 버튼을 숨기는 것은 인가가 아닙니다. UI 는 편의이고, 판단은 반드시 서버에서 다시 해야 합니다. "관리자만 볼 수 있는 화면인데 API 는 열려 있는" 상황이 침투 테스트에서 가장 먼저 나옵니다.

다음 확인에서 볼 것

먼저 퀴즈에서 인증 성공과 자원 인가 성공을 구분할 수 있는지 확인합니다. 다음 모듈에서 OAuth2 그랜트 타입의 지형도를 정리한 뒤 실제 Keycloak 으로 넘어갑니다.