๐Ÿ”„ ์ˆœํ™˜ ์ฐธ์กฐ(Circular Reference) ๋ฌธ์ œ์™€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

NTbellยท2025๋…„ 1์›” 1์ผ

JWT์„ ์ด์šฉํ•ด์„œ ๋กœ๊ทธ์ธ, ํšŒ์›๊ฐ€์ž…์„ ๋‹ค์‹œ ๊ณต๋ถ€ํ•˜๋ฉด์„œ ์ˆœํ™˜์ฐธ์กฐ ๋ช‡๋ฒˆ ์ผ์–ด๋‚ฌ๋‹ค
์ด๋ฒˆ ํฌ์ŠคํŒ… ๊ฒฝ์šฐ, ์ˆœํ™˜์ฐธ์กฐ์— ๋Œ€ํ•ด ๊ธ€์„ ์ž‘์„ฑํ•ด ๋ณผ๊นŒ ํ•œ๋‹ค


๐Ÿ” ์ˆœํ™˜ ์ฐธ์กฐ๋ž€?

  • ์ˆœํ™˜ ์ฐธ์กฐ๋Š” ๋‘ ๊ฐœ ์ด์ƒ์˜ ๋นˆ(Bean)์ด ์„œ๋กœ๋ฅผ ์ฐธ์กฐํ•  ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ
  • ์˜ˆ๋ฅผ ๋“ค์–ด, A๊ฐ€ B๋ฅผ ํ•„์š”๋กœ ํ•˜๊ณ , B๊ฐ€ ๋‹ค์‹œ A๋ฅผ ํ•„์š”๋กœ ํ•˜๋Š” ์ƒํ™ฉ์—์„œ ๋ฐœ์ƒํ•จ-> ์ฆ‰, ์„œ๋กœ ํ•„์š”ํ•œ ์ƒํ™ฉ ์•ฝ๊ฐ„ ์‰ฝ๊ฒŒ ํ˜„์‹ค์ƒํ™ฉ์—์„œ ์ ‘๊ทผํ•ด๋ณด๋ฉด, ..ํ 


  • ์ข‹์€ ์ง์—…์„ ์–ป์œผ๋ ค๋ฉด ๊ฒฝ๋ ฅ์ด ํ•„์š”ํ•˜๋‹ค

  • ํ•˜์ง€๋งŒ ๊ฒฝ๋ ฅ์„ ์Œ“๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ง์—…์ด ํ•„์š”ํ•˜๋‹ค
    ์™€ ๊ฐ™์€ ์˜ˆ์‹œ๋ฅผ ์ƒ๊ฐํ•˜๋ฉด ์ข€๋” ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šธ ๊ฒƒ์ด๋‹ค

  • ์ด๋Ÿฐ ์ƒํ™ฉ์—์„œ๋Š” Spring์ด ๋นˆ์„ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, UnsatisfiedDependencyException ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•จ


๐Ÿ’ก ์ˆœํ™˜ ์ฐธ์กฐ ๋ฐœ์ƒ (JwtTokenFilter์™€ SecurityConfig)

ํ•„์ž ๊ฒฝ์šฐ ํ† ํฐ์„ ๊ฒ€์ฆํ•˜๋Š” JwtTokeFilter์™€ SecurityConfig ์ˆœํ™˜์ฐธ์กฐ๊ฐ€ ๋ฐœ์ƒํ–ˆ์—ˆ๋‹ค

JwtTokenFilter.java

@Component
@RequiredArgsConstructor
public class JwtTokenFilter extends OncePerRequestFilter {

