Spring Security 적용 요약

간단한 회원가입과 게시판 구현시 스프링 시큐리티가 필요한 부분은 다음과 같습니다.

  • 로그인/로그아웃 및 회원가입
  • 글쓰기/수정/삭제권한

적용하기 앞서 @어노테이션으로 손쉽게 스프링 시큐리티를 적용할 수 있는 환경을 만들었습니다.

servlet-context.xml

1
2
<!-- 스프링 시큐리티 설정 -->
	<security:global-method-security pre-post-annotations="enabled" secured-annotations="enabled" />

위와 같이 설정시 @PreAuthorize, @PostAuthorize, @PostFIlter, @PreFilter등의 어노테이션을 사용할 수 있습니다.

@PreAuthorize는 클라이언트측의 요청이 들어와 선언한 메소드를 실행하기 전 권한을 검사하는 기능을 하며, @PostAuthorize는 반대로 클라이언트측의 응답을 하기 직전에 권한을 검사하는 어노테이션입니다.

그 외에 위의 어노테이션에 관해 자세한 설명은 Spring Security @PreAuthorize, @PostAuthorize 를 사용하는 신박한 전처리 후처리 기법 에 나와있습니다.


security-context.xml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<!-- 에러 페이지 설정-->
<bean id="customAccessDenied" class="org.zerock.security.CustomAccessDeniedHandler"></bean>
<!-- 비밀번호 암호화처리 -->
<bean id="bcryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>
<!-- 사용자 정보 객체의 권한과 인증처리를 위한 customUserDetailsService -->
<bean id="CustomUserDetailsService" class="org.zerock.security.CustomUserDetailsService"></bean>


<!-- 로그아웃 -->
<security:logout logout-url="/customLogout" invalidate-session="true"/>
<security:access-denied-handler ref="customAccessDenied" />
<!-- 커스텀 로그인 -->
<security:form-login login-page="/customLogin"/>

web.xml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<filter>
  <filter-name>encodingFilter</filter-name>
  <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  <init-param>
    <param-name>encoding</param-name>
    <param-value>UTF-8</param-value>
  </init-param>
</filter>

<filter-mapping>
  <filter-name>encodingFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

security.xml과 web.xml의 파일의 설정을 위와 같이 선언합니다. web.xml의 한글 인코딩 작업은 스프링 시큐리티 필터 태그보다 위에 선언해줘야 합니다.

xxx.jsp

1
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="sec" %>

화면부분의 코드파일엔 스프링 시큐리티 태그라이브러리를 추가합니다. 이는 로그인이 된 회원을 기준으로 글쓰기 권한이나 작성자만 자신의 글을 수정하거나 삭제하는 등의 권한을 부여하기 위해 사용합니다.

CSRF 토큰

스프링 시큐리티 적용시 POST 방식으로 정보가 입력된 데이터를 저장할 때는 반드시 CSRF 토큰을 사용합니다.

CSRF토큰이란 랜덤하게 변하는 특정한 토큰값을 서버단에서 확인하는 방법을 말합니다. 클라이언트가 특정한 행위를 요청시 토큰값을 가진 파라미터가 서버로 넘어가 서버에 있는 토큰의 값과 비교하여 동일하면 처리에 응하고 그렇지 않을때는 공격으로 판단하는 보안로직입니다.

ex) register.jsp

1
2
3
4
5
6
7
<div class="form-group">
<label>Writer</label>
                            <input class="form-control" name="writer" value='<sec:authentication property="principal.username"/>' readonly>
                        </div>
                        <button type="submit" class="btn btn-default">Submit</button>
                        <button type="reset" class="btn btn-default">Reset</button>
                        <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />

일반적으로 토큰은 세션에 보관하며 토큰의 값을 input태그의 hidden으로 함께 form으로 넘겨줍니다.

Ajax 이용시 CSRF 토큰 전달

1
2
3
4
5
6
7
var csrfHeaderName ="${_csrf.headerName}"; 
var csrfTokenValue="${_csrf.token}";

//ajax spring security header
$(document).ajaxSend(function(e, xhr, options){
  xhr.setRequestHeader(csrfHeaderName, csrfTokenValue);
});

csrf.token과 headerName을 변수로 설정 후 ajax 전송시 ajaxSend 함수에 RequestHeader에 csrf토큰의 정보를 변수로 설정하여 함께 전송합니다.

이후 브라우저 개발자도구에서 토큰이 함께 전달되어지는 것을 확인할 수 있습니다.

스크린샷 2019-05-31 오후 1 03 16


Reference