1. 암호화의 기본 개념

1.1 암호화란?

  • 정의: 암호화는 데이터를 안전하게 보호하기 위해 원본 정보를 변환하는 과정이다. 암호화된 정보는 인가된 사용자만 접근할 수 있다.
  • 목적: 암호화의 목적은 데이터의 기밀성(외부 접근 제한), 무결성(정보 손상 방지), 가용성(필요 시 사용 가능성)을 보장하는 것이다.

1.2 암호화의 종류


  • 단방향 암호화:
    • 특징: 한 번 암호화되면 원본으로 복호화할 수 없으며, 주로 비밀번호 저장 및 데이터 검증에 사용된다.
    • 용도: 단방향 암호화는 패스워드 저장과 무결성 검증에 주로 사용된다.
    • 충돌 문제: 동일하지 않은 데이터가 동일한 해시 값을 가질 수 있는데, 이를 충돌(Collision)이라고 한다.
  • 양방향 암호화:
    • 특징: 암호화와 복호화가 모두 가능한 방식으로, 암호화할 때 특정 키를 사용하며, 복호화할 때도 동일한 키를 이용한다.
    • 사용 예시: 양방향 암호화는 HTTPS 통신, 파일 전송, 데이터베이스 암호화 등에 사용된다.
    • 종류:
      • 대칭키 암호화: 하나의 키로 암호화와 복호화를 모두 수행하는 방식이다. 예로 AES, DES가 있다.
      • 공개키 암호화: 공개키와 비밀키 두 가지 키를 사용해 암호화와 복호화를 수행한다. 예로 RSA, ECC가 있다.

단방향 특징

- 데이터 무결성을 검증하는 데 주로 사용되며, 패스워드 저장 등에서도 활용된다.
- 단방향이므로 원본 데이터를 복원할 수 없다.
- 동일한 데이터에 대해서는 항상 동일한 해시값이 생성되지만, 서로 다른 데이터에 대해서도 같은 해시값이 나올 수 있어 충돌이 발생할 수 있다.
- 미세한 데이터 변화에도 해시값은 완전히 달라진다.
- 주로 해시 함수(MD5, SHA-1, SHA-256 등)를 사용하여 구현된다.

양방향 특징

- 데이터의 기밀성을 유지하거나 안전한 통신을 위해 사용된다.
- 공개키와 대칭키 암호화를 조합하여 데이터 보안을 유지하면서 처리 속도를 향상시킨다.
- HTTPS와 같은 프로토콜로 클라이언트-서버 통신을 보호하여 안전한 웹 통신을 제공한다.



2. 해시 함수와 해시 알고리즘

2.1 해시 함수란?

  • 정의: 해시 함수는 입력 데이터를 고정된 크기의 출력 값(해시 값)으로 변환하는 함수이다. 동일한 데이터는 동일한 해시 값을 생성하며, 주로 데이터 무결성 검증에 사용된다.
  • 사용 예시: 데이터베이스에서 비밀번호를 해시하여 저장하면 데이터가 노출되더라도 원본 비밀번호를 보호할 수 있다.
  • 해싱전 문자 : abcde → 해싱후 문자 : ab56a4d636f4f6a198d6b247d6e2c79f)
  • 해시는 동일한 데이터에 대해 동일한 해시값을 생성하므로 충돌이 발생할 수 있다.

2.2 주요 해시 알고리즘 (MD5, SHA-1 는 사용하지 않음.)

  • SHA-256 / SHA-512:
    • 비트 길이: SHA-256은 256비트, SHA-512는 512비트이다.
    • 특징: 높은 보안성과 충돌 저항성 및 보안성이 높다. 덕분에 디지털 서명, 데이터 검증 등에 자주 사용된다.
  • MD5 (Message Digest Algorithm 5):
    • 비트 길이: MD5의 비트 길이는 128비트이다.
    • 특징: 연산 속도가 빠르지만 보안이 취약하여, 현재는 보안 목적으로는 잘 사용되지 않는다.
  • SHA-1 (Secure Hash Algorithm 1):
    • 비트 길이: SHA-1의 비트 길이는 160비트이다.
    • 특징: MD5보다 보안성이 강화되었지만, 충돌 취약성이 발견되어 현재는 더 높은 보안이 필요한 경우 다른 알고리즘을 권장한다.

"해시 함수 = 해시 알고리즘"

해시 함수와 해시 알고리즘이 동일한 개념을 나타낸다는 뜻이다.
즉, 해시 함수를 사용하여 데이터를 변환하고 고정된 크기의 해시 값을 생성하는 과정은 해시 알고리즘에 따라 수행된다.
이 두 용어는 일반적으로 서로 바꿔 사용할 수 있으며, 특정 알고리즘(예: MD5, SHA-256 등)을 사용하여 해시 값을 생성하는 방식을 의미한다.