    private final JwtUtil jwtUtil;
    private final UserRepository userRepository;
    private final CsrfTokenRepository csrfTokenRepository;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        String authHeader = request.getHeader("Authorization");

        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);

            try {
                Long userId = jwtUtil.getUserIdFromToken(token).get("userId", Long.class);
                User user = userRepository.findById(userId).orElse(null);

                CsrfToken csrfToken = csrfTokenRepository.loadToken(request);
                String csrfHeader = request.getHeader("X-CSRF-TOKEN");

                if (csrfToken == null || csrfHeader == null || !csrfToken.getToken().equals(csrfHeader)) {
                    response.sendError(HttpServletResponse.SC_FORBIDDEN, "CSRF token invalid or missing");
                    return;
                }

                if (user != null) {
                    UsernamePasswordAuthenticationToken authentication =
                            new UsernamePasswordAuthenticationToken(user, null, null);
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                } else {
                    response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid token: User not found");
                    return;
                }

            } catch (Exception e) {
                response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid token");
                return;
            }
        }

        filterChain.doFilter(request, response);
    }
}
  • JwtTokenFilter๋Š” CsrfTokenRepository๋ฅผ ์ฃผ์ž…๋ฐ›์•„ ์š”์ฒญ์—์„œ CSRF ํ† ํฐ์„ ๊ฒ€์ฆ

