ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [수정 예정] 사진을 더 안전하게 저장하기 - AES 알고리즘 적용
    개발/Spring Boot 2024. 5. 27. 10:35

    암호화를 하게 된 배경

    제3자도 접근 파일 시스템에 가능한 공용서버

    우리 서버 애플리케이션이 동아리 공용 서버에서 작동하게 될 예정이다. 동아리 공용 서버는 여러 동아리원들이 공유하는 서버로 다양한 사용자와 관리자들이 접근할 수 있다. 이러한 환경에서는 여러 사람이 서버에 접근할 수 있어, 보안에 취약할 가능성이 높다.

    특히, 서버의 파일 시스템은 여러 프로젝트의 파일을 저장하고 관리하기 때문에 제3자가 파일에 접근할 위험이 존재한다.

    이와 같은 이유로, 중요한 사용자 데이터인 사진 파일을 보호하기 위해서는 암호화가 필수적이라고 판단했다. 암호화를 통해 파일을 안전하게 보호하면, 설령 제3자가 서버에 접근하더라도 암호화된 파일을 해독하지 못해 데이터의 기밀성을 유지할 수 있을 것이라 생각했다.

    AES 알고리즘이란?

    AES(Advanced Encryption Standard)는 대칭 키 암호화 알고리즘으로, 데이터의 암호화와 복호화를 동일한 키를 사용하여 수행한다.

    AES는 미국 국립표준기술연구소에 의해 2001년 표준으로 채택되었으며, 현재 전 세계적으로 가장 널리 사용되는 암호화 알고리즘 중 하나이다. AES는 128비트 192비트 256비트의 키 길이를 지원하며, 높은 수준의 보안성을 제공하는 것으로 잘 알려져 있다.

     

    AES는 빠르고 효율적으로 데이터를 암호화할 수 있으며, 하드웨어와 소프트웨어 모두에서 효과적으로 구현될 수 있다. 많은 현대 CPU는 AES 암호화 작업을 가속화하기 위해 AES-NI와 같은 명령어 집합을 포함하고 있어 암호화 작업을 매우 빠르게 수행할 수 있다.

     

    RSA가 아닌 AES를 선택한 이유

    AES는 RSA보다 훨씬 빠른 성능을 제공하며, 특히 대용량 데이터의 암호화 및 복호화 작업에서 RSA의 속도를 크게 앞지른다. 이는 파일 시스템에 데이터를 저장할 때 매우 유리하다. 키 관리 측면에서 AES는 대칭 키 알고리즘이므로 하나의 키로 암호화와 복호화를 모두 수행할 수 있어 키 관리가 상대적으로 간단하다. 반면 RSA와 같은 비대칭 키 암호화 알고리즘은 공개 키와 비공개 키 두 가지를 관리해야 하며, 이는 복잡성을 증가시킨다. 또한, RSA는 일반적으로 작은 데이터 블록의 암호화에 사용되는데, RSA를 사용하여 큰 파일을 직접 암호화하는 것은 매우 비효율적이다. AES는 대용량 데이터를 효율적으로 처리할 수 있도록 설계되었다.

     

    AES 키 관리

    프로젝트에서 AES키를 관리하는 방법은 다음과 같다. AES 키를 생성한 뒤, 생성된 SecretKey 객체를 그대로 데이터 그대로 데이터베이스에 저장한다. 이는 AES 키를 복호화하여 저장할 경우 탈취의 위험이 있기 때문에, 객체 상태 그대로 저장하여 난독화해 놓고자 하는 이유이다. 데이터베이스 테이블 Encryption은 keyId, encryptionKey, userId 필드를 포함하고 있으며 Encryption 객체는 이 필드들로 구성된다. 이를 통해 사용자별로 고유한 암호화 키를 안전하게 관리할 수 있다. 각 Encryption 객체는 사용자의 고유 ID와 매핑되어 있으며, 필요시 암호화된 데이터를 복호화하는 데 사용된다.

    Encryption Table과 User Table

    프로젝트 적용

    private WritePhotoToFileSystemResult savePhotoToFileSystem(User user, MultipartFile multipartFile, boolean isPrivate) {
            try {
                if (isPrivate) {
                    Encryption encryption = encryptionComponent.setEncryption(user);
                    byte[] encryptedData = encryptionComponent.encryptData(encryption, multipartFile.getInputStream().readAllBytes());
                    return fileComponent.writePhotoToFileSystem(multipartFile.getOriginalFilename(), multipartFile.getContentType(), encryptedData);
                } else {
                    return fileComponent.writePhotoToFileSystem(multipartFile.getOriginalFilename(), multipartFile.getContentType(), multipartFile.getInputStream().readAllBytes());
                }
            } catch (Exception e) {
                log.error(e.getMessage());
                throw new CustomException(ExceptionCode.FILE_READ_ERROR);
            }
        }

    savePhotoToFileSystem이라는 메서드는 파일이 비공개인 경우, setEncryption 메서드를 통해 사용자에 대한 암호화 키를 가져오거나 생성하며, 이를 사용하여 파일 데이터를 암호화한다.

    public Encryption setEncryption(User user) {
            Encryption encryption = encryptionRepository.findByUser(user);
            if (encryption == null) {
                encryption = createSecretKey(user);
            }
            return encryption;
        }
        
    private Encryption createSecretKey(User user) {
            try {
                SecretKey secretKey = EncryptionUtil.generateAESKey();
                return encryptionRepository.save(
                    Encryption.builder()
                            .secretKey(secretKey)
                            .user(user)
                            .build()
                );
            } catch (Exception e) {
                log.error(e.getMessage());
            }
            throw new CustomException(ExceptionCode.ENCRYPTION_ERROR);
        }

     

    setEncryption 메서드는 사용자에 대한 암호화 설정을 데이터베이스에서 조회하거나 없는 경우, 새로 생성하여 데이터베이스에 저장한다.

    createSecretKey 메서드는 AES키를 생성하고 이를 데이터베이스에 저장하는 기능을 한다.

    public byte[] encryptData(Encryption encryption, byte[] fileBytes) {
            try {
                return EncryptionUtil.encryptData(fileBytes, encryption.getSecretKey());
            } catch (Exception e) {
                log.error(e.getMessage());
                throw new CustomException(ExceptionCode.ENCRYPTION_ERROR);
            }
        }

    encryptData는 메서드는 주어진 데이터를 AES 키로 암호화한다.

     

    결론 및 개선점

    AES를 사용하여 파일을 암호화하고 저장하는 방법은 파일 보안을 강화하는데 매우 효과적이었고, AES의 속도와 보안성 덕분에 사용자 데이터를 안전하게 보호할 수 있었다. 그러나, 현재 구현된 방식은 최적의 보안 수준을 보장하지 않는다. 특히 , 키 관리 측면에서 그렇다.

     

    현재 우리는 AES 키를 관리하기 위해 자체적으로 구현한 방법을 사용하고 있지만, 이는 KMS나 HSM을 활용하는 것만큼 안전하지 않다. KMS나 HSM은 키의 생성, 저장, 회전, 폐기 등의 과정을 더 안전하고 효율적으로 관리할 수 있는 전문적인 솔루션이다. 이러한 솔루션을 도입하면 키 관리의 복잡성을 줄이면서도 보안을 강화할 수 있다.

     

    다음 단계에서는 KMS를 도입하여 사용자의 암호화 키를 더 안전하게 보관할 수 있는 방안을 생각해 볼 예정이다.
    이러한 개선점을 통해 프로젝트의 보안을 더욱 강화하고 사용자의 데이터를 보다 안전하게 보호할 수 있을 것이라고 생각한다.

    댓글

Designed by Tistory.