밤빵's 개발일지
[TIL]20241118 Spring Security에서 권한별 URL 접근 제어에 대한 고민 본문
Spring Security를 사용하면서, 한 유저에게 부여된 권한에 따라 접근 가능한 URL을 나누고자 한다. 예를 들어, guest, user, admin과 같은 권한을 나눠서, user 권한이 있는 사람만 접근할 수 있는 URL에 guest 이용자가 접근하지 못하게 제한하고 싶다. 이 문제를 해결하기 위한 방법으로 몰랐던 방식을 알게됐고, 그 방법에 대한 의견을 정리하면서 이 개발일지를 작성하게되었다.
- SecurityConfig에서 경로별 접근 제한 설정
- @PreAuthorize 어노테이션을 사용한 메서드 단위 접근 제한
▶첫 번째 방법: SecurityConfig 파일에서 경로 제한 설정
첫 번째 방법은 SecurityConfig 파일에서 URL 경로별로 접근 권한을 설정하는 것이다. 스프링 시큐리티에서 제공하는 .requestMatchers() 메서드를 이용해 특정 경로에 접근할 수 있는 권한을 제한할 수 있다. 예를 들어, 아래와 같이 /user/** 경로에 대해 USER 권한이 있는 사람만 접근 가능하도록 설정할 수 있다.
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers("/user/**").hasRole("USER")
.requestMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().permitAll();
}
→ 이 방법은 경로별로 명확하게 접근 권한을 설정할 수 있어, 각 경로에 대한 권한 정책이 한눈에 보인다는 장점이 있다. 따라서 보안 관련된 설정이 한 곳에 모여 있어 관리가 용이하고, 코드의 흐름을 쉽게 파악할 수 있다.
▶두 번째 방법: @PreAuthorize 어노테이션을 사용한 접근 제한
두 번째 방법은 스프링의 @PreAuthorize 어노테이션을 사용하는 것이다. 이 어노테이션은 메서드 단위로 접근 권한을 제어할 수 있게 해준다. 예를 들어, 특정 메서드에 대해 USER 권한이 있는 경우에만 접근하도록 설정하려면 다음과 같이 작성할 수 있다.
@PreAuthorize("hasRole('USER')")
public String userPage() {
// 사용자 페이지 로직
}
→ 이 방법은 세밀한 접근 제어가 필요할 때 유용하다. 보안이 중요한 특정 메서드에 대해 권한을 설정할 수 있으며, 메서드 레벨에서 바로 권한을 확인할 수 있기 때문에 코드의 비즈니스 로직과 보안 로직을 결합하여 좀 더 명시적으로 표현할 수 있다.
나는 현재 첫 번째 방법을 사용하고 있지만, 두 번째 방법인 @PreAuthorize 어노테이션을 사용한 접근 제한에 대해서도 관심이 생겼다. 이 방법을 학습하면서 몇 가지 장단점과 고려 사항을 알게 되었다.
- 장점:
- @PreAuthorize는 메서드 단위로 접근 권한을 설정할 수 있기 때문에 세밀한 권한 제어가 가능하다. 예를 들어, 특정 메서드에 대해 사용자 권한을 제한하고자 할 때, 메서드에 직접적으로 권한을 명시함으로써 보안 로직을 명확하게 표현할 수 있다.
- 코드가 더 직관적이고, 메서드 자체에서 권한을 확인하기 때문에 해당 메서드를 사용하는 개발자가 보안 정책을 쉽게 이해할 수 있다.
- 단점:
- 보안 로직이 여러 메서드에 흩어지기 때문에 코드의 일관성이 떨어지고, 보안 설정이 분산될 수 있다. 이는 유지보수성 측면에서 어려움을 야기할 수 있다. 특히, 권한 설정이 변경될 경우 여러 메서드를 수정해야 할 수 있어 관리 비용이 증가한다.
- @PreAuthorize를 남발하게 되면 비즈니스 로직과 보안 로직이 혼재되어 코드의 가독성이 떨어질 수 있다. 보안 관련 설정은 보통 한 곳에서 집중적으로 관리하는 것이 좋기 때문에, 메서드 단위로 분산되는 것은 오히려 혼란을 초래할 수 있다.
▶다른 개발자들의 의견
위 두 가지 방법에 대해 고민하면서, 다른 개발자들의 의견을 들을 수 있었다. 대부분의 개발자들은 첫 번째 방법인 SecurityConfig에서 경로별로 접근 권한을 제한하는 것을 선호했다. 그 이유는 보안 관련 책임을 한 곳에 집중시켜 관리하는 것이 더 명확하고 유지보수가 용이하기 때문이었다. @PreAuthorize를 사용하게 되면, 비즈니스 로직에서 접근 제어를 설정해야 하므로, 코드의 흐름을 파악하기 어려워질 수 있다는 단점이 있었다.
하지만, 예외적으로 보안이 매우 중요하고 민감한 메서드에 대해서는 @PreAuthorize를 사용하여 메서드 단위로 권한을 제한하는 것이 좋다는 의견도 있었다. 이 경우 특정 메서드에 대해 더 명확한 보안 설정을 적용할 수 있어 보안성을 높일 수 있다.
▶URL 경로 노출에 대한 고민
경로별 접근 제한을 설정할 때, /user/**와 같은 경로가 URL에 노출되는 것이 꺼려질 수 있다는 고민도 있었다. 특히 URL을 통해 어떤 권한이 필요한지 드러나는 것이 보안 측면에서 문제가 되지 않을까 생각하게 되었다. 이에 대해 다른 개발자의 의견을 참고해보니, 대부분의 경우 권한 정보가 노출되더라도 큰 문제는 없다는 것이었다. 보통 JWT 토큰에도 권한 정보가 포함되어 있고, 특정 권한을 가지지 않으면 요청을 처리할 수 없기 때문에, 권한 기반 인증에서 중요한 것은 권한 획득의 어려움이지, 권한이 노출되는지 여부가 아니라는 것이다.
만약 권한 정보를 URL에서 숨겨야 한다면, 경로별 권한 설정 대신 @PreAuthorize와 같은 어노테이션을 사용하여 메서드 단위로 권한을 제한하는 방법이 대안이 될 수 있다. 또한, 경로 정보를 배열에 저장하고 이를 통해 경로별로 권한을 관리하는 것도 고려할 수 있다.
private final String[] adminUrls = {"/api/post/create", "/api/post/delete"};
.requestMatchers(adminUrls).hasRole("ADMIN");
스프링 시큐리티에서 권한별 URL 접근을 제어하는 방법에는 여러 가지가 있지만, 각 방법의 장단점을 고려해야 한다. SecurityConfig에서 경로별로 접근 권한을 설정하는 방법은 보안 관련 로직을 한 곳에 모아 관리할 수 있어 코드의 가독성과 유지보수성 측면에서 유리하다. 반면에, @PreAuthorize를 사용하면 메서드 단위로 더 세밀한 접근 제어를 할 수 있지만, 보안 로직이 분산되어 코드의 흐름을 파악하기 어려워질 수 있다. 앞으로 개발을 진행하면서 @PreAuthorize 어노테이션을 사용하는 방법에 대해 더 깊이 있게 학습하고, 어떤 상황에서 이 방법이 적합한지 고민해 보고자 한다. 특히 보안이 중요한 메서드에 대해서는 @PreAuthorize를 사용하는 것이 보안성을 높일 수 있는 좋은 방법일 수 있다. 개발자로서 요구사항에 맞는 적절한 접근 제어 방법을 선택하고, 보안과 유지보수성 사이의 균형을 잘 맞춰 나가야겠다. 또한, URL에 권한 정보가 노출되는 것에 대한 고민도 필요할 때는 보안 정책을 재검토하고, 필요 시 다른 접근 제어 방식을 활용해 문제를 해결해야겠다.
'개발Article' 카테고리의 다른 글
[TIL]20241121 Jackson @JsonInclude (1) | 2024.11.21 |
---|---|
[TIL]20241120 FACADE 패턴 (14) | 2024.11.20 |
[TIL]20241117 TDD (1) | 2024.11.17 |
[TIL]20241116 @Data를 써도 될까? (0) | 2024.11.16 |
[TIL]20241115 소프트웨어에서 도메인이란? (9) | 2024.11.15 |