스프링 시큐리티는 사용자 인증(authentication) 및 권한 제어(authorization) 요구에 대해 매우 유연한 프레임워크를 제공하지만, 보안 어플리케이션을 구축하기 위해서는 스프링 시큐리티의 범위 밖에 있는 다양한 고려사항이 있다. 웹 어플리케이션은 이미 잘 알려져 있는 모든 종류의 공격에 취약하기 때문에, 개발을 시작하기 전에 발생할 수 있는 문제들을 잘 이해한 후에 코딩하고 설계해야만 한다. 웹 어플리케이션 개발자가 알아야 하는 주요 이슈와 대응책을 얻기 위해서는 OWASP 웹 사이트를 참조하기를 바란다.
2. web.xml 보안으로 충분하지 않는가?
자, 당신이 스프링 기반으로 엔터프라이즈 응용 프로그램을 개발하고 있다 가정하자.
일반적으로 언급되고, 보안 시스템 구축 시 요구되는 4가지 보안 문제가 있다. 인증(authentication), 웹 요청 보안(web request security), 서비스 계층 보안 (비즈니스 로직을 구현한 메소드들), 도메인 객체 인스턴스 보안 (서로 다른 도메인 객체는 다른 접근 제한 등급을 가진다) 등이다.
1) 인증(authentication) : 서블릿 사양(servlet specification)에는 기본적인 인증 방식이 정의되어 있다. 그러나, 일반적으로 서블릿 인증을 수행하기 위해서는 웹 컨테이너(web container)의 고유 영역(realm)을 설정해야 한다. (예를 들자면, 톰캣의 설정 방식과 JBoss의 설정 방식이 다르다.) 이러한 설정 방식은 이식성(portability)이 없는데다, 컨테이너의 인증 인터페이스를 구현한 자바 클래스를 작성해야 하는 경우 더욱 더 이식성이 없어지게 된다. 스프링 시큐리티를 사용하게 되면 WAR 수준에서 완벽한 호환성을 달성할 수 있다. 게다가, 스프링 시큐리티는 검증된 사용자 인증 제공자 및 메커니즘들을 선택할 수 있으므로, 개발 진행 중에 인증 방식을 선택하거나 교체할 수 있다. 이는 확정되지 않은 운영 환경을 대상으로 개발되는 소프트웨어를 개발하는 업체에게 유용하다.
2) 웹 요청 보안(web request security) : 서블릿 사양(servlet specification)에서는 요청 URI의 보안성을 유지하는 방법을 제공한다. 그러나, 서블릿 사양에 기초해 보안 가능한 URI들은 사양에서 지정한 제한된 URI 포맷을 따라야만 한다. 스프링 시큐리티는 훨씬 더 포괄적인 방식을 제공하고 있다. 예를 들어, Ant 경로 혹은 정규식 표현을 사용할 수 있다. 단순히 요청된 페이지 경로가 아니라, URI의 일부 요소 (HTTP Get 인자 등)를 고려할 수도 있다. 이것은 웹 어플리케이션이 실행되는 동안에 웹 요청 보안이 동적으로 변경될 수 있음을 의미한다.
3) 서비스 레이어와 도메인 객체 보안(Service layer and domain object security) : 서블릿 사양 내에 서비스 계층 보안 및 도메인 객체 인스턴스 보안에 대한 지원(혹은 표준)이 없다는 것은 다계층(multi-tier) 어플리케이션을 개발함에 있어 심각한 한계를 보여준다. 일반적으로 개발자들은 이러한 요구사항을 애써 무시하거나, MVC 컨트롤러 코드 (더 나쁜 경우는 뷰 계층에서...) 내에서 보안 로직을 구현한다. 이러한 대응 방식은 심각한 단점들을 내포하고 있다.
a. 관심사의 분리(Separation of concerns) : 인증은 횡단 관심사(crosscutting concern)로 간주되어야 하고, 그렇게 구현되어야 한다. 반면에 MVC 코드나 뷰에서 인증 코드를 구현할 경우, 제어 로직과 인증 로직을 함께 테스트 하기 어렵고, 디버깅하기 어려우며, 코드 중복으로 이어지게 된다.
b. 리치 클라이언트와 웹 서비스에 대한 지원(rich clients and web services) : 새로운(혹은 추가된) 유형의 클라이언트를 필수적으로 지원해야 하는 상황이 닥친다면, 웹 계층에 내장된 인증 코드는 재사용할 수 없게 된다. 이런 상황에서는 스프링 리모팅 익스포터(remoting expoters)만이 서비스 계층 빈(MVC 컨트롤러가 아닌 객체)들을 외부로 노출할 수 있다. 다양한 클라이언트 유형을 지원하기 위해서는 인증 로직인 서비스 계층에 존재해야 한다.
c. 계층 문제(layering issues): MVC 컨트롤러나 뷰(view) 계층에 인증 로직을 담는 것은 매우 잘못된 계층 설계이다. 반면에, 서비스 계층에서 인증하게끔 결정할 경우 모든 서비스 계층 메소드에 추가 인자(argument)를 전달해야 하는 문제가 발생한다. 좀 더 우아한 방식은 ThreadLocal 에 인증 정보를 담는 방식이나, 이는 개발 기간의 증가를 의미한다. 가장 경제적인 방법(비용 절감 차원)은 전용(dedicated) 보안 프레임워크를 사용하는 것이다.
d. 인증 코드 품질(authorization code quality) : 웹 프레임워크들은 종종 "올바른 것들은 더욱 쉽게 할 수 있고, 잘못된 방식들은 더욱 하기 어렵게 만드는 것(make it easier to do the right things, and harder to do the wrong things)"이라고 불리운다. 보안 프레임워크는 보다 다양한 목적과 추상적 방식으로 설계되기 때문에 웹 프레임워크와 동일한 특징을 가지고 있다. 자신만의 인증 코드를 작성할 경우, "검증(design check)"이 이루어지지 않는다. 반면에 보안 프레임워크들은 객관적으로 검증된 것이다. 또한, 자체 제작(in-house) 된 인증 코드는 광범위한 개발을 통한 개선, 외부 혹은 동료 개발의 리뷰, 버전업 등이 이루어지지 않는다.
간단한 어플리케이션인 경우, 서블릿 스펙 보안으로 충분할 수 있다. 그러나, 웹 컨테이너 간의 낮은 이식성, 설정 방식의 비호환성, 웹 요청 보안의 유연성 부족, 서비스 계층과 도메인 객체 인스턴스 보안의 부재 등을 고려해 본다면, 또 다른 솔루션을 고려해야 하는 것이 분명하다.