HTTP로 로그인 요청을 보내면 네트워크 패킷에 이런 데이터가 담긴다.
POST /login HTTP/1.1
Content-Type: application/json
{"id": "admin", "password": "1234"}
같은 네트워크에 있는 누구든 이 패킷을 캡처하면 그대로 읽을 수 있다. 이것이 스니핑이다. 암호화가 없으면 전송 중인 데이터는 누구에게나 공개된 것과 다름없다.
sequenceDiagram
participant C as 클라이언트
participant A as 공격자
participant S as 서버
C->>S: id=admin, pw=1234 (평문 그대로)
Note over A: 패킷 캡처 → 내용 그대로 노출
암호화는 이 문제를 해결하기 위해 등장했다. 데이터를 읽을 수 없는 형태로 변환해서 전송하면, 패킷을 캡처해도 내용을 알 수 없다.
암호화와 복호화에 같은 키를 쓴다. 키를 알고 있는 사람만 데이터를 복원할 수 있다. 처리 속도가 빠르기 때문에 대용량 데이터 암호화에 적합하다. 대표 알고리즘은 AES다.
sequenceDiagram
participant S as 송신자
participant R as 수신자
S->>S: 비밀키로 암호화
S->>R: 암호문 전송
R->>R: 같은 비밀키로 복호화
Note over S,R: 같은 키를 미리 공유해야 함
단점은 키 전달이 어렵다는 것이다. 암호화된 데이터를 보내면서 복호화 키도 함께 보내야 하는데, 그 키가 탈취되면 모든 데이터가 노출된다.
공유키: a8f3c9d2b1e4f7a0... (송수신자 모두 동일한 키 보유)
"1234-5678-9012-3456" → 암호화 → 8f4a2c9d1b3e5f7a...
8f4a2c9d1b3e5f7a... → 복호화 → "1234-5678-9012-3456"
다른 키로 복호화 시: 오류 또는 깨진 값
대칭키는 빠르지만, 이 키를 상대방에게 어떻게 안전하게 전달할 것인가라는 문제가 남는다. 그것을 해결하는 게 비대칭키다.
공개키와 개인키 두 개를 쓴다. 공개키로 암호화하면 개인키로만 복호화할 수 있다. 공개키는 누구에게나 공개해도 되고, 개인키는 수신자만 가지고 있으면 된다. 키 전달 문제가 없다.
sequenceDiagram
participant S as 송신자
participant R as 수신자
R->>S: 공개키 배포 (누구나 받아도 됨)
S->>S: 공개키로 암호화
S->>R: 암호문 전송
R->>R: 개인키로 복호화
Note over R: 개인키는 수신자만 보유
대신 처리 속도가 느리다. 그래서 대용량 데이터 암호화에는 쓰지 않는다. 대표 알고리즘은 RSA로, 소인수분해가 어렵다는 수학적 성질을 기반으로 한다.
공개키: MIIBIjANBgkqhkiG... (누구에게나 공개)
개인키: MIIEvQIBADANBgkq... (수신자만 보유)
"전송할 데이터" → 공개키로 암호화 → 9a3f1c8e2b4d7f0a...
9a3f1c8e2b4d7f0a... → 개인키로 복호화 → "전송할 데이터"
공개키로는 복호화 불가능
두 방식 모두 암호화/복호화가 가능하다. 그런데 비밀번호처럼 애초에 복호화할 필요가 없는 데이터는 어떻게 저장해야 할까.
복호화가 불가능하다. 같은 입력을 넣으면 항상 같은 해시값이 나오는데, 그 해시값으로 원래 값을 복원하는 방법이 없다. 비밀번호를 저장할 때 쓰는 이유가 여기 있다. 서버가 비밀번호를 몰라도 로그인 시 입력값을 해시해서 저장된 값과 비교하면 된다.
SHA-256은 대표적인 단방향 해시 알고리즘이지만, 비밀번호 저장에 그대로 쓰기엔 문제가 있다. 같은 입력이 항상 같은 해시값을 내기 때문에, 미리 계산해둔 해시표(레인보우 테이블)로 공격당할 수 있다.
Bcrypt는 이 문제를 Salt로 해결했다. Salt는 해시할 때 랜덤 값을 섞는 것으로, 같은 비밀번호를 입력해도 매번 다른 해시값이 나온다. 미리 계산해둔 레인보우 테이블로는 대응이 불가능해진다.
[SHA-256 — 같은 입력이면 항상 같은 출력]
"password123" → ef92b778bafe771...
"password123" → ef92b778bafe771... ← 레인보우 테이블로 역추적 가능
[Bcrypt — 같은 입력이어도 매번 다른 출력]
"password123" → $2a$10$X9aB3cD4eF5g...
"password123" → $2a$10$R7mN2pQ8sT1u... ← Salt가 달라서 매번 달라짐
검증: 원본 없이 입력값과 저장된 해시만 비교 → 일치 여부만 확인
암호화를 고를 때 기준은 두 가지다. 원본을 복원해야 하는가, 그리고 데이터 양이 얼마나 되는가. 이 두 질문에 답하면 세 가지 중 하나로 좁혀진다.