SecurityConfig.java

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {

    private final JwtTokenFilter jwtTokenFilter; 

    @Bean
    public RoleHierarchy roleHierarchy() {
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_OWNER \n ROLE_OWNER > ROLE_USER");
        return roleHierarchy;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .csrf(csrf -> csrf
                        .csrfTokenRepository(csrfTokenRepository())  // CSRF ํ† ํฐ ์ฟ ํ‚ค ์ €์žฅ
                )
                .formLogin(formLogin -> formLogin.disable())
                .httpBasic(httpBasic -> httpBasic.disable())
                .cors(cors -> cors.configurationSource(corsConfigurationSource()))
                .headers(headers -> headers
                        .frameOptions(frameOptions -> frameOptions.disable())
                )
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/api/auth/*", "/api/auth/refresh", "/h2-console/**").permitAll()
                        .anyRequest().authenticated()
                )
                .addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class);  // JWT ํ•„ํ„ฐ ์ถ”๊ฐ€

        return http.build();
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
        return configuration.getAuthenticationManager();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedOriginPattern("*");
        configuration.addAllowedMethod("*");
        configuration.addAllowedHeader("*");
        configuration.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    @Bean
    public CsrfTokenRepository csrfTokenRepository() {
        CookieCsrfTokenRepository repository = new CookieCsrfTokenRepository();
        repository.setCookieHttpOnly(false);  // ์ฟ ํ‚ค ์ ‘๊ทผ ๊ฐ€๋Šฅ
        repository.setHeaderName("X-CSRF-TOKEN");
        repository.setCookieName("XSRF-TOKEN");
        return repository;
    }
}
  • SecurityConfig๋Š” JwtTokenFilter๋ฅผ ์ฃผ์ž…๋ฐ›์•„ ํ•„ํ„ฐ ์ฒด์ธ์— ๋“ฑ๋กํ•จ
    ๋™์‹œ์— CsrfTokenRepository๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋กํ•˜์—ฌ CSRF ํ† ํฐ์„ ๊ด€๋ฆฌํ•จ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”
| jwtTokenFilter (field private org.springframework.security.web.csrf.CsrfTokenRepository com.example.login.JWT.JwtTokenFilter.csrfTokenRepository)
โ†‘ โ†“
| securityConfig defined in file
โ””โ”€โ”€โ”€โ”€โ”€โ”˜

์ˆœํ™˜ ์ฐธ์กฐ ๋ฐœ์ƒ ํ๋ฆ„

private final CsrfTokenRepository csrfTokenRepository;

JwtTokenFilter์—์„œ CsrfTokenRepository๋ฅผ ์ฃผ์ž…๋ฐ›์Œ
๋ฌธ์ œ๋Š” CsrfTokenRepository๊ฐ€ SecurityConfig์—์„œ ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋œ๋‹ค๋Š” ์ 

SecurityConfig๋Š” CsrfTokenRepository๋ฅผ ๋นˆ์œผ๋กœ ๋“ฑ๋ก

๐Ÿ”„ ์ˆœํ™˜ ์ฐธ์กฐ ๋ฌธ์ œ ๋ฐœ์ƒ ํ๋ฆ„

  1. SecurityConfig์—์„œ JwtTokenFilter๋ฅผ ํ•„ํ„ฐ ์ฒด์ธ์— ๋“ฑ๋กํ•˜๋ ค๊ณ  ํ•จ
  2. JwtTokenFilter๋Š” CsrfTokenRepository๋ฅผ ์ฃผ์ž…๋ฐ›์•„ ์‚ฌ์šฉํ•ด์•ผ ํ•จ
    ํ•˜์ง€๋งŒ CsrfTokenRepository๋Š” SecurityConfig์—์„œ ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋˜์–ด ์žˆ์Œ.
  3. ๋”ฐ๋ผ์„œ, SecurityConfig๊ฐ€ JwtTokenFilter๋ฅผ ์ฃผ์ž…ํ•˜๋Š” ๊ณผ์ •์—์„œ JwtTokenFilter๊ฐ€ ๋‹ค์‹œ CsrfTokenRepository๋ฅผ ํ•„์š”๋กœ ํ•˜๊ฒŒ ๋˜์–ด ์ˆœํ™˜ ์ฐธ์กฐ๊ฐ€ ๋ฐœ์ƒ!

์ฆ‰, SecurityConfig์—์„œ JwtTokenFilter๋ฅผ ํ•„ํ„ฐ๋กœ ๋“ฑ๋กํ• ๋ ค๊ณ  ํ• ๋•Œ JwtTokenFilter๋Š” CsrfTokenRepository๋ฅผ ์ฃผ์ž…๋ฐ›์•„์•ผ๋งŒ ์ƒ์„ฑ์ด ๊ฐ€๋Šฅํ•จ
๋ฐ˜๋ฉด์—, CsrfTokenRepository๋Š” SecurityConfig์—์„œ ๋นˆ์œผ๋กœ ๋“ฑ๋ก ๋˜์–ด์žˆ๋‹ค
๊ทธ๋ž˜์„œ ์‹œํ๋ฆฌํ‹ฐ๊ฐ€ ํ† ํฐํ•„ํ„ฐ ๋งŒ๋“ค๊ณ ์‹ถ์€๋ฐ ํ† ํฐํ•„ํ„ฐ๋Š” ์‹œํ๋ฆฌํ‹ฐ์— ๋นˆ์œผ๋กœ ๋“ฑ๋ก๋œ CsrfTokenRepository ์ด๊ฒŒ ํ•„์š”ํ•ด์„œ
SecurityConfig โ†’ JwtTokenFilter โ†’ CsrfTokenRepository
์„œ๋กœ๊ฐ€ ์„œ๋กœ๋ฅผ ํ•„์š”ํ•œ ์ƒํ™ฉ์ž„!


๐Ÿš€ ์ˆœํ™˜ ์ฐธ์กฐ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

1. CsrfTokenRepository๋ฅผ ์ง์ ‘ ์ฃผ์ž…ํ•˜์ง€ ์•Š๊ณ , ์š”์ฒญ(Request)์—์„œ ๊ฐ€์ ธ์˜ค๊ธฐ

  • JwtTokenFilter์—์„œ CsrfTokenRepository ๋Œ€์‹  ์š”์ฒญ ๊ฐ์ฒด(HttpServletRequest)์—์„œ CSRF ํ† ํฐ์„ ๊ฐ€์ ธ์˜ด.

JwtTokenFilter ์ˆ˜์ •:

@Component
@RequiredArgsConstructor
public class JwtTokenFilter extends OncePerRequestFilter {
    private final JwtUtil jwtUtil;
    private final UserRepository userRepository;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        String authHeader = request.getHeader("Authorization");

        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);
            try {
                Long userId = jwtUtil.getUserIdFromToken(token).get("userId", Long.class);
                User user = userRepository.findById(userId).orElse(null);

                // ์š”์ฒญ์—์„œ ์ง์ ‘ CSRF ํ† ํฐ ๊ฐ€์ ธ์˜ค๊ธฐ
                CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
                String csrfHeader = request.getHeader("X-CSRF-TOKEN");

                if (csrfToken == null || csrfHeader == null || !csrfToken.getToken().equals(csrfHeader)) {
                    response.sendError(HttpServletResponse.SC_FORBIDDEN, "CSRF token invalid or missing");
                    return;
                }

                UsernamePasswordAuthenticationToken authentication =
                        new UsernamePasswordAuthenticationToken(user, null, null);
                SecurityContextHolder.getContext().setAuthentication(authentication);
            } catch (Exception e) {
                response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid token");
                return;
            }
        }
        filterChain.doFilter(request, response);
    }
}

[ ํ๋ฆ„ ]
์šฐ์„  , CsrfTokenRepository๋Š” CSRF ํ† ํฐ์„ ์ƒ์„ฑ, ์ €์žฅ, ๋กœ๋“œํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค
CSRF ํ† ํฐ์€ HttpServletRequest์˜ ์†์„ฑ(attribute)์— ์ €์žฅ
์ดํ›„ ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ JwtTokenFilter๋Š” httpServletRequest์—์„œ CSRF ํ† ํฐ์„ ๊บผ๋‚ด ๊ฒ€์ฆ

์ˆœํ™˜์ฐธ์กฐ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์ฝ”๋“œ ๊ฒฝ์šฐ,
ํ•„ํ„ฐ์—์„œ ์ง์ ‘CsrfTokenRepository ์ด์šฉํ•ด์„œ ํ•„ํ„ฐ์—์„œ ์ฃผ์ž…๋ฐ›์•„ ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ๋งˆ๋‹ค csrfTokenRepository.loadToken(request)๋กœ CSRF ํ† ํฐ์„ ๊ฐ€์ ธ์™€ ๊ฒ€์ฆํ–ˆ์—ˆ๋‹ค

CsrfToken csrfToken = csrfTokenRepository.loadToken(request);

ํ•˜์ง€๋งŒ ์ˆœํ™˜์ฐธ์กฐ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๊ณ ..

[ ํ•ด๊ฒฐ๋ฐฉ๋ฒ• ]

CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName());

Spring Security๋Š” CsrfFilter์—์„œ CSRF ํ† ํฐ์„ ์ƒ์„ฑํ•˜๊ณ 
HttpServletRequest์˜ ์†์„ฑ์— ์ €์žฅํ•จ
ํ•„ํ„ฐ์—์„œ ์ง์ ‘ CsrfTokenRepository๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ ,
=>SecurityConfig์™€ JwtTokenFilter ๊ฐ„์˜ ์˜์กด์„ฑ์ด ์‚ฌ๋ผ์ง€๋ฉด์„œ ์ˆœํ™˜ ์ฐธ์กฐ๊ฐ€ ํ•ด๊ฒฐ๋จ


Q.๊ทธ๋Ÿผ HttpServletRequest์‚ฌ์šฉํ• ๋•Œ๋Š” ์ˆœํ™˜์ฐธ์กฐ๊ฐ€ ์ผ์–ด๋‚˜์ง€ ์•Š์„๊นŒ?

๐Ÿ˜บ : ํ•„์ž ๊ฒฝ์šฐ ๊ณต๋ถ€๋ฅผ ํ•˜๋ฉด์„œ CsrfTokenRepository๋ฅผ ์‚ฌ์šฉํ• ๊ฒฝ์šฐ ์ˆœํ™˜์ฐธ์กฐ ๋ฐœ์ƒํ•œ๋‹ค๊นŒ์ง€๋Š” ์•Œ๊ฒ ๋Š”๋ฐ ๊ทธ๋Ÿผ ์™œ ๋ฐœ์ƒํ–ˆ์„๊นŒ๋ผ๋Š” ์˜๋ฌธ์ด ๋“ค์—ˆ๋‹ค
CsrfTokenRepository๊ฒฝ์šฐ๋Š” CSRFํ† ํฐ์„ ์ƒ์„ฑํ•˜๊ณ  ์ €์žฅํ•œ๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ ๊ทธ๊ฑธ HttpServletRequest์— ์ €์žฅํ•œ๋‹ค๊นŒ์ง€๋Š” ์•Œ๊ฒ ๋‹ค..! ๊ทผ๋ฐ ์™œ์ง€ ์™ค๊นŒ? ๋ผ๋Š” ์ƒ๊ฐ์ด๋“ค์–ด ํ๋ฆ„์„ ๋‹ค์‹œ ์ดํ•ดํ• ๋ ค๊ณ  ํ–ˆ๋‹ค


์ฆ‰, ์ผ๋‹จ ์ƒํ™ฉ์„ ๋‹ค์‹œ ์„ค๋ช…ํ•ด๋ณด๋ฉด
๊ณผ๊ฑฐ ๋ฐฉ์‹

  • ํ•„ํ„ฐ๊ฐ€ ์ง์ ‘ CsrfTokenRepository๋ฅผ ํ˜ธ์ถœํ•ด ํ† ํฐ์„ ๋ถˆ๋Ÿฌ์˜ด
  • ๋งค๋ฒˆ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ์ฟ ํ‚ค์—์„œ ์กฐํšŒ
  • ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ๋งˆ๋‹ค CsrfTokenRepository๊ฐ€ ํ† ํฐ์„ ์ƒ์„ฑํ•˜๊ณ  ๊ฒ€์ฆ
    ์ƒˆ ๋ฐฉ์‹
  • ์š”์ฒญ(HttpServletRequest)์—์„œ ํ† ํฐ์„ ๋ฐ”๋กœ ๊บผ๋ƒ„
  • CsrfFilter๊ฐ€ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด์„œ ๋„ฃ์–ด๋‘” ๊ฒƒ์„ ๊บผ๋‚ด๊ธฐ๋งŒ ํ•จ
  • ํ•œ ๋ฒˆ ์ƒ์„ฑ๋œ ํ† ํฐ์„ ์š”์ฒญ ๊ฐ์ฒด(HttpServletRequest)์— ๋ณด๊ด€


    ํ•„์ž๋Š” ์—ฌ๊ธฐ์„œ ํ˜ผ๋™์ด ์™”๋˜๊ฒƒ ๊ฐ™๋‹ค ์–ด์งธ๋“  ๋‘˜๋‹ค ํ† ํฐ์„ ๋ถˆ๋Ÿฌ์™€์„œ ๊ฒ€์ฆํ•˜๋Š” ๊ฑด๋ฐ ์™œ ์ˆœํ™˜์ฐธ์กฐ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”๊ฑด์ง€, ์™œ CsrfTokenRepository์—์„œ๋งŒ ์ˆœํ™˜์ฐธ์กฐ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ์˜๋ฌธ์ด ๊ณ„์† ๋“ค์—ˆ๋‹ค
    ๊ฒฐ๋ก ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค

HttpServletRequest ๊ฒฝ์šฐ CSRF ํ† ํฐ์€ ์ตœ์ดˆ ์š”์ฒญ์—์„œ ํ•œ ๋ฒˆ๋งŒ ์ƒ์„ฑ
์ด๊ฒŒ ํ•ต์‹ฌ ํฌ์ธํŠธ์ธ๊ฒƒ ๊ฐ™๋‹ค

  • ์ดํ›„ ๋ชจ๋“  ์š”์ฒญ์—์„œ ์ด๋ฏธ ๋งŒ๋“ค์–ด์ง„ CSRF ํ† ํฐ์„ HttpServletRequest์—์„œ ์ง์ ‘ ์กฐํšŒํ•˜์—ฌ ๊ฒ€์ฆ

๊ทธ๋Ÿฌ๋ฉด, ์ด ๋ฐฉ์‹๋„ ๊ฒฐ๊ตญ ํ† ํฐ์„ ์ƒ์„ฑํ•ด์„œ ๊ฒ€์ฆํ•ด์•ผํ•˜๋Š” ๊ฑฐ๋ฉด ์„œ๋กœ๊ฐ€ ํ•„์š”ํ•ด์„œ ์ˆœํ™˜์ฐธ์กฐ ์ผ์–ด๋‚  ์ˆ˜ ์žˆ์ง€์•Š์„๊นŒ? ๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์ˆ˜ ์žˆ๋‹ค

๐Ÿงฉ์ตœ์ดˆ CSRF ํ† ํฐ์€ ์–ด๋–ป๊ฒŒ ๋งŒ๋“ค์–ด์ง€๋‚˜?

  • CSRF ํ† ํฐ์€ CsrfFilter๊ฐ€ ์ตœ์ดˆ ์š”์ฒญ์—์„œ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  HttpServletRequest์— ์ €์žฅ
  • JwtTokenFilter๋Š” ์ดํ›„ ์š”์ฒญ์—์„œ ์š”์ฒญ ๊ฐ์ฒด(HttpServletRequest)์—์„œ CSRF ํ† ํฐ์„ ๋ฐ”๋กœ ๊บผ๋‚ด ์‚ฌ์šฉ ํ•˜๋Š” ํ”„๋กœ์„ธ์ž„

์ดˆ๊ธฐ์— ์ƒ์„ฑ์€ ์ˆœํ™˜์ฐธ์กฐ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Œ!
-> CsrfFilter๋Š” SecurityConfig์™€ ๋…๋ฆฝ์ ์œผ๋กœ ๋™์ž‘
-> ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ดˆ๊ธฐํ™” ์‹œ(๊ตฌ๋™) Spring Security๊ฐ€ ์ž๋™์œผ๋กœ ๋™์ž‘ํ•ด CSRF ํ† ํฐ์„ ์ƒ์„ฑ
๊ฒฐ๊ตญ, ์‹คํ–‰์‹คํ‚ฌ๋•Œ CSRFํ† ํฐ์ด ๋ฐœ๊ธ‰๋˜์–ด, ์ดํ›„ ์š”์ฒญ์—์„œ๋Š” JwtTokenFilter๊ฐ€ HttpServletRequest์—์„œ ์กฐํšŒ๋งŒ ํ•˜๋ฉด ๋˜์–ด์„œ ์ˆœํ™˜์ฐธ์กฐ๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค!

์ •๋ฆฌ

1. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ดˆ๊ธฐํ™” โ€“ CSRF ํ† ํฐ ์ƒ์„ฑ (์ˆœํ™˜ ์ฐธ์กฐ ์—†์Œ)

  1. Spring Security๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๊ตฌ๋™๋  ๋•Œ CsrfFilter๋ฅผ ์ž๋™์œผ๋กœ ๋“ฑ๋ก ๋ฐ ์‹คํ–‰
  2. ์ดˆ๊ธฐํ™” ์‹œ CsrfTokenRepository๋ฅผ ์‚ฌ์šฉํ•ด CSRF ํ† ํฐ์„ ์ƒ์„ฑํ•˜๊ณ , ์ด ํ† ํฐ์„ ์ฟ ํ‚ค ๋ฐ HttpServletRequest์˜ ์†์„ฑ(attribute)์— ์ €์žฅ
  3. ์ด ๊ณผ์ •์—์„œ๋Š” JwtTokenFilter๊ฐ€ ์ „ํ˜€ ๊ด€์—ฌํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์ˆœํ™˜ ์ฐธ์กฐ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Œ

2. ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ

  1. ์‚ฌ์šฉ์ž๊ฐ€ API ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ
  2. JwtTokenFilter๋Š” HttpServletRequest์—์„œ CSRF ํ† ํฐ์„ ๋ฐ”๋กœ ์กฐํšŒํ•˜์—ฌ ๊ฒ€์ฆ
  3. JwtTokenFilter๋Š” CsrfTokenRepository๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜์ง€ ์•Š๊ณ ,
    HttpServletRequest์— ์ €์žฅ๋œ ํ† ํฐ์„ ๊บผ๋‚ด๊ธฐ๋งŒ ํ•˜๋ฉด ๋จ!
profile
์–ด๋–ค ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜๊ณ ์‹ถ๋‚˜

0๊ฐœ์˜ ๋Œ“๊ธ€