@Value 어노테이션 사용 시 static 변수에 대한 주의사항

승등·2024년 5월 27일

발단

프로젝트 배포를 위해 이것저것 설정을 변경하며, 추후 CI 단계를 생각해 기존 final 클래스로 관리하던 상수를 application.properties 로 옮기고 @Value 어노테이션을 사용하여 변수에 프로퍼티를 주입하여 사용하는 방법으로 변경하였다.

문제없이 적용된 줄 알았으나 프로젝트 상태를 다시 확인하던 중 이상을 발견하였다.
작성 된 일부 리뷰가 정상적으로 조회되지 않는 문제였다.

원인

문제가 되는 리뷰는 리뷰북이 등록되어 있는 경우였다.

java.lang.NullPointerException: Cannot invoke "String.getBytes(String)" because "com.io.threegonew.commons.AesUtil.privateKey_256" is null
   at com.io.threegonew.commons.AesUtil.aesCBCEncode(AesUtil.java:18) ~[main/:na]

프로젝트 개발 당시 리뷰북의 URL에 리뷰북ID가 노출되는 보안상의 문제를 해결하기 위해 AES256 암호화를 구현하여 적용시켜 놓았었다.

AesUtil

package com.io.threegonew.commons;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Hex;
import org.springframework.beans.factory.annotation.Value;

public class AesUtil {

    @Value("${keys.aes.key}")
    private static String privateKey_256;


    public static String aesCBCEncode(String plainText) throws Exception {

        SecretKeySpec secretKey = new SecretKeySpec(privateKey_256.getBytes("UTF-8"), "AES");
        IvParameterSpec IV = new IvParameterSpec(privateKey_256.substring(0,16).getBytes());

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

        cipher.init(Cipher.ENCRYPT_MODE, secretKey, IV);

        byte[] encrpytionByte = cipher.doFinal(plainText.getBytes("UTF-8"));

        return Hex.encodeHexString(encrpytionByte);
    }


    public static String aesCBCDecode(String encodeText) throws Exception {

        SecretKeySpec secretKey = new SecretKeySpec(privateKey_256.getBytes("UTF-8"), "AES");
        IvParameterSpec IV = new IvParameterSpec(privateKey_256.substring(0,16).getBytes());

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

        cipher.init(Cipher.DECRYPT_MODE, secretKey, IV);

        byte[] decodeByte = Hex.decodeHex(encodeText.toCharArray());

        return new String(cipher.doFinal(decodeByte), "UTF-8");
    }
}

 

문제는 privateKey_256 변수에 프로퍼티 값이 정상적으로 주입되지 않아 발생하였다.

@Value를 사용했을 때 값이 null로 반환되는 경우에 대해 찾아 본 결과, 값을 주입할 변수가 static 일 경우 정상적으로 값을 주입받지 못해 null을 반환한다고 한다.

@Value 애너테이션이 property 값을 받아오지 못하는 경우
1. 프로퍼티 이름을 잘못 입력했을 경우
2. Bean으로 등록되지 않은 경우
3. static 변수로 받은 경우
4. 외부에서 해당 클래스를 new로 생성했을 경우

해결

이런 경우에는 static 변수의 setter를 생성하여 setter에 @Value 어노테이션을 사용하는 것으로 문제를 해결 할 수 있다.

주의 - setter 생성과 함께 해당 클래스를 @Component 등록해주어야 한다.

수정된 AesUtil

@Component
public class AesUtil {

    private static String privateKey_256;

    @Value("${keys.aes.key}")
    public void setPrivateKey_256(String privateKey_256) {
        AesUtil.privateKey_256 = privateKey_256;
    }
    
    ... 생략
    
 }

참고

Spring - @Value가 계속 null을 가져올 때 원인과 해결 방법
Spring Boot - static 변수에서 @Value Annotation 사용

profile
기록, 코딩보다 어렵다-!

0개의 댓글