권한 검증 위치
한 줄 정의
권한 검증 위치는 인증된 사용자가 특정 리소스에 접근 가능한지 확인하는 책임을 Controller, Service, Query, 공통 보안 계층 중 어디에 둘지 정하는 설계 문제다.
실무에서 왜 문제 되는가
- 권한 검증이 여러 계층에 흩어지면 어떤 API가 안전한지 확인하기 어렵다.
- Controller에서만 검증하면 내부 서비스 호출이나 배치 경로에서 누락될 수 있다.
- Query 조건에 소유권을 넣지 않으면 조회 후 필터링 과정에서 데이터 노출 위험이 생긴다.
- 공통 어노테이션만 사용하면 리소스 소유권처럼 데이터 기반 권한을 표현하기 어렵다.
동작 원리
- 요청의 인증 정보를 공통 필터나 인터셉터에서 확인한다.
- 기능 단위 권한은 Controller 또는 method security에서 빠르게 차단한다.
- 리소스 소유권과 상태 기반 권한은 Service에서 업무 규칙으로 검증한다.
- 목록 조회나 검색은 Query 조건에 접근 가능한 범위를 포함한다.
- 권한 실패는 일관된 예외와 로그로 처리한다.
실무 판단 기준
| 검증 대상 | 적절한 위치 | 이유 |
|---|---|---|
| 로그인 여부 | Filter, Interceptor | 대부분의 요청에 공통으로 적용된다 |
| 기능 role | Controller, method security | API 진입 지점에서 빠르게 차단한다 |
| 리소스 소유권 | Service | 업무 규칙과 함께 판단해야 한다 |
| 목록 조회 범위 | Query 조건 | 권한 없는 데이터를 애초에 조회하지 않는다 |
| 관리자 예외 정책 | Service | role과 리소스 상태를 함께 판단한다 |
자주 나는 실수
@PreAuthorize("isAuthenticated()")만 붙이고 소유권 검증을 끝냈다고 생각한다.- 목록 API에서 전체 데이터를 조회한 뒤 애플리케이션에서 필터링한다.
- Service 내부 메서드가 다른 진입점에서도 호출된다는 점을 고려하지 않는다.
- 관리자 role이면 모든 리소스 접근을 허용한다.
- 권한 실패 로그에 민감한 요청 값을 그대로 남긴다.
확인 방법
- 테스트: 소유자가 아닌 사용자가 단건 조회, 목록 조회, 수정, 삭제를 모두 실패하는지 확인한다.
- 테스트: 관리자 예외가 필요한 기능과 필요 없는 기능을 분리해 검증한다.
- 코드 리뷰: 권한 조건이 Controller, Service, Query 중 어디에서 보장되는지 추적한다.
- 로그: 권한 실패 시 사용자 id, 리소스 id, 정책 이름, trace id를 남긴다.
장점과 한계
| 방식 | 장점 | 한계 |
|---|---|---|
| 공통 필터 | 로그인 여부를 일관되게 확인한다 | 리소스별 권한은 알기 어렵다 |
| Controller 검증 | API 진입점에서 의도가 보인다 | 내부 호출이나 재사용 경로에서 누락될 수 있다 |
| Service 검증 | 업무 규칙과 함께 판단할 수 있다 | 반복 코드가 생길 수 있다 |
| Query 조건 | 권한 없는 데이터 조회 자체를 줄인다 | 조건이 복잡해지면 테스트가 중요하다 |
짧은 예제
public List<OrderSummary> findMyOrders(AuthenticatedUser user, OrderSearchCondition condition) {
return orderQueryRepository.findSummaries(
condition.withOwnerId(user.id())
);
}목록 조회는 조회 후 필터링보다 query 조건에 접근 가능한 범위를 포함하는 방식이 안전하다.
핵심 요약
권한 검증은 한 계층만의 문제가 아니라 요청 진입, 업무 규칙, 조회 조건에 걸친 설계 문제다.
로그인 여부는 공통 계층에서 처리할 수 있지만 리소스 소유권은 업무 규칙과 함께 봐야 한다.
목록 조회는 권한 없는 데이터를 가져온 뒤 제거하는 방식보다 query 조건에 권한 범위를 포함하는 것이 안전하다.
Controller 검증은 의도를 드러내지만 내부 호출 경로까지 보장하지 못할 수 있다.
Service 검증은 반복될 수 있으므로 정책 메서드나 도메인 규칙으로 정리할 수 있다.
권한 실패는 403으로 처리하고 감사 가능한 최소 정보만 로그에 남긴다.
꼬리 질문
- 권한 검증은 Controller와 Service 중 어디에 두는 것이 좋은가?
- 목록 조회에서 권한 검증을 어떻게 보장할 것인가?
- 공통 보안 어노테이션으로 해결하기 어려운 권한은 무엇인가?