Skip to content

Spring security framework #

Find similar titles

8회 업데이트 됨.

Edit
  • 최초 작성자
    yang4851
  • 최근 업데이트

Structured data

Category
Programming

Spring Security 는 Java Platform, Enterprise Edition(Java EE) 기반의 엔터프라이즈 소프트웨어 애플리케이션을 위한 포괄적인 보안 서비스를 제공하는 스프링 오픈 플랫폼으로 강력하고 사용자 정의가 가능한 인증(authentication)과 액세스 제어를 지원하는 프레임워크이고, 스프링 기반 애플리케이션 보안을 위한 사실상의 표준이라 할 수 있다.

자바 애플리케이션에 인증(Authentication)과 권한(Authority) 부여 제공에 중점을 둔 프레임워크로 모든 스프링 프로젝트와 마찬가지로 스프링 시큐리티의 진정한 힘은 사용자 정의 요구 사항을 충족시키기 위한 확장성 보장이 얼마나 쉬운가에 있다.

스프링 시큐리티(Spring Security)의 특징

  • 포괄적이고 확장 가능한 인증과 권한 지원
  • 세션 고정, 클릭 재킹, 크로스 사이트 요청 위조 등과 같은 공격으로부터 보호
  • 서블릿(Servlet) API(Application Programming Interface) 통합
  • Spring Web MVC와의 선택적 통합

여기서는 Spring Web MVC 와 Spring Security가 통합된 웹 애플리케이션 개발을 위해 Maven 프로젝트 생성을 위한 XML설정 방법과 XML기반의 스프링 시큐리티 설정방법을 알아보고 간단한 스프링 시큐리티 적용 웹 애플리케이션 실행 결과를 확인해 보도록 하겠다.

응용 프로그램에 보안 설정을 적용하기 전에 기존 응용 프로그램이 제대로 작동하는지 확인해야 하고, 예제 코드들의 실행은 이클립스(Eclipse)기반의 전자정부프레임워크(eGov 3.7) 에서 JDK 1.8, 스프링 프레임워크 4.2.7, Servlet 3.1 기준으로 작성하였으며, 통합개발환경(Integrated Development Environment, IDE)과 스프링 프레임워크 버전이 다른 경우 일부 설정이나 동작이 변경될 수 있다.

메이븐(Maven) 프로젝트 생성과 의존성 추가 #

메이븐 기반의 "eGovFrame Web Project"가 생성되면 pom.xml 파일을 열어 다음과 같이 서블릿 기반의 Security Filter 제공과 스프링 보안설정, 암호화, REST 통신을 위한 메이븐 의존성(Dependency) 설정을 추가한다. (메이븐 프로젝트 생성에 대한 기본적인 내용은 다음 문서에서 확인할 수 있음 : Maven + Spring framework (Eclipse + eGov))

<dependencies>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-web</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>      
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-config</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>        
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-crypto</artifactId>
        <version>4.2.4.RELEASE</version>
    </dependency>        
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.4</version>
    </dependency>
</dependencies>

웹 애플리케이션 스프링 시큐리티 등록하기 #

스피링 시큐리티 설정을 적용하기 위해선 자바 서블릿 설정에 security filter 선언과 스프링 기본 설정이 추가되어야 한다.

메이븐 프로젝트의 Package Explorer View에서 src/main/webapp/WEB-INF 폴더를 선택하고 web.xml 파일이 없는 경우는 새로 생성하고 이미 등록된 경우는 web.xml 파일을 열어 다음의 설정을 추가해 준다.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
    http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    id="WebApp_ID" version="3.1">
    <display-name>Spring Security Basic XML</display-name>

    <servlet>
        <servlet-name>action</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/config/dispatcher-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>action</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>


    <!-- spring security 설정 파일 경로 선언 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath*:egovframework/spring/context-*.xml
        </param-value>
    </context-param>

    <!-- Spring Security  Filter Chain 선언 -->
    <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>
</web-app>

Spring Security 가 적용되면 서블릿이 실행되기 전에 Spring Security Filter 에서 조건에 따라 다음의 순서대로 먼저 보안 확인을 수행한 후 문제가 없는 경우 요청에 대한 처리가 진행되게 된다. 예를 들어 요청이 사용자 인증이 필요한 경우 SECURITY_CONTEXT_FILTER가 요청을 가로채고 인증되지 않은 경우는 FORM_LOGIN_FILTER 로 요청이 넘어가고 사용자 인증이 완료되면 원래의 요청 대상이 실행될 수 있도록 보안 필터가 등록되어 있다.

표준 보안 필터링 종류와 실행 순서는 다음과 같다. (출처)

