포스코x코딩온 웹 풀스택 양성과정

[포스코x코딩온] 웹 풀스택 과정 7주차 회고 | 암호화

Codult 2024. 3. 29. 21:51
728x90

 

암호화

단방향 암호화

암호화만 가능한 방식이다. 복호화는 불가능하기 때문에, 한번 암호화된 정보는 바꿀 수 없다.

  • 비밀번호 저장에 주로 사용한다.
  • 암호화 해시함수를 이용하여, Hash 암호화 방식을 사용한다.

해시함수 (Hash Function)

  • 임의의 길이의 데이터를 고정된 길이의 데이터로 반환시켜준다. (출력값은 언제나 동일한 길이)
  • 동일한 데이터에 대해서 항상 동일한 해시 값이 생성된다.
  • 해시(Hash): 해시 함수에 의해 얻어지는 값
  • 해시함수(해시알고리즘): SHA-256, SHA-512, ...

암호 생성

  • crypto를 불러온다. (node.js 내장된 패키지로 별도 설치 필요없음)
const crypto = require('crypto');
  • 아래의 해시생성 명령어를 입력한다.
    .createHash('알고리즘').update('암호화할 값').digest('인코딩방식')
    : 선택한 인코딩 방식으로, 암호화할 값을 선택한 알고리즘에 따라 암호화한다.
const createHashedPassword = (password) => {
  retrun crypto.createHash('sha512').update(password).digest('base64');
};

 

※인코딩 방식 'base64'
: 64개의 가능한 문자로 데이터를 인코딩하는 방식이다.
(그 중 62개는 영문 대소문자와 10진수 숫자로 이루어짐. 나머지 2개는 인코딩과 디코딩 과정에서 추가적인 문자로 사용됨)

암호화 보완

해시함수로 생성한 암호의 경우, 레인보우 테이블 (해시함수를 사용해 만들 수 있는 값들을 대량으로 저장해놓은 표)에 의해 보안 문제점이 있다.

  • salt 값 추가 또는 해시함수의 반복으로 위 문제점을 보완한다.

1) salt 값 추가: 입력한 값에 salt라는 특정 값을 붙여 변형시킨다.
crypto.randomBytes(size): 지정한 크기의 random data를 생성한다.
.toString(): 생성된 random data는 버퍼형식이기 때문에, 읽을 수 있는 String으로 변환한다.

const salt = crypto.randomBytes(16).toString('base64');

 

2) 해시함수의 반복: 해시 함수를 여러번 반복하여 본래의 값을 예측하기 어렵게 한다.

const iterations = 10000;


pdkdf2 함수를 이용한 암호화

pdkdf2Sync(password, salt, iterations, keylen, digest)
crypto에 내장된 pbkdf(password-based key derivation function)는 비밀번호 기반의 키 도출 함수이다.


암호화할 비밀번호, 솔트, 반복횟수, 키의 길이, 알고리즘을 지정하여 생성할 수 있다.
버퍼를 반환하기 때문에, .toString()을 이용하여 인코딩 방식 지정이 필요하다.

const salt = crypto.randomBytes(16).toString('base64'); // 솔트 생성
const iterations = 10000; // 반복횟수
const keylen = 64; // 생성할 키의 길이
const digest = 'sha512'; // 해시 알고리즘

const createPbdkf = (password) => {
	return crypto.pbdkf2Sync(password, salt, iterations, keylen, digest).toString('base64');
}

검증

복호화가 불가능하기 때문에, 입력받은 비밀번호를 동일한 알고리즘으로 암호화한 뒤, 결과를 비교하여 검증한다.

const verifyPassword = (password) => {
	const compare = crypto.pbdkf2Sync(password, salt, iterations, keylen, digest).toString('base64');
	if (compare === dbPassword) return true;
	return false;
}

Bcrypt

비밀번호를 암호화하는 알고리즘 중 하나로, 강력한 보안이 필요할 때 적합하다.
내장된 패키지가 아니므로, bcrypt 설치 후 불러와야 한다. (npm install bcrypt)

암호화와 검증을 위한 함수가 각각 bcrypt에 내장되어 있어, 비교적 간단하게 코드를 작성할 수 있다.

  • 암호화 .hashSync()
const bcrypt = require('bcrypt');
const salt = 10; // 일반적으로 10, 11으로 설정함

const bcryptPassword = (password) => {
	return bcrypt.hashSync(password, salt);
}
  • 검증 .compareSync()
const comparePassword = (password, dbPassword) => {
	return bcrypt.compareSync(password, dbPassword);
}


양방향 암호화

암호화와 복호화를 모두 하는 방식으로, 주로 문서를 암호화해서 보낼 때 사용한다.

대칭키 암호화 방식

암복호화에 사용하는 키가 동일한 방식이다.

  • 키 관리가 중요하다!
  • 해당 키를 아는 사람만이 문서를 복호화하여 볼 수 있다.
  • 대표적인 알고리즘: DES, 3DES, AES, ARIA

대칭키 암호화

.createCipheriv(algorithm, key, iv): 암호화 객체를 생성한다. (iv: 데이터블록을 암호화할 때, 보안성을 높이기 위해 사용)
.update(암호화할 데이터, '입력 인코딩', '출력 인코딩'): 암호화할 데이터를 처리한다.
ex) .update(word, 'utf-8', 'base64'): word라는 데이터를 utf-8 형식으로 입력받아, base64 형식으로 출력한다.

  • 전체 과정:

1) 알고리즘, 키, iv를 지정

const algorithm = 'aes-256-cbc'; // 256비트 키를 사용, 128비트의 블록.
const key = crypto.randomBytes(32); // 1바이트는 8비트이므로, 32바이트 크기의 키 생성
const iv = crypto.randomBytes(16);

 

2) 암호화 객체 생성 → 데이터 암호화 처리 → 최종결과 생성

const cipherEncrypt = (word) => {
	const cipher = crypto.createCipheriv(algorithm, key, iv); // 암호화할 객체 생성
  	let encryptedData = cipher.update(word, 'utf-8', 'base64'); // 데이터 암호화 처리
  	encryptedData += cipher.final('base64'); // 최종결과 생성
 	return encryptedData;
}

대칭키 복호화

.createDecipheriv(algorithm, key, iv): 복호화 객체를 생성한다. (암호화와 동일한 값 입력)

  • 복호화 과정은 암호화와 동일하다. (입력, 출력 인코딩 방식은 뒤바뀜)
const decipher = (encryptedData) => {
 	const decipher = crypto.createDecipheriv(algorithm, key, iv);
 	const decryptedData = decipher.update(encryptedData, 'base64', 'utf-8');
  	decryptedData += decipher.final('utf-8');
  	return decryptedData;
}

공개키 암호화 방식

암복호화에 사용하는 키가 서로 다른 방식이다.

  • 공개키(모든 사람이 접근 가능한 공개된 키)와 개인키(각 사용자만이 갖는 키, 공개X)로 이루어진다.
  • 공개키로 데이터를 암호화하고, 암호를 받아 개인키로 복호화한다.
  • 대칭키에서 키를 전송해야 하는 점을 보완할 수 있다.
  • 속도가 느리다.
728x90