[Database][MYSQL]SHA-256 과 키 스트레칭 및 솔트를 활용한 비밀번호 안전하게 저장하기

JIEUM KIM·2025년 3월 12일

Database

목록 보기
3/9
post-thumbnail

인터넷이 일상화된 현대 사회에서 보안은 가장 중요한 요소 중 하나다. 특히, 비밀번호 관리는 개인정보 보호의 핵심이다. 만약 어떤 서비스에서 비밀번호를 원본 그대로 저장한다면, 데이터베이스가 해킹당할 경우 사용자의 계정 정보가 그대로 유출될 위험이 있다. 이를 방지하기 위해 단방향 해시 함수(One-Way Hash Function)를 사용한다. 대표적인 알고리즘인 SHA-256은 입력값을 복호화할 수 없는 고유한 해시 값으로 변환하여 보관한다. 하지만, 동일한 입력값은 항상 같은 해시 값을 가지기 때문에 레인보우 테이블 공격에 취약할 수 있다. 이를 보완하기 위해 솔트(Salt)키 스트레칭(Key Stretching) 기법이 사용된다.
이번 포스팅에서는 SHA-256 해싱, 솔트 적용, 환경변수 설정을 통해 안전한 비밀번호 저장 방법을 배워보겠다.

*레인보우 테이블 공격: 동일한 비밀번호는 동일한 해시 값을 가지므로, 해커는 미리 계산된 해시 값과 비교하여 원본 비밀번호를 유추할 수 있다.


📌 암호화와 해시 함수의 개념

✏️ 암호화란?

암호화(Encryption)데이터를 보호하기 위해 특정 알고리즘을 사용해 변환하는 과정이다.

암호화된 데이터는 원본 데이터를 알아볼 수 없는 형태로 변경되어 저장된다. 암호화된 데이터를 복호화하여 원래 상태로 되돌릴수 있으며, 이는 양방향 방식이라고 한다. 예를들어 온라인 결제 시스템에서 신용카드 정보를 암호화하여 해커가 원본 데이터를 알아낼 수 없도록 하거나 기업에서 기밀 문서를 암호화를 통해 보호하는 등 다양한 보안 시스템이 존재한다.

✏️ 해시 함수란?

해시 함수(Hash Function)임의의 데이터를 고정된 길이의 고유한 값으로 변환하는 알고리즘이다.

해시함수는 암호화와 달리 단방향(one-way)로 변환되며, 복호화가 불가능하다. 또한, 동일한 입력값은 항상 동일한 해시값을 생성하게되는데, 다음과 같은 특징들이 있다.

🔧 특징

  • 고정된 길이의 해시 값 생성 (입력 데이터 크기와 무관)
  • 빠른 연산 속도
  • 입력 값이 조금만 달라도 완전히 다른 해시 값 출력 (Avalanche 효과)
  • 보안성을 위해 충돌(Collision)이 발생하지 않아야 함

예를들어 아래 이미지와 같이 해시 생성기를 통해 "안녕"이라는 문구를 출력하면 다음과 같이 다양한 해시 함수에서 값이 출력된다.

여기서 "안녕"이라는 문구에서 .하나만 추가를 해도 완전히 다른 해시 함수가 출력되는 것을 알 수 있다.

그런데 서론에서 언급한 바와 같이 동일한 입력값은 동일한 해시값만 출력하기 때문에 경험에 의한 추론이 가능하여 해커에게서 보안이 취약하다는 문제점이 있다. 예를들어, 어떤 사이트에서 회원가입시에 입력한 비밀번호의 해시값을 저장할 경우, 해커가 그 해시값을 유추하여 유저의 정보를 알아낼 수 있다는 것이다. 이를 방지하기 위해 다양한 알고리즘을 결합하여 보안을 강화하고는 하는데, 이어지는 챕터들에서 알아보자.


📌 SHA-256을 활용한 비밀번호 해싱

✏️ SHA-256 알고리즘

SHA-256(Secure Hash Algorithm 256-bit)256비트(32바이트) 길이의 해시 값을 생성하는 암호학적 해시 함수이다.

SHA-256은 보안성이 높아 비밀번호를 저장하거나 블록체인, 디지털 서명등에 사용된다. 하지만 앞선 챕터에서 설명한 바와 같이 SHA-256 알고리즘 또한 동일한 입력값에 대해 항상 같은 해시값을 생성하게 되어 레인보우 테이블 공격이나 브루트포스 공격으로부터 방어하기 위해 솔트(salt)키 스트레칭(key stretching)을 함께 사용해야한다.

✏️ 솔트(salt)

솔트(Salt)해시 함수에 추가되는 무작위 값으로, 같은 비밀번호라도 서로 다른 해시 값을 생성하도록 만드는 기법이다. 단어 뜻 그대로 원문에 임의의 문자열을 붙인다는 의미의 소금친다(salting) 는 것이다.