Alias Filter Class Namespace Element or Attribute
CHANNEL_FILTER ChannelProcessingFilter http/intercept-url@requires-channel
SECURITY_CONTEXT_FILTER SecurityContextPersistenceFilter http
CONCURRENT_SESSION_FILTER ConcurrentSessionFilter session-management/concurrency-control
LOGOUT_FILTER LogoutFilter http/logout
X509_FILTER X509AuthenticationFilter http/x509
PRE_AUTH_FILTER AstractPreAuthenticatedProcessingFilter N/A
CAS_FILTER CasAuthenticationFilter N/A
FORM_LOGIN_FILTER UsernamePasswordAuthenticationFilter http/form-login
BASIC_AUTH_FILTER BasicAuthentcationFilter http/http-basic
SERVLET_API_SUPPORT_FILTER SecurityContextHolderAwareRequestFilter http/@servlet-api-provision
JAAS_API_SUPPORT_FILTER JaasApilntegrationFilter http/@jaas-api-provision
REMEMBER_ME_FILTER RememberMeAuthenticationFilter http/remember-me
ANONYMOUS_FILTER AnonymousAuthenticationFilter http/anonymous
SESSION_MANAGEMENT_FILTER SessionManagementFilter session-management
EXCEPTION_TRANSLATION_FILTER ExceptionTranslationFilter http
FILTER_SECURITY_INTERCEPTOR FilterSecurityInterceptor http
SWITCH_USER_FILTER SwitchUserFilter N/A

스프링 시큐리티 XML 설정 #

web.xml 파일에서 설정한 "contextConfigLocation" 에서 설정한 "WEB-INF/classes/egovframework/spring/" 폴더에 context-security.xml 파일에 스프링 시큐리티의 인증과 인가 설정을 추가한다.

