현재 프로젝트를 함께 진행하고 있는 Jun님께서 공유해주신 내용인 JWT 토큰은 여러 온라인 사이트 등 에서 처럼 쉽게 해석할 수 있어 JWT에 사용자 정보가 들어 있다면 쉽게 노출될 가능성이 높습니다.
따라서 페이로드에 저장되고 있는 사용자 정보들은 모두 서버에서만 알 수 있도록 암호화하였는데, 이 부분에 대해서 공유하기 위해 글을 작성해 보았습니다.
1. 중요한 부분만 암호화
- JWT는 Header, Payload, Signature 이렇게 세 부분으로 나뉘어져 있습니다.
- 사용자의 정보가 담겨 있는 payload 부분만을 암호화하여 JWT가 너무 길어지지 않도록 하였습니다.
- 만약 JWT 전체를 암호화 하게 될 경우, 위와 같이 모든 상황에서 JWT를 사용 시 복호화 과정이 필요하게 됩니다.
2. AES 대칭키 사용
암호화와 복호화 모두 서버에서 진행되기 때문에 대칭키를 사용하였습니다.
DES vs AES
- DES는 1970년대부터 설계되었고 56비트의 짧은 키 길이로 [1998년 56시간만에 암호를 해독하는 공격 하드웨어를 만들정도로 보안에 취약합니다.
- DES는 라운드끼리의 의존성도 크지만 AES는 라운드가 독립적이라서 병렬처리의 이점도 더 활용하여 비교적 성능이 빠릅니다.
- 따라서 미국 정부가 채택한 이후로 널리 사용되고 있는 AES(고급 암호화 표준) 암호화 방식을 사용하였습니다.
AES 256 길이를 선택한 이유
- AES는 128, 192, 256 의 길이를 지원하는데
- 2²⁵⁶ 이란 충분히 거대한 영역을 가지게 되어 마찬가지로 거의 충돌이 일어나지 않는다고 볼 수 있고 가장 보안에 뛰어나 256을 사용하게 되었습니다.
3. CBC 구조로 암호화
암호화 구조에는 `EBC`, `CBC`, `CTR`, `OFB`, `CFB` 등의 다양한 구조들이 존재하는데,
그 중에서 저는 파일 및 데이터 암호화에서 가장 널리 사용되고 있는 `CBC`를 학습하여 암호화를 진행하였습니다.
- CBC는 Cipher Block Chaining Mode로 각 평문 블록이 `이전 암호문 블록`과 `XOR` 연산된 후에 암호화 되는 특징을 가지고 있습니다.
- 이는 이전 암호문이 다음 암호문 블록에 영향을 주기 때문에 더 안정적인 보안을 얻을 수 있게 됩니다.
ECB vs CBC
- `ECB`의 암호화의 경우 블록간에 영향을 주지 않고 암호화를 진행하게 되기 때문에 항상 똑같은 `Key`를 가지고 암호화를 진행하게 됩니다.
- 따라서 `ECB`는 항상 같은 Key를 넣으면 같은 결과가 나오므로 위의 사진과 같이 BMP 파일을 암호화하여도 윤곽이 드러나게 됩니다.
- 하지만 `CBC`는 이전 암호문 블록이 다음 암호문 블록에 영향을 주기 때문에 가장 오른쪽 그림과 같이 형태를 알아볼 수 없습니다.
랜덤 IV 사용(Initializing Vector)
- IV를 사용하는 이유는 `동일한 값`을 `동일한 키`로 암호화 하더라도 다른 암호화 된 결과 값을 얻을 수 있도록 사용합니다.
- 때문에 IV를 얼마나 랜덤한 값을 사용하는지에 따라 보안이 더 강화 될 수 있습니다.
- IV는 최초 블록에서 사용되지만 이전 블록의 결과가 이후의 블록 결과에 영향을 미치기 때문에 전혀 다른 결과값을 얻을 수 있게 됩니다.
- 저는 `java.util.Random`의 경우 시간 베이스로 난수를 생성하는 반면 `java.security.SecureRandom`는 OS의 임의 값을 베이스로 랜덤 값을 생성하기 때문에 난수 예측이 매우 힘든 `SecureRandom`로 IV를 생성하였습니다.
✏️ 추가 학습 키워드
CBC 이외에도 여러가지 암호화 구조가 존재하지만, CTR모드와 인증을 결합한 GCM 암호화 구조가 존재한다고 합니다.
GCM는 CBC의 병렬 처리가 불가능 한 단점을 보완하고, 암호화 과정에서 Hash 값을 추가하여 암호문의 무결성 검사도 가능하다고 합니다.
- How does AES GCM encryption work
- AES-GCM과 VAES 인스트럭션
- Why would I ever use AES-256-CBC if AES-256-GCM is more secure?
우선 암호화를 구현하는 것이 제가 처음이라 이번에는 비교적 학습자료가 많은 CBC로 구현하였는데,
추후 CBC와 GCM 두 가지를 직접 성능테스트하여 GCM을 사용하면 어느정도 빨라지는지 글을 작성해보겠습니다.🫡