주의
이 책은 Spring Security 5 버전을 기준으로 작성되었으므로, Spring Boot 3.X 버전에서는 일부 클래스가 더 이상 사용되지(deprecated) 않을 수 있습니다.
서론
- 스프링 시큐리티는 앱이 HTTP 엔드포인트를 이용하지 않는 시나리오에도 문제없이 잘 쓸 수 있음
- 메서드 수준에서 권한 부여를 구성하는 방법을 `전역 메서드 보안`이라고 지칭
- 해당 방법으로 웹 애플리케이션과 웹이 아닌 애플리케이션의 권한 부여를 구성할 수 있음
- 웹이 아닌 애플리케이션에서 전역 메서드 보안은 엔드포인트 없이도 권한 부여 규칙을 구현할 수 있게 해 줌
- 웹 애플리케이션에서는 엔드포인트 수준만이 아니라 앱의 다양한 계층에 권한 부여 규칙을 적용하는 유연성을 제공
1. 전역 메서드 보안 활성화
- 전역 메서드 보안은 기본적으로 비활성화 상태이므로 해당 기능을 이용하려면 먼저 활성화해야 함
- 전역 메서드 보안은 또한 여러 방식으로 권한 부여를 적용할 수 있게 해 줌
- 전역 메서드 보안으로 할 수 있는 일은 크게 두 가지
- 호출 권한 부여: 정립된 여러 이용 권리 규칙에 따라 누군가가 메서드를 호출할 수 있는지 (사전 권한 부여) 또는 메서드가 실행된 후 메서드가 반환하는 것에 접근할 수 있는지 (사후 권한 부여) 결정
- 필터링: 메서드가 매개변수를 통해 받을 수 있는 것 (사전 필터링)과 메서드가 실행된 후 호출자가 메서드에서 다시 받을 수 있는 것 (사후 필터링)을 결정
1.1 호출 권한 부여의 이해
- 호출 권한 부여는 전역 메서드 보안과 함께 이용하는 권한 부여 규칙을 구성하기 위한 접근 방식 중 하나
- 호출 권한 부여 방식은 메서드를 호출할 수 있는지를 결정하거나 메서드를 호출하도록 허용한 후 호출자가 메서드에서 반환된 값에 접근할 수 있는지를 결정하는 권한 부여 규칙을 적용하는 것을 말함
- 애플리케이션에서 전역 메서드 보안을 활성화하면 스프링 Aspect 하나가 활성화됨
- 해당 Aspect는 우리가 권한 부여 규칙을 적용하는 메서드에 대한 호출을 가로채고 권한 부여 규칙을 바탕으로 가로챈 메서드로 호출을 전달할지 결정함
- 스프링 프레임워크의 구현은 상당수가 AOP에 의존하는데 전역 메서드 보안 또한 Aspect에 의존하는 스프링 애플리케이션의 많은 구성 요소 중 하나
- 호출 권한 부열을 다음과 같이 간단하게 분류할 수 있음
- 사전 권한 부여 (Preauthorization): 메서드 호출 전에 권한 부여 규칙을 검사하는 프레임워크
- 사후 권한 부여 (Postauthorization): 메서드 호출 후에 권한 부여 규칙을 검사하는 프레임워크
사전 권한 부여로 메서드에 대한 접근 보호
- 누군가가 특정 상황에서 메서드를 호출하는 것을 완전히 금지하는 권한 부여 규칙을 적용할 때 이를 사전 권한 부여라고 함
- 호출자가 우리가 정의한 권한 부여 규칙에 따른 사용 권한이 없으면 프레임워크는 메서드 호출하는 대신 오류를 내뱉음
사후 권한 부여로 메서드 호출 보호
- 메서드를 호출하도록 허용하지만 메서드가 반환한 결과를 얻기 위해 권한 부여가 필요한 방식을 사후 권한 부여라고 함
- 사후 권한 부여에서 스프링 시큐리티는 메서드 호출 후에 권한 부여 규칙을 검사함
- 이러한 유형의 권한 부여를 통해 특정 조건에서 메서드 반환에 대한 접근을 제한할 수 있음
- 사후 권한 부여는 메서드 실행 후에 수행되기 때문에 메서드에서 반환된 결과를 바탕으로 권한 부여 규칙을 적용할 수 있음
- 사후 권한 부여를 적용했을 때 다음과 같은 내용을 주의해야 함
- 메서드가 실행 중에 무엇인가를 변경하면 권한 부여의 성공 여부와 관계없이 이러한 변경 사항이 적용됨
1.2 프로젝트에서 전역 메서드 보안 활성화
- 스프링 시큐리티에서 전역 메서드 보안을 활성화하기 위해서는 구성 클래스에 @EnableGlobalMethodSecurity 어노테이션을 추가하면 됨
- 전역 메서드 보안에 권한 부여 규칙을 정의하는 세 가지 접근 방식이 있음
- 사전/사후 권한 부여 어노테이션
- JSR 250 어노테이션 (@RolesAllowed)
- @Secured 어노테이션
- HTTP Basic 인증에서 OAuth 2에 이르기까지 모든 인증 방식에 전역 메서드 보안을 사용할 수 있음
2. 권한과 역할에 사전 권한 부여 적용
- 복습하자면 사전 권한 부여는 스프링 시큐리티가 특정 메서드를 호출하기 전에 적용하는 권한 부여 규칙을 정의하는 것
- 해당 규칙이 준수되지 않으면 프레임워크는 메서드를 호출하지 않음
- 이 절에서 구현하는 애플리케이션은 "Hello, "에 이름을 더한 문자열을 반환하는 /hello 엔드포인트를 노출
- 컨트롤러가 이름을 얻으려면 서비스 메서드를 호출해야 함
- 해당 메서드는 사용자에게 쓰기 권한이 있는지 확인하는 사전 권한 부여 규칙을 적용
- 사용자 엠마로 인증하면 정상적으로 응답을 반환하지만 사용자 나탈리로 인증하면 403 Forbidden 오류 발생
3. 사후 권한 부여 적용
- 메서드 호출 후에 권한 부여 규칙을 적용하고 싶다면 사후 권한 부여를 이용하면 됨
- 메서드가 수행하는 일은 명확하지만 메서드를 호출하는 상대에 관해서는 확신할 수 없을 때 메서드 실행은 허용하되 반환되는 내용을 검증하고 기준이 충족되지 않으면 호출자가 반환 값에 접근하지 못하게 할 수 있음
- 스프링 시큐리티로 사후 권한 부여를 적용하려면 @PostAuthorize 어노테이션을 이용함
- 해당 어노테이션은 @PreAuthorize와 비슷하며 권한 부여 규칙을 정의하는 SpEL을 값으로 받음
- 아래 예제 코드에서 Employee 객체가 정의되어 있고 Employee에는 이름, 책의 목록, 권한의 목록이 들어 있으면 각 애플리케이션 사용자에게 하나씩 Employee를 연결함
- 해당 예제에서 원하는 것은 메서드의 호출자가 읽기 권한이 있는 직원의 세부 정보만 얻을 수 있게 하는 것
- 레코드를 검색하기 전에는 직원 레코드와 연결된 권한을 알 수 없으므로 메서드 실행 후 권한 부여 규칙을 적용해야 하기 때문에 @PostAuthorize 어노테이션을 이용해야 함
4. 메서드의 사용 권한 구현
- 복잡한 권한 부여 규칙을 구현해야 할 때는 긴 SpEL 식을 작성하지 말고 논리를 별도의 클래스로 만들어야 함
- 스프링 시큐리티의 사용 권한 개념으로 권한 부여 규칙을 별도의 클래스로 작성하면 애플리케이션을 읽고 이해하기 쉽게 만들 수 있음
- 이 절에서는 프로젝트에서 사용 권한으로 권한 부여 규칙을 적용함
- 이 예제는 문서를 관리하는 애플리케이션이며 모든 문서에는 해당 문서를 작성한 사용자인 소유자가 있음
- 기존 문서의 세부 정보를 얻으려면 사용자는 관리자이거나 해당 문서의 소유자여야 함
- 위 요구 사항을 해결하기 위해 사용 권한 평가기를 구현
- 사용 권한 논리를 구현할 책임은 개발자에게 있으며 이를 위해 PermissionEvaluator 계약을 구현하는 객체를 작성해야 함
- PermissionEvaluator 계약으로 사용 권한 논리를 구현하는 방법은 두 가지가 있음
- 객체 사용 권한: 사용 권한 평가기는 두 객체 (권한 부여 규칙의 주체가 되는 개체와 사용 권한 논리를 구현하기 위한 추가 세부 정보를 제공하는 객체)를 받음
- 객체 ID, 객체 형식, 사용 권한: 사용 권한 평가기는 필요한 객체를 얻는 데 이용할 수 있는 객체 ID를 받음, 또한 같은 권한 평가기가 여러 객체 형식에 적용될 때 이용할 수 있는 객체 형식을 받으며 사용 권한을 평가하기 위한 추가 세부 정보를 제공하는 객체가 필요함
- 예제에서는 첫 번째 메서드만 사용하면 됨
- 주체는 이미 있기 때문에 이 경우 메서드가 반환하는 값이 주체
- 또한 예제의 시나리오에 정의된 값이며 모든 문서에 접근할 수 있는 역할 이름은 'ROLE_admin'을 보냈음
- 물론 이 예제에서 사용 권한 평가기 클래스에 역할 이름을 직접 이용하면 hasPermission() 객체의 값으로 보낼 필요가 없었을 것
- 실제 시나리오는 여러 메서드가 있고 권한 부여 프로세스에 필요한 세부 정보도 각기 달라서 더 복잡할 수 있기 때문에 메서드 수준에서 권한 부여 논리에 이용하는 데 필요한 세부 정보를 보낼 수 있는 매개변수가 있음
- 스프링 시큐리티는 hasPermission() 메서드를 호출할 때 자동으로 Authentication 객체를 매개변수 값으로 제공하기 때문에 Authentication 객체를 직접 전달할 필요 없음
- 이미 SecurityContext에 있으므로 프레임워크는 인증 인스턴스의 값을 알 수 있음
- 스프링 시큐리티가 새 PermissionEvaluator 구현을 인식할 수 있도록 구성 클래스에 MethodSecurityExpressionHandler를 정의해야 함
- 아래 에제 코드에는 맞춤형 PermissionEvaluator를 알리기 위해 MethodSecurityExpressionHandler를 정의하는 방법이 나옴
- 실행되기 전에 권한 부여 규칙을 적용하도록 현재 예제를 변경한다면 첫 번째 메서드 대신 두 번째 메서드를 사용해야 함
- 이때는 아직 반환된 객체는 없지만 객체 자체 대신 고유 식별자인 문서의 코드가 있음
참고
스프링 시큐리티 인 액션
반응형
'Spring > 스프링 시큐리티 인 액션' 카테고리의 다른 글
[17장] 전역 메서드 보안: 사전 및 사후 필터링 (0) | 2025.06.05 |
---|---|
[15장] OAuth 2: JWT와 암호화 서명 사용 (0) | 2025.06.01 |
[14장] OAuth 2: 리소스 서버 구현 (0) | 2025.06.01 |
[13장] OAuth 2: 권한 부여 서버 구현 (0) | 2025.06.01 |
[12장] OAuth 2가 작동하는 방법 (0) | 2025.05.31 |