[Spring] Security + Redis Session

민스킴·2024년 12월 30일
0

Spring

목록 보기
14/14

발단

Spring Boot + Spring Security에서 Redis를 Session으로 사용하여 AuthenticatedPrincipal 커스텀 구현체인 KakaoUser를 만들어 저장하는 과정에서 오류가 발생하고 있습니다.

Caused by: java.lang.IllegalArgumentException: 
The class with java.lang.Long and name of java.lang.Long is not in the allowlist. 
If you believe this class is safe to deserialize, please provide an explicit mapping using Jackson annotations or by providing a Mixin. 
If the serialization is only done by a trusted source, you can also enable default typing. 
See https://github.com/spring-projects/spring-security/issues/4370 for details at 
.
.
.

위와 같은 오류가 발생 했습니다. 발생하는 이유는 다음과 같습니다.
(오류 로그에서 여기를 주목: See https://github.com/spring-projects/spring-security/issues/4370 for details)

갈등

이 오류는 Spring Security의 Jackson2 모듈에서 직렬화/역직렬화 보안 강화를 위해 기본적으로 허용되지 않은 클래스(java.lang.Long 등)를 역직렬화하려고 할 때 발생합니다.
(예시: “The class with java.lang.Long and name of java.lang.Long is not in the allowlist…”)

Spring Security 5.4(또는 그 이상)부터, SecurityJackson2Modules라는 것이 도입되어 Jackson 직렬화/역직렬화 과정에서 특정 클래스만 허용하도록 제한을 두고 있습니다.
따라서 Long(또는 다른 클래스)이 세션 직렬화/역직렬화 중에 등장하면, 기본 allowlist(허용 목록)에 없다는 이유로 예외가 발생하게 됩니다.

정리하자면, Spring Security가 보안상 이유로 allowlist에 등록된 클래스만 역직렬화를 허용한다는 뜻 입니다.

해결

해결책은 크게 2가지를 찾았습니다.
1. Mixin을 사용해서 명시적으로 특정 클래스를 허용
2. defalut typing 활성화

저는 1번 방법인 Mixin을 사용해서 해결 했습니다.


/**
 * KakaoUser Mixin 설정
 * 역직렬화 시 허용된 클래스만 가능하도록 하기 때문에
 * */
@JsonTypeInfo(
        use = JsonTypeInfo.Id.CLASS,
        include = JsonTypeInfo.As.PROPERTY,
        property = "@class"
)
public abstract class KakaoUserMixin {
}

/**
 * Spring Session Serializer 설정
 * */
@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer(ObjectMapper objectMapper) {

    ClassLoader loader = this.getClass().getClassLoader();

    objectMapper.addMixIn(KakaoUser.class, KakaoUserMixin.class);
    objectMapper.addMixIn(Long.class, KakaoUserMixin.class);
    objectMapper.addMixIn(List.of("ImmutableCollections$List12").getClass(), KakaoUserMixin.class);

    objectMapper.registerModules(SecurityJackson2Modules.getModules(loader));

    return new GenericJackson2JsonRedisSerializer(objectMapper);
}

마무리

Spring Security는 사용할 때 마다 계속 새로운 것을 알아가는 것 같습니다.
꾸준히 계속 배우다보면 언젠가는 능숙하게 사용할 수 있으리라 믿습니다.

profile
Boys, be ambitious!

0개의 댓글