암호화

mongBrown·2026년 4월 22일

암호화를 고를 때 기준이 있는가

암호화가 왜 필요한가

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가 달라서 매번 달라짐

검증: 원본 없이 입력값과 저장된 해시만 비교 → 일치 여부만 확인

암호화를 고를 때 기준은 두 가지다. 원본을 복원해야 하는가, 그리고 데이터 양이 얼마나 되는가. 이 두 질문에 답하면 세 가지 중 하나로 좁혀진다.

참조

profile
화이팅!

0개의 댓글