context-security.xml 파일에서 설정할 수 있는 보안 내용은 다음과 같다.

  • 인증요청을 위한 응용 프로그램 URL 선언
  • 로그인 폼 생성
  • Username, Password 속성을 갖는 인증 폼에서 사용자 인증 실행
  • 로그아웃 실행
  • 세션 정보 유지 보호
  • HTTP 응답 헤더 정보 사용자 정의 지원 (X-XSS-Protection, X-Content-Type-Options, X-Frame-Options, Cache Control, Http Strict Transport Security)
  • 서블릿 API 메소드와 통합(HttpServletRequest#login(), HttpServletRequest#logout() 등)

사용자 인증(Authentication-로그인, 로그아웃) 설정 #

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/security
        http://www.springframework.org/schema/security/spring-security-4.2.xsd">

    <global-method-security secured-annotations="enabled" pre-post-annotations="enabled" />

    <!-- 인증/인가 예외 리소스 정의 --> 
    <http pattern="/" security="none" />
    <http pattern="/index.html" security="none" />
    <http pattern="/resources/**" security="none" />

    <!-- 사용자 인증 설정 -->
    <http pattern="/api/login" auto-config="true" use-expressions="true">
        <csrf disabled="true" />
        <intercept-url pattern="/**" access="permitAll" />

        <form-login login-processing-url="/api/login"
            username-parameter="username"
            password-parameter="password"
            always-use-default-target="false" />

        <http-basic entry-point-ref="authenticationEntryPoint" />
        <custom-filter before="FORM_LOGIN_FILTER" ref="loginFilter" />
    </http>


    <!-- 인증 실패에 대한 처리 리소스 정의 --> 
    <beans:bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder" />
    <beans:bean id=" authenticationEntryPoint " class="com.insilicogen.example.security.StatelessAuthenticationEntryPoint" />

    <!-- 인증 객체 생성을 위한 필터 설정 --> 
    <beans:bean id="loginFilter" class="com.insilicogen.example.security.StatelessLoginFilter">
        <beans:constructor-arg name="urlMapping" value="/api/login" />
        <beans:constructor-arg name="authManager" ref="authManager" />
    </beans:bean>

    <!-- 로그인(인증) 관리 모듈 설정 --> 
    <beans:bean id="authenticationProvider" class="com.insilicogen.example.security.StatelessAuthenticationProvider" />

    <authentication-manager id="authManager">
        <authentication-provider ref="authenticationProvider" />
    </authentication-manager>
</beans:beans>

스프링 보안 설정 XML 표현식(expressions) #

Expression Description
hasRole([role]) 현재 주체가 입력받은 특정 롤(ROLE)을 갖고 있는 경우 "true"를 반환. 롤 매개변수는 해당 롤 앞에 "ROLE_"를 접두어로 붙여서 사용.
hasAnyRole([role1,role2]) 현재 주체가 입력받은 롤(ROLE)을 포함된 경우 "true"를 반환. 입력하는 롤들은 쉼표(,)로 구분해 여러 개의 롤을 확인할 수 있음. hasRole과 동일하게 각각의 롤은 "ROLE_"가 접두어를 붙여서 사용.
hasAuthority([authority]) 현재 주체가 입력된 특정 권한(authority)을 갖고 있는 경우 "true" 반환
hasAnyAuthority([authority1, authority2]) 현재 주체가 입력된 권한 중 하나라도 갖고 있는 경우 "true" 반환. 입력하는 권한 목록은 쉼표(,)로 구분해 여러 개의 권한을 확인할 수 있음.
principal 현재 사용자를 나타내는 주요 개체에 직접 액세스 할 수 있음.
authentication SecurityContext에서 획득한 현재 인증 개체에 직접 액세스 할 수 있음.
permitAll 보안 인증, 인가를 항상 실행함.
denyAll 보안 인증, 인가를 항상 거부함.
isAnonymous() 현재 주체가 익명 사용자인 경우 "true" 반환
isRememberMe() 현재 주체가 기억된 사용자인 경우 "true" 반환
isAuthenticated() 사용자가 익명이 아닌 경우 "true" 반환

(참고 : https://www.baeldung.com/spring-security-expressions)

사용자 인가(Authority) 설정 #

    <!-- FilterInvocationSecurityMetadataSource -->
    <beans:bean id = "filterInvocationSecurityMetadataSource"
    class="com.insilicogen.common.security.ReloadableFilterInvocationSecurityMetadataSource"
        c:requestMap-ref="requestMap"
        c:anonymousBean-ref="anonymousBean"
    />

    <!-- AccessDecisionManager 설정 -->
    <beans:bean id = "accessDecisionManager" class = "org.springframework.security.access.vote.AffirmativeBased">
        <beans:constructor-arg name = "decisionVoters">
            <beans:list>
                <beans:bean class = "org.springframework.security.access.vote.RoleVoter"/>
            </beans:list>
        </beans:constructor-arg>
    </beans:bean>

    <!-- FilterSecurityInterceptor 설정  -->
    <beans:bean id = "filterSecurityInterceptor" class = "org.springframework.security.web.access.intercept.FilterSecurityInterceptor"
        p:authenticationManager-ref="authManager"
        p:accessDecisionManager-ref="accessDecisionManager"
        p:securityMetadataSource-ref="filterInvocationSecurityMetadataSource"
        p:messageSource-ref="messageSource"
    />
  • FilterInvocationSecurityMetadataSource

    • FilterInvocationSecurityMetadataSource를 통해 요청된 자원에 대해 접근권한 판별 후 통과 여부 판단
    • 해당 interface를 상속받아 getAttributes 재정의하여 해당 시스템에 맞게 구현
    • 해당 클래스의 반환 객체인 ConfigAttribute 는 권한의 종류에 대한 정보를 담고 있으며 시스템 내에 기본적으로 하나의 자원(url-RequestMatcher)에 어떠한 권한(role-ConfigAttribute)들이 통과할 수 있는지에 대한 정보 갖고 있어야 함
  • accessDecisionManager

    • ccess Control 결정을 내리는 인터페이스로, 구현체 3가지를 기본으로 제공
    • AffirmativeBased : 여러 Voter 중에 한 명이라도 허용하면 허용, 기본전략
    • ConsensusBased : 다수결
    • UnanimousBased : 만장일치
  • vote

    • 위에 결정을 내리는 기준이 되는 투표권자
    • FilterSecurityInterceptor의 WebExpressionVoter : 표현식에 따라 투표
    • GlobalMethodSecurityInterceptor
      • RoleVoter : IT초기 부터 전통적으로 구현해서 사용하던 가장 직관적인 체계
      • AuthenticatedVoter : 인증받고 들어온 사용자와 RemeberMe토큰을 통해서 들어온 사용자와 익명 사용자를 구분하기 위해 사용
  • RoleHierarchy
    • RoleVoter의 단점을 보완하기 위해 계층구조로 권한을 구분하기 위해 사용

spring security taglib #

  • jsp 내에서 security를 이용하여 인증 처리 및 권한 분기를 할 경우 사용

    • AuthenticationProvider의 구현체에서 role을 정의하고 UsernamePasswordAuthenticationToken에 정의된 role을 setting 하였을 때 사용 가능
  • 먼저 pom.xml에 등록

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-taglibs</artifactId>
        <version>4.2.16.RELEASE</version>
    </dependency>
    
  • context-security.xml(하위 컨테이너 파일)에서 http 설정 부분에 use-expressions="true" 추가

  • jsp 내에서 taglib 추가 <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>

  • jsp내 표현식은 위 '스프링 보안 설정 XML 표현식(expressions)' 참고

  • 표현식과 c태그를 사용한 간단한 예제(현재 세션에서 인증객체의 존재 여부 판별)

    <sec:authorize access="isAuthenticated()">
        <input type = "hidden" id = "anonymous" value = "N"/>
        <c:set var="searchUrl" value="/authenticated"/>
     </sec:authorize>
    

참고 사이트 #

Incoming Links #

Related Data Sciences #

Suggested Pages #

0.0.1_20230725_7_v68