3. 레인보우 테이블과 해시 보완 기법

3.1 레인보우 테이블 공격

  • 정의: 레인보우 테이블 공격은 미리 계산된 해시 값을 표 형태로 저장하여 해시 값을 역추적하는 공격 방식이다.
  • 한계: 동일한 해시 값이 생성되는 단방향 암호화의 특성을 악용하여, 동일한 입력값에 대한 해시 값을 역으로 찾아내 원본 비밀번호를 노출할 수 있다.

3.2 보완 기법

  • Salt:

    • 정의: 비밀번호에 임의의 문자열(Salt)을 추가한 후 해싱하여 동일한 비밀번호에 대해서도 다른 해시 값을 생성하도록 만든다.
    • 용도: 레인보우 테이블 공격에 대한 보완책으로 비밀번호를 더욱 안전하게 보호할 수 있다.
    • 예를 들어, 내가 비밀번호를 “abcde”로 만들었다면, 랜덤 문자열(예: “ab12”)을 비밀번호에 추가하여 “abcdeab12”라는 새로운 문자열을 만들고, 이 값을 해시 함수에 넣어 해싱된 결과인 “34bhh3gh4h3j2hj2”를 DB에 저장한다. 여기서 랜덤 문자열 ‘ab12’는 salt라고 불리며, 매번 달라지는 값을 사용하여 동일한 비밀번호라도 해시 값이 달라지도록 만든다.
  • 해시 함수 반복:
    - 정의: 해시 함수를 여러 번 반복하여 원본 데이터를 추적하기 어렵게 만든다.
    - 활용 방법: 해싱 과정을 반복해 연산 복잡도를 높여 해킹을 어렵게 만든다.


4. 비밀번호 해싱 및 보안: PBKDF2

4.1 PBKDF2 (Password-Based Key Derivation Function 2)

  • 정의: PBKDF2는 솔트와 반복 횟수를 사용해 비밀번호를 해싱하는 안전한 알고리즘이다.
  • 작동 원리: PBKDF2는 랜덤 솔트를 생성한 후 비밀번호와 솔트를 함께 해시 함수에 적용하고, 이 과정을 반복하여 해시 값을 생성한다.
  • 활용 방법: 비밀번호 검증 시, 새로 입력된 비밀번호를 동일한 방식으로 해시한 후 저장된 해시 값과 비교한다.
  • 구성 요소:
    • 솔트: 해시할 때 비밀번호에 추가하는 임의의 문자열이다.
    • 반복 횟수: 해시 알고리즘을 반복하는 횟수로, 연산 복잡도를 높인다.
    • 키 길이: 원하는 해시 길이를 지정할 수 있다.

5. Crypto 암호화

5.1 Crypto 모듈 사용하기

  • 정의: Node.js에 내장된 Crypto 모듈은 별도의 설치 없이 다양한 암호화 기능을 제공한다. const crypto = require('crypto');
  • 사용 방법:
    • createHash(algorithm): 해시 알고리즘을 통해 해시 값을 생성한다. (데이터의 무결성을 확인하거나 비밀번호 해싱 등에 사용)
    • pbkdf2Sync(password, salt, iterations, keylen, digest): 비밀번호 기반의 키 도출 함수를 사용해 비밀번호를 해싱하고, 보안을 강화한다. (알고리즘을 사용하여 비밀번호를 해싱. 입력값으로 비밀번호, 솔트, 반복 횟수, 원하는 해시 길이 등을 받음. 비밀번호 저장 및 검증 시 보안성을 높이기 위해 사용함.)
    • createCipheriv(algorithm, key, iv) / createDecipheriv(algorithm, key, iv): 대칭키 암호화를 통해 데이터를 암호화하는 메서드이다. (데이터를 암호화 하거나 복호화 하는데 사용)

  1. 객체 생성
    문자를 넣어서 암호화를 시켜줄 암호화 객체를 생성한다.세개의 인자를 활용해서 암호화 객체를 생성한다.
    crypto.createCipheriv(algorithm, key, iv);
  • algorithm : 사용할 알고리즘
  • key : 암호화에 사용할 비밀 키
  • iv : 같은 값이라도 랜덤하게 추출할 벡터 문자.

  1. 암호화할 데이터 처리
    객체에 update 메서드를 통해 암호화를 진행한다.
    cipher.update(word, "utf-8", "base64");
  • word : 암호화 할 원문
  • utf-8 : 입력할 문자의 인코딩
  • base64 : 출력할때 지정할 인코딩

  1. 패딩 처리
    aes-256-cbc 알고리즘은 문자를 16바이트 단위로 블럭 지어서 암호화를 진행한다.
    이때 암호화 시킬 문자가 16바이트 단위로 떨어지지 않는 경우가 생길 수 있어 불완전한 암호를 생성하거나 복호화할때 문제를 발생시킬 수 있다.
    그래서 16바이트씩 암호화를 진행하고 남는 부분은 .final()로 처리한다.
  • 최종 출력 인코딩을 지정할 수 있다.

