프론트엔드 애플리케이션의 메모리에 데이터를 저장할 수 있다.
그러나 이 방법은 브라우저가 닫히면 데이터가 소멸되므로 장기적인 보관이 필요한 민감한 정보에는 적합하지 않다.
쿠키는 브라우저에 저장되므로 보안 상의 이슈가 있을 수 있다.
한 정보를 저장할 때는 쿠키를 암호화하거나 토큰 기반의 인증 시스템과 함께 사용하여 보안을 강화해야 한다.
HTML5에서 도입된 웹 스토리지인 localStorage 또는 sessionStorage를 사용하여 데이터를 저장할 수 있다.
하지만 이러한 스토리지는 클라이언트 측에서 접근 가능하므로 보안에 주의해야 한다.
localStorage에 저장할 때 암호화를 적용하는 방법은 다양합니다. 다음은 localStorage에 저장할 때 추천하는 암호화 방법 중 일부입니다:
CryptoJS는 JavaScript에서 암호화를 수행하기 위한 라이브러리이다.
AES, DES, Triple DES, Rabbit, RC4 등 다양한 암호화 알고리즘을 지원한다.
CryptoJS 객체를 사용하여 데이터를 암호화하고 복호화할 수 있다.
Web Crypto API는 웹 브라우저에서 암호화 기능을 제공하는 웹 표준이다.
이 API를 사용하여 브라우저에서 데이터를 암호화하고 복호화할 수 있다.
하지만 모든 브라우저에서 동일한 지원을 보장하지 않으므로 브라우저 호환성에 주의해야 한다.
웹 브라우저에서 제공하는 암호화 기능을 사용하지 않고, 직접 암호화 알고리즘을 구현할 수도 있다.
JavaScript에서 암호화를 위한 함수와 알고리즘을 작성하여 데이터를 암호화하고 복호화할 수 있다.
물론 이 경우에는 보안 전문가와의 협력해야한다.
키 관리: 암호화에 사용되는 키를 안전하게 보관해야 한다. 키를 분실하거나 유출되면 데이터 보호가 위협받을 수 있다.
성능: 암호화는 추가적인 계산을 필요로 하므로 성능에 영향을 줄 수 있다. 암호화 알고리즘을 선택할 때 성능 측면 또한 고려해야 한다.
보안 강화: 데이터를 암호화할 때만으로는 부족하다.
사용자 데이터를 보호하기 위해 암호화 외에도 접근 제어, 입력 검증, 보안 헤더 설정 등 다른 보안 메커니즘을 함께 사용해야 한다.
따라서, 브라우저 호환성이 중요한 경우에는 CryptoJS를 사용하는 것이 좋을 수 있다.
그러나 최신 브라우저를 타겟으로 하고 웹 표준을 따르는 것이 중요한 경우에는 Web Crypto API를 사용하는 것이 더 적합하다.
// 데이터를 암호화하는 함수.
const encryptData = async (data) => {
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(data);
// 웹 크립토 API를 사용하여 데이터를 암호화.
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt']
);
const encryptedBuffer = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv: crypto.getRandomValues(new Uint8Array(12)) },
key,
dataBuffer
);
// 암호화된 데이터를 Base64로 인코딩하여 반환.
return btoa(String.fromCharCode.apply(null, new Uint8Array(encryptedBuffer)));
};
위의 코드는 axios를 사용하여 서버에 로그인 요청을 보내고 응답으로 받은 사용자 정보를 sessionStorage에 암호화하여 저장하는 예시이다.
데이터를 암호화하기 위해 Web Crypto API
의 AES-GCM
암호화 알고리즘을 사용하였다.
물론 위 코드는 단순한 예시일 뿐이며, 실제로 사용할 때에는 암호화 키 관리, 인증 처리, 예외 처리 등을 고려해야 한다.
또한, 복호화 시에는 저장된 데이터를 복호화하여 사용해야 한다.
// sessionStorage에서 암호화된 사용자 데이터를 가져와 디코드하여 복호화하는 함수.
const decryptUserData = async (data) => {
// 변수로 sessionStorage에서 암호화된 데이터를 넘겨줌.
const encryptedData = data;
if (!encryptedData) {
// 암호화된 데이터가 없으면 처리할 로직을 추가해야함.
return null;
}
// Base64로 인코딩된 암호화된 데이터를 디코드.
const encryptedBuffer = Uint8Array.from(atob(encryptedData), c => c.charCodeAt(0));
// 웹 크립토 API를 사용하여 데이터를 복호화.
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['decrypt']
);
const decryptedBuffer = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv: crypto.getRandomValues(new Uint8Array(12)) },
key,
encryptedBuffer
);
// 디코드된 데이터를 문자열로 변환하여 반환.
const decoder = new TextDecoder();
const decryptedData = decoder.decode(decryptedBuffer);
// JSON 형태로 파싱하여 사용자 데이터 객체로 반환.
return JSON.parse(decryptedData);
};
위의 코드는 매개변수로 sessionStorage에서 암호화된 데이터를 넘겨주면 디코드 및 복호화하여 사용자 데이터를 보여주는 예시이다.
이전에 사용한 암호화 과정과 동일한 AES-GCM 암호화 알고리즘을 사용하여 복호화를 수행한다.
복호화 과정에서 예외 처리와 오류 처리를 적절하게 추가해야 한다.
암호화된 데이터의 복호화는 암호화된 데이터와 해당 암호화에 사용된 키와 알고리즘 등의 정보가 필요하다.
이러한 정보를 안전하게 관리하고 보호하는 것 또한 굉장히 중요한 요소이다.
전송 보안: 암호화된 데이터를 전송하는 경우, 데이터의 무결성과 기밀성을 보장하기 위해 HTTPS
와 같은 보안 프로토콜을 사용하는 것이 좋다.
보안 강화: 암호화된 데이터를 저장할 때 추가적인 보안 강화를 고려할 수 있다.
예를 들어, 사용자의 추가 인증 요소를 사용하거나 암호화된 데이터를 분리하여 저장하는 등의 방법을 고려할 수 있다.
암호화 키의 주기적인 갱신: 암호화 키는 일정한 주기로 변경하여 보안을 강화하는 것이 좋다.
키를 주기적으로 갱신하고 이전 키를 폐기하는 정책을 수립하는 것이 좋다.
import CryptoJS from 'crypto-js';
const plaintext = 'Hello, World!'; // 암호화할 텍스트
const key = CryptoJS.enc.Hex.parse('0123456789abcdef0123456789abcdef'); // 256비트 암호화 키
const iv = CryptoJS.enc.Hex.parse('abcdef9876543210abcdef9876543210'); // 초기화 벡터
// 텍스트 암호화
const encrypted = CryptoJS.AES.encrypt(plaintext, key, { iv: iv });
// 암호화된 결과를 Base64로 인코딩
const encryptedBase64 = encrypted.toString();
console.log(encryptedBase64); // 암호화된 결과 출력
CryptoJS.AES.encrypt
함수를 사용하여 텍스트를 암호화하고, 암호화된 결과를 Base64로 인코딩하여 출력하도록 설정하였다.import CryptoJS from 'crypto-js';
const decodeFn = (data) => {
const encryptedBase64 = data; // 암호화된 Base64 데이터
const key = CryptoJS.enc.Hex.parse('0123456789abcdef0123456789abcdef'); // 256비트 암호화 키
const iv = CryptoJS.enc.Hex.parse('abcdef9876543210abcdef9876543210'); // 초기화 벡터
// Base64로 인코딩된 암호화된 데이터를 디코드
const ciphertext = CryptoJS.enc.Base64.parse(encryptedBase64);
// 텍스트 복호화
const decrypted = CryptoJS.AES.decrypt(
{ ciphertext: ciphertext },
key,
{ iv: iv }
);
// 복호화된 결과를 문자열로 변환
const decryptedText = decrypted.toString(CryptoJS.enc.Utf8);
return decryptedText
}
참고로 복호화 과정에서는 암호화에 사용된 키(key)와 초기화 벡터(iv)를 지정해야한다.
CryptoJS.enc.Base64.parse() 함수를 사용하여 Base64로 인코딩된 암호화된 데이터를 디코드한 뒤, CryptoJS.AES.decrypt() 함수를 사용하여 텍스트를 복호화한다.
최종적으로 toString() 함수를 사용하여 복호화된 결과를 문자열로 변환하고 출력한다.
암호화에서 키(key)와 초기화 벡터(iv)는 보안성을 위해 매우매우매우 중요한 역할을 한다.
키는 암호화 및 복호화에 사용되는 비밀 값으로, 안전하고 예측할 수 없는 값을 가져야 한다.
초기화 벡터는 블록 암호화 모드에서 사용되며, 각 암호화 작업마다 고유한 값을 가져야 한다.
따라서, 키와 초기화 벡터는 보안에 매우 중요하며, 무작위성과 예측 불가능성이 요구된다.
즉, 랜덤한 값을 사용하거나 안전한 난수 생성기를 통해 생성하는 것이 좋다.
// 256비트 암호화 키 생성
const key = CryptoJS.lib.WordArray.random(32);
// 초기화 벡터 생성
const iv = CryptoJS.lib.WordArray.random(16);
async function encryptData(data) {
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(data);
// 웹 크립토 API를 사용하여 데이터를 암호화.
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt']
);
const initializationVector = crypto.getRandomValues(new Uint8Array(12));
const encryptedBuffer = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv: initializationVector },
key,
dataBuffer
);
// 암호화된 데이터를 Base64로 인코딩하여 반환.
const encryptedData = btoa(String.fromCharCode.apply(null, new Uint8Array(encryptedBuffer)));
// 암호화된 데이터와 초기화 벡터를 sessionStorage에 저장.
sessionStorage.setItem('encryptedData', encryptedData);
sessionStorage.setItem('initializationVector', JSON.stringify([...initializationVector]));
return encryptedData;
}
async function decryptData(data) {
// 변수로 sessionStorage에서 암호화된 데이터와 초기화 벡터를 가져옴.
const encryptedData = data;
const initializationVector = JSON.parse(sessionStorage.getItem('initializationVector'));
if (!encryptedData || !initializationVector) {
// 암호화된 데이터가 없으면 처리할 로직을 추가해야함.
return null;
}
// Base64로 인코딩된 암호화된 데이터를 디코드.
const encryptedBuffer = new Uint8Array(atob(encryptedData).split('').map(c => c.charCodeAt(0)));
// 웹 크립토 API를 사용하여 데이터를 복호화.
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['decrypt']
);
const decryptedBuffer = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv: new Uint8Array(initializationVector) },
key,
encryptedBuffer
);
// 디코드된 데이터를 문자열로 변환하여 반환.
const decoder = new TextDecoder();
const decryptedData = decoder.decode(decryptedBuffer);
// JSON 형태로 파싱하여 사용자 데이터 객체로 반환.
return JSON.parse(decryptedData);
}