이 글에서는 스프링 시큐리티의 핵심 개념들을 살펴보고, 주요 용어와 아키텍처에 대해 정리해 보겠다. 또한 기본적인 보안 옵션을 적용해보며, 이러한 설정이 실제 애플리케이션에 어떤 영향을 미치는지 상세히 알아볼 것이다.
보안에 취약한 애플리케이션의 문제를 해결하기 위해 가장 먼저 해야 할 일은 보안의 두 축인 인증과 권한부여의 개념을 명확히 하고, 이를 처리하기 위한 표준 설정을 이해하는 것이다.
![]()
1. 핵심 보안 개념: 인증과 권한부여
보안 시스템을 구축할 때 가장 혼동하기 쉽지만 반드시 구별해야 할 두 가지 개념이 바로 인증(Authentication)과 권한부여(Authorization)다.
먼저 인증은 사용자가 주장하는 본인이 맞는지를 확인하는 절차를 말한다. 온라인 뱅킹이나 전자 상거래 사이트에서는 보통 아이디와 비밀번호를 통해 사용자를 확인한다. 스프링 시큐리티에서는 이러한 인증의 주체를 주체(Principal)라고 부르며, 신원 확인을 위해 제시하는 비밀번호와 같은 정보를 자격 증명(Credentials)이라고 한다. 시스템은 이 두 가지를 조합하여 사용자가 누구인지 식별한다.
반면 권한부여는 인증된 사용자가 특정 리소스에 접근하거나 특정 기능을 수행할 자격이 있는지를 판단하는 과정이다. 스프링 시큐리티에서는 이를 부여된 권한(Granted Authority)이라고 하며, 리소스에 접근하기 위해 필요한 권한과 사용자가 가진 권한을 비교하여 접근 허용 여부를 결정한다.
예를 들어 사용자가 보호된 리소스(예: 재고 관리 페이지)에 접근하려 할 때, 시스템은 사용자의 권한과 리소스가 요구하는 권한(예: 관리자 권한)의 교집합을 확인한다. 교집합이 없다면 접근은 거부(Access Denied)**된다. 즉, 권한부여는 보안이 적용된 리소스에 대한 사용자의 요청에 대해 권한을 부여하거나 거부하는 결정 과정이다.
2. 스프링 시큐리티 필터 설정: DelegatingFilterProxy
스프링 시큐리티를 웹 애플리케이션에 적용하기 위해서는 서블릿 컨테이너(예: Tomcat)와 스프링 애플리케이션 컨텍스트 사이를 연결해 주는 매개체가 필요하다. 이를 위해 web.xml 파일에 DelegatingFilterProxy를 필터로 등록해야 한다.
DelegatingFilterProxy는 서블릿 필터로서, 모든 웹 요청을 가로채어 스프링 컨텍스트 내에 정의된 스프링 시큐리티 필터 체인으로 위임하는 역할을 한다. web.xml에 다음과 같은 필터 설정을 추가하여 모든 URL 패턴(/*)에 대해 이 필터가 동작하도록 설정한다.
<filter> <filter-name>springSecurityFilterChain</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>springSecurityFilterChain</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
여기서 중요한 점은 필터의 이름을 springSecurityFilterChain으로 지정해야 한다는 것이다. 이는 스프링 시큐리티가 내부적으로 사용하는 빈의 이름과 일치해야 올바르게 동작한다.
3. 스프링 설정 파일 구성과 XML 네임스페이스
스프링 MVC 설정과는 별도로 보안 관련 설정을 담당할 독립적인 ApplicationContext를 생성하는 것이 좋다. 이를 위해 web.xml에 ContextLoaderListener를 설정하고, 보안 설정 파일(예: dogstore-security.xml)을 로드하도록 context-param을 추가한다.
이제 실제 보안 규칙을 정의하는 dogstore-security.xml 파일을 작성해 보자. 스프링 시큐리티 2.0부터 도입된 보안 네임스페이스를 사용하면 복잡한 빈 설정 없이도 간결하게 보안을 적용할 수 있다. 최소한의 설정으로 웹 애플리케이션 보안을 적용하는 코드는 다음과 같다.
위 설정의 핵심 내용은 다음과 같다. 첫째, <http auto-config="true"> 요소는 폼 로그인, 기본 인증, 로그아웃 기능 등 기본적인 웹 보안 기능을 자동으로 설정한다. 둘째, <intercept-url> 요소는 특정 URL 패턴에 대한 접근 권한을 정의한다. 여기서는 모든 경로(/**)에 대해 ROLE_USER 권한이 필요하다고 설정했다. 셋째, <user-service> 요소를 통해 메모리 상에 사용자를 정의한다. 아이디 guest, 비밀번호 guest인 사용자를 생성하고 ROLE_USER 권한을 부여했다.
이 간단한 설정만으로도 JBCP Pets 사이트에 로그인 페이지가 생성되고, 인증되지 않은 사용자의 접근을 차단하는 기본 수준의 보안이 구현된다.
4. 자주 발생하는 문제 및 주의사항
스프링 시큐리티를 처음 적용할 때 개발자들이 자주 겪는 문제들이 있다. 다음 사항들을 미리 점검하여 불필요한 오류를 방지하자.
먼저 XML 설정 파일 작성 시 cvc-elt.1: Cannot find the declaration of element 'beans'와 같은 에러가 발생한다면, 스키마 선언 부분에 오타가 없는지 확인하고 XML 유효성 검증기를 통해 검증하는 것이 좋다. 개발자들은 다양한 XML 네임스페이스 레퍼런스를 혼동하는 경우가 잦으므로 주의가 필요하다.
또한 사용하는 스프링 프레임워크와 스프링 시큐리티의 버전이 책의 예제와 일치하는지, 혹은 서로 호환되는지 확인해야 하며 불필요한 JAR 파일이 남아있지 않도록 관리해야 한다. 마지막으로 서블릿 컨테이너를 실행할 때는 IDE를 사용하여 콘솔 로그를 확인하면 예외 발생 시 원인을 파악하기 쉽다.
지금까지 스프링 시큐리티의 핵심 개념인 인증과 권한부여를 이해하고, DelegatingFilterProxy와 XML 네임스페이스 설정을 통해 간단한 보안 시스템을 구축해 보았다. 하지만 이 설정은 사용자의 아이디와 비밀번호가 XML 파일에 그대로 노출되어 있다는 단점이 있다. 또한 로그인 페이지가 지나치게 평범하여 기존 사이트의 디자인과 어울리지 않는 문제도 있다.