개념 설명
사용자의 비밀번호를 데이터베이스에 그대로 저장해서는 안 됩니다. 만약 데이터베이스가 유출되면 모든 사용자의 계정이 탈취되기 때문입니다. 이를 방지하기 위해 비밀번호는 해시된 형태로 저장해야 합니다.
해싱??
임의의 길이 데이터를 고정된 길이의 데이터로 매핑하는 단방향 함수입니다.
해시 함수는 다음과 같은 특징을 가집니다.
1. 단방향성: 원본 데이터(비밀번호)로 해시 값을 계산하기는 쉽지만, 해시 값으로 원본 데이터를 알아내는 것은 거의 불가능해야 합니다. md5()나 sha1() 같은 오래된 해시 함수는 이 원칙이 깨졌으므로 절대 비밀번호 저장에 사용하면 안 됩니다.
2. 솔팅 : 동일한 비밀번호라도 해싱할 때마다 결과가 달라져야 합니다. 이는 '레인보우 테이블' 공격(미리 계산된 해시 값 목록을 이용한 공격)을 무력화합니다. 해싱에 사용되는 랜덤 데이터를 솔트(Salt)라고 합니다.
3. 느린 처리 속도 : 해시 함수는 의도적으로 느리게 설계되어야 합니다. 속도가 빠르면 공격자가 무차별 대입 공격을 통해 짧은 시간 안에 수많은 비밀번호를 테스트해볼 수 있기 때문입니다.
1. password_hash(): 비밀번호 해싱하기
$password: 해싱할 사용자의 원본 비밀번호.
$algo: 사용할 해싱 알고리즘입니다.
PASSWORD_DEFAULT: PHP가 설치된 버전에 따라 알고리즘을 자동으로 선택합니다. 나중에 PHP가 업데이트되어 더 좋은 알고리즘이 나오면 자동으로 업그레이드되므로 유지보수에 매우 유리합니다.
PASSWORD_BCRYPT: Bcrypt 알고리즘을 강제로 사용.
PASSWORD_ARGON2I, PASSWORD_ARGON2ID: Argon2 알고리즘을 강제로 사용 (PHP 7.2+).
$options: 알고리즘에 대한 옵션. 주로 cost 값을 지정합니다.
cost: 해싱의 복잡도를 결정하는 값입니다. 숫자가 높을수록 해시 계산에 더 많은 시간이 걸려 보안성이 높아집니다. 기본값은 10이며, 서버 성능에 따라 10~12 사이의 값을 사용하는 것이 일반적입니다.

2. password_verify(): 해시 검증하기
로그인 시 입력한 비밀번호와 DB에 저장된 해시 값이 일치하는지 비교합니다.
주의: 절대 if (password_hash($input, ...) == $dbHash) 와 같이 비교하면 안 됩니다. password_hash()는 매번 다른 해시를 생성하므로 항상 false가 나옵니다. 또한, == 연산자는 타이밍 공격(Timing Attack)에 취약할 수 있습니다. 반드시 password_verify()를 사용해야 합니다.
문법:
password_verify(string $password, string $hash): bool
$password: 사용자가 로그인 시 입력한 원본 비밀번호.
$hash: 데이터베이스에 저장되어 있던 해시 값.

3.password_needs_rehash(): 리해싱 필요 여부 확인
시간이 지나면 기존의 cost 값은 너무 낮아져 보안에 취약해질 수 있습니다. 또는 PHP가 업데이트되어 PASSWORD_DEFAULT가 더 강력한 새 알고리즘(예: Bcrypt -> Argon2)을 가리킬 수도 있습니다.
이때 사용자가 로그인할 때마다 해시를 검증하고, 필요하다면 더 강력한 설정으로 다시 해싱하여 DB를 업데이트하는 것이 좋습니다. password_needs_rehash() 함수가 이 작업을 도와줍니다.
password_needs_rehash(string $hash, string|int|null $algo, array $options = []): bool

'PHP' 카테고리의 다른 글
| [PHP] Traits (트레이트) - 코드를 재사용하는 방법 (0) | 2025.11.17 |
|---|---|
| [PHP] foreach 없이 두 배열의 '차이'와 '교집합' 찾기 array_diff(), array_intersect() (0) | 2025.11.12 |
| [PHP] array_merge와 + 연산자로 두 배열 합치기의 차이점 (0) | 2025.11.09 |
| [PHP] usort()로 '사용자 목록'을 '나이 순'으로 정렬 (0) | 2025.11.06 |
| [PHP] NumberFormatter로 '2000000'을 '이백만'으로 변환하기 (0) | 2025.11.05 |