5.2 코드 예시

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

// PBKDF2 함수를 사용한 비밀번호 해싱
const createpbkdf = (password) => {
  // createHash(알고리즘).update(암호화할 값).digest(인코딩 방식)
  return crypto.pbkdf2Sunc(password, salt, iteration, keylen, digest).toString("base64");
};

// 암호화 및 복호화 예시
const hashedPassword = createPBKDF2("password123");
console.log(`Hashed password: ${hashedPassword}`);

⬇️ 설명 ⬇️

  1. 해시를 만들기 위해 사용되는 함수로 parameter로는 사용할 알고리즘 이름이 들어간다.
  2. password 문자열을 전달한다. 이 데이터가 해시함수에 입력으로 사용된다.
  3. “base 64” : 64개의 가능한 문자로 데이터를 인코딩하는 방식. 64개의 문자중 62개는 영문 대소문자와 10진수 숫자로 구성, 나머지 두개의 문자는 인코딩과 디코딩 과정에서 추가적인 문자로 사용.
  4. “hex” : 16진수 인코딩.

16진수란? 각 숫자는 0-9까지는 숫자로, 10-15까지는 a부터 f까지의 문자로 구성.

5.3 Crypto 복호화

복호화는 암호화 과정과 거의 동일하다. 주요 차이점은 다음과 같다 :

  1. 비밀키와 초기화벡터는 동일해야 한다: 암호화와 복호화 모두 동일한 비밀키와 초기화 벡터를 사용해야 정확하게 원본 데이터를 복원할 수 있다.

  2. 암호문을 입력하고 원본 데이터를 출력: 복호화 시, 암호화된 데이터(암호문)를 입력하여 원본 데이터를 복원한다.

  3. 입출력 인코딩 순서가 반대: 암호화 시 입력은 원문, 출력은 암호문이고, 복호화 시 입력은 암호문, 출력은 원문이므로 인코딩 방식이 반대로 처리된다.

📖 Crypto 노트필기


6. Bcrypt 암호화

6.1 Bcrypt 개요

  • 정의: Bcrypt는 비밀번호 보안 강화를 위해 사용되는 단방향 해시 알고리즘으로, Blowfish 암호화 알고리즘을 기반으로 설계되었다.
  • 특징: Bcrypt는 반복 작업과 솔트를 자동으로 생성해 비밀번호를 암호화하며, 해킹에 대비해 해싱 속도를 느리게 설정할 수 있다. (강력한 보안이 필요할 때 적합)
  • Bcrypt는 단방향 해시 알고리즘이기 때문에 복호화할 수 없다. 즉, Bcrypt를 사용하여 해싱한 비밀번호는 원래의 비밀번호로 되돌릴 수 없다는 의미다.

Bcypte는 npm install bcypte 명령어를 입력해야 사용할 수 있다.

명령어를 입력하고 const bcrypt = require('bcrypt') 를 명시하여 bcrypt를 가져온다.

6.2 Bcrypt 함수 및 활용 예시

  • 사용 함수:
    • bctyptPassword(password): 비밀번호를 입력받아 솔트를 추가해 해싱한다.
    • comparePassword(password, hashedPassword): 입력된 비밀번호와 해시된 비밀번호가 일치하는지 확인한다.
  • 코드 예시:
// bcrypt
// : 비밀번호 암호화하는 알고리즘 중 하나
// : 주로 강력한 보안 필요할 때 사용
// : blowfish 암호를 기반으로 설계된 단방향 암호화 함수

const bcrypt = require("bcrypt");

const originalPw = "1234";
const saltRounds = 10; // 솔트 라운드 수를 정의

// 1. 비밀번호 해싱 함수
function bctyptPassword(password) {
  return bcrypt.hashSync(password, saltRounds); // salt 자동 생성
}

// 2. 원본 비밀번호와 해시된 비밀번호가 일치하는지 확인하는 함수
function comparePassword(password, hashedPw) {
  return bcrypt.compareSync(password, hashedPw);
}

// 사용 예제
// 원본 비밀번호를 해싱한 결과
const hashedPw = bctyptPassword(originalPw);
console.log(`Hashed password : ${hashedPw}`);

// 원본 비밀번호와 해시된 비밀번호가 일치하는지 확인
const isMatch = comparePassword(originalPw, hashedPw);
console.log(`비밀번호 일치 : ${isMatch}`);

const isMatch2 = comparePassword("1818", hashedPw);
console.log(`비밀번호 일치 : ${isMatch2}`);

참고해도 좋은 강의

https://www.youtube.com/watch?v=1BKATk8hGTU

profile
킵고잉~

0개의 댓글