아래의 예제는 솔트를 무작위로 생성하여 원본 비밀번호와 조합하여 해싱하는 코드이다.

const crypto = require('crypto');

console.log("dd")

// 원본 비밀번호
const password = "admin123";

// 솔트 생성 (무작위 문자열)
const salt = crypto.randomBytes(16).toString('hex');  

// 솔트를 포함한 비밀번호 해싱
const hash = crypto.createHash("sha256").update(password + salt).digest('hex');

console.log("Salt:", salt); //> 6212f2d1c7bec7847a4383153fc530c6
console.log("Hashed Password:", hash); //> eb3787c4176b07c106718b7cfed0258ebfbf8ed6a8539ae02056d155618f45ca

솔트 생성시에 toString('hex')createHash()로 해싱한 값을 16진수 문자열로 변환하고, 비밀번호 해싱시에 digest('hex')는 Buffer 데이터를 16진수로 변환한다.

이렇게 솔트 알고리즘을 비밀번호 해싱에 사용하게 되면 같은 비밀번호를 사용하는 사용자 중 한명이 해커로부터 공격을 받게 되어도 다른 사용자는 다른 해시값을 가지기 때문에 사용자 정보를 유추하기 어려워진다.

✏️ 키 스트레칭(key stretching)

키 스트레칭(Key Stretching)해싱을 여러 번 반복하여 해커의 무작위 대입 공격(Brute Force Attack)을 어렵게 만드는 기법이다.

SHA-256 같은 해시 함수는 빠른 연산이 장점이지만, 이 때문에 해커가 초당 수억 개의 비밀번호 조합을 시도할 수 있다. 이를 방어하기 위해 의도적으로 연산 속도를 늦추는 방법이 키 스트레칭이다.

아래의 예제는 pbkdf2Sync를 사용하여 100,000번 키 스트레칭을 통해 비밀번호를 암호화한 코드이다.

const crypto = require('crypto');

// 원본 비밀번호
const password = "admin123";

// 키 스트레칭 적용 (솔트 적용 x )
const derivedKey = crypto.pbkdf2Sync(password, '', 100000, 64, 'sha256');

console.log("Stretched Hashed Password:", derivedKey.toString('hex'));
//> Stretched Hashed Password: e737966066900353dd8561f75f160efc52830abadb2e0f333c4a1e110d6af8cd723de1cd284e5d60f7a6ac44004ed37ba83f8d3772d67c517af4f66f47b7fa93

✏️ 솔트와 키 스트레칭을 적용한 예제

앞서 설명한 솔트와 키 스트레칭 기법을 조합하여 SHA-256 해싱을 하여 비밀번호를 저장하게 된다면 비로소 해커로부터 보다 보안이 강화된 개인정보 보호가 가능할 것이다.

아래 예제는 솔트와 키 스트레칭 기법을 조합하여 SHA-256 해싱을 하는 코드이다.

const crypto = require('crypto');

// 원본 비밀번호
const password = "admin123";

// 솔트 생성 (16바이트의 랜덤 값)
const salt = crypto.randomBytes(16).toString('hex');

// 키 스트레칭 적용 (PBKDF2)
const derivedKey = crypto.pbkdf2Sync(password, salt, 100000, 64, 'sha256');

console.log("Salt:", salt); //> Salt: e450bd20445a88f3b9667d0daeae630c
console.log("Stretched Hashed Password:", derivedKey.toString('hex')); //> Stretched Hashed Password: f3c69369e6ad74ea9c89655a64acd1c663ead0bfaff1cc37f9c037e41209b592b4db760aa5c15a91db029277c6fc10a307757167c874ac62c07431f43ea10292

📌 정리

이번 포스팅에서는 솔트, 키 스트레칭과 더불어 SHA-256을 활용한 비밀번호 해싱을 보다 안전하게 저장하는 방법에 대해 다루었다.

  • SHA-256 해시 함수를 사용하여 비밀번호를 암호화하지만, 동일한 입력값은 항상 같은 해시 값을 가지므로 레인보우 테이블 공격에 취약할 수 있다. 이를 방어하기 위해 솔트(Salt)와 키 스트레칭(Key Stretching) 기법을 적용해야 한다.
  • 솔트(Salt)는 비밀번호에 무작위 값을 추가하여 같은 비밀번호라도 다른 해시 값이 생성되도록 만들며, 레인보우 테이블 공격을 방어할 수 있다.
  • 키 스트레칭(Key Stretching)은 해싱 연산을 여러 번 반복하여 해커가 무작위 대입(Brute Force Attack)을 시도하는 속도를 늦춰 보안을 강화한다.
  • 솔트 + 키 스트레칭을 적용한 SHA-256 해싱을 사용하면, 비밀번호를 보다 안전하게 보호할 수 있으며, 해커가 해싱된 데이터를 유추하는 것을 어렵게 만들 수 있다.

Reference

0개의 댓글