Spring Security Taglibs

merci·2023년 11월 5일

스프링 시큐리티를 이용한다면 csrf 설정을 통해서 보안설정을 간단히 구현할 수 있습니다.

의존성 및 상단 추가

implementation 'org.springframework.security:spring-security-taglibs:5.8.0'
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %>

...

<security:authorize />

현재 사용자의 권한을 바탕으로 페이지의 특정 부분을 조건부로 렌더링하는 데 사용됩니다.

  • 특정 권한이나 사용자에게만 허용하고 싶을 경우
<security:authorize access="!isAuthenticated()">
  Login
</security:authorize>
<security:authorize access="isAuthenticated()">
  Logout
</security:authorize>
  • 특정권한이 있는 사용자에게만 표시
<security:authorize access="hasRole('ADMIN')">
    Manage Users
</security:authorize>
  • 권한있는 사용자에게만 URL 표시
<security:authorize url="/userManagement">
    <a href="/userManagement">Manage Users</a>
</security:authorize>
  • 인증태그 이용
<sec:authorize access="isAuthenticated()">
    Welcome Back, <sec:authentication property="name"/>
</sec:authorize>
  • 로그인된 상태일때만
<security:authorize access="!isAnonymous()">


<sec:authentication>

이 태그는 현재 인증된 사용자의 상세 정보를 가져오는 데 사용됩니다.

  • 인증된 사용자의 이름을 표시
<sec:authentication property="name"/>
<security:authentication property="principal.userName" var="userName"/>


<security:csrfMetaTags/>

CSRF 공격을 보호하기 위해 사용됩니다.

<head>
    <security:csrfMetaTags/>
</head>

이 태그는 html 메타태그를 생성하게 되고 아래와 같은 형태입니다.

<meta name="_csrf" content="토큰값"/>
<meta name="_csrf_header" content="X-CSRF-TOKEN"/>

이러한 토큰값은 자바스크립트의 요청에 포함해 보낼 수 있습니다.

    const csrfToken = document.querySelector('meta[name="_csrf"]').getAttribute('content');
    const csrfHeaderName = document.querySelector('meta[name="_csrf_header"]').getAttribute('content');

    fetch('/some-endpoint', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        [csrfHeaderName]: csrfToken, // CSRF 토큰을 헤더에 추가
      },
      body: JSON.stringify({ data: 'yourData' }),
    })
    .then(response => response.json())
    .then(data => console.log(data));
    var csrfToken = $("meta[name='_csrf']").attr("content");
    var csrfHeader = $("meta[name='_csrf_header']").attr("content");

    $.ajax({
        url: "your-endpoint",
        type: "post",
        data: { ... },
        beforeSend: function(xhr) {
            xhr.setRequestHeader(csrfHeader, csrfToken);
        }
    });

<security:csrfInput />

<div>
    <security:csrfInput />
</div>

자동으로 아래 태그를 만들어 줍니다.

<input type="hidden" name="_csrf" value="토큰값"/>

POST요청시 form에 포함시켜서 요청을 보낼 수 있습니다.


Spring security 설정

스프링에서 아래와 같은 시큐리티 설정을 통해 로그인이 되었을 경우 헤더에 csrf 토큰을 넣어서 응답합니다.

@EnableWebSecurity
public class WebSecurityConfig {

	@Bean
	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
		http
			.csrf()
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
            // .. 생략
            );

		return http.build();
	}

HttpSessionCsrfTokenRepository

http.csrf()를 통해 csrf 보호를 활성화하게 되면 HttpSessionCsrfTokenRepository가 디폴트로 설정됩니다.
이는 세션이 토큰을 저장하게 되고 클라이언트는 <security:csrfInput /> 또는 <security:csrfMetaTags/>를 통해 html에 포함된 토큰을 요청 헤더에 포함시킵니다.
이때 스프링 시큐리티의 CsrfFilter는 세션의 토큰과 헤더의 토큰이 일치하는지 검사하게 됩니다.

CookieCsrfTokenRepository

csrfTokenRepository(CookieCsrfTokenRepository) 설정은 CSRF 토큰을 쿠키에 저장하도록 합니다.


HttpOnlyTrue()로 설정하면 자바스크립트가 쿠키의 값을 가져올수 없어서 XSS(Cross-site scripting) 공격에 의한 쿠키 탈취를 방지할 수 있습니다.
하지만 html을 만들지 않고 클라이언트측에서 SPA로 화면을 만들경우 자바스크립트가 토큰값을 가져와서 비동기로 요청을 보내야할때가 있으므로 false설정을 합니다.

서버사이드렌더링이라면 false설정을 하지않아도 됩니다.
<security:csrfInput /> 또는 <security:csrfMetaTags/>로 html에 포함된 토큰을 자바스크립트가 헤더에 포함시키면
스프링 시큐리티의 CsrfFilter가 쿠키에 저장된 토큰과 자바스크립트로 추가한 토큰이 일치하는지 검사하게 됩니다.


profile
작은것부터

0개의 댓글