1 SSH란 무엇인가
SSH(Secure Shell)는 네트워크를 통해 원격 시스템에 안전하게 접속하기 위한 암호화 프로토콜이다. 1995년 핀란드 헬싱키대학교의 Tatu Ylönen이 개발했으며, 현재 사실상 모든 리눅스/유닉스 서버 원격 접속의 표준이다.
1.1 SSH가 해결한 문제
- SSH 이전에는 Telnet, rsh, FTP 등을 사용했는데, 이들은 모든 데이터를 평문(plain text)으로 전송했다.
- Telnet, rsh, FTP는 암호화가 없는 프로토콜이다.
| 기존 프로토콜 | 문제점 | SSH 해결책 |
|---|---|---|
| Telnet | 평문 전송 (패킷 스니핑 취약) | 모든 데이터 암호화 |
| rlogin | 약한 인증 (IP 기반) | 공개키 암호화 인증 |
| FTP | 비밀번호 평문 전송 | SFTP로 안전한 파일 전송 |
| rsh | 권한 상승 취약점 | 호스트 키 검증 |
평문 전송이 위험한 이유:
- 도청(Eavesdropping): 같은 네트워크의 누구든 패킷을 캡처하면 ID/비밀번호 탈취 가능
- 중간자 공격(MITM): 클라이언트와 서버 사이에서 통신 내용 변조 가능
- 세션 하이재킹: 인증된 세션을 탈취하여 악의적 명령 실행 가능
SSH는 암호화 + 인증 메커니즘으로 이 세 가지를 모두 해결한다.
1.2 SSH의 주요 기능
SSH는 단순한 원격 접속 도구가 아니라 다양한 기능을 제공한다.
| 기능 | 설명 |
|---|---|
| 원격 로그인 | 원격 서버의 셸에 접속하여 명령 실행 |
| 파일 전송 | SCP, SFTP를 통한 안전한 파일 복사 |
| 포트 포워딩 | 로컬/리모트/다이나믹 포트 포워딩 |
| 터널링 | 암호화된 터널을 통한 데이터 전송 |
| X11 포워딩 | 원격 서버의 GUI 애플리케이션을 로컬에서 실행 |
2 SSH 작동 원리
SSH 연결은 3단계로 이루어진다.
2.1 서버 인증 (Host Key Verification)
클라이언트가 서버에 처음 접속하면, 서버는 자신의 공개키(Host Key)를 제공한다.
The authenticity of host '192.168.1.100' can't be established.
ED25519 key fingerprint is SHA256:abc123...
Are you sure you want to continue connecting (yes/no)?
yes를 입력하면 서버의 공개키가~/.ssh/known_hosts에 저장된다known_hosts: GitHub, 회사 서버, Azure VM 등 어떤 서버든 처음 SSH 접속할 때 내 SSH 클라이언트가 알아서 만든다. 즉, 서버 공개키가 저장되는 파일이다.
- 이후 접속할 때 서버가 제시한 키와 저장된 키를 비교하여 서버 신원을 검증한다
처음 접속 시:
ssh user@서버주소
→ "Are you sure you want to continue connecting (yes/no)?" 질문
→ yes 입력
→ ~/.ssh/known_hosts 파일이 없으면 자동 생성
→ 서버의 공개키(host key)가 한 줄 추가됨
두 번째 접속부터:
→ 질문 없이 바로 접속
→ 저장된 키와 서버 키를 자동 비교
→ 일치하면 통과, 불일치하면 경고
실제 known_hosts 파일 예시:
192.168.1.100 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIxxxxxx...
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm...
(nblog) PS C:\Users\kmkim\.ssh> ls
Directory: C:\Users\kmkim\.ssh
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2026-03-11 오후 1:35 441 config (SSH 접속 설정을 저장하는 설정 파일, 간단한 별명으로 접속 가능)
-a--- 2026-03-06 오전 8:41 464 id_ed25519_github (내가 ssh-keygen 명령어로 직접 생성한 개인키)
-a--- 2026-03-06 오전 8:41 102 id_ed25519_github.pub (내가 ssh-keygen으로 생성 (공개키))
-a--- 2026-03-06 오전 8:47 1671 known_hosts (내 SSH 클라이언트가 자동 생성한 파일)
-a--- 2026-03-05 오후 4:22 933 known_hosts.old (known_hosts가 업데이트될 때 클라이언트가 이전 버전을 자동으로 백업한 파일, 삭제해도 무방)
-a--- 2025-11-25 오전 10:57 2498 test-agent_key.pem (Azure가 생성해서 다운로드해줌)
- 키가 다르면 중간자 공격 가능성을 경고한다
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
이 경고가 뜨면 서버가 재설치되었거나 중간자 공격 가능성이 있다.
2.2 암호화 채널 수립 (Key Exchange)
Diffie-Hellman 키 교환 알고리즘을 통해 클라이언트와 서버가 안전하게 세션 키를 협상한다. 이후 모든 통신은 이 세션 키로 대칭 암호화(AES-256 등)된다.
2.3 사용자 인증 (User Authentication)
서버 신원 확인 후 사용자 인증이 이루어진다. 두 가지 방식이 있다.
| 방식 | 설명 | 보안 수준 |
|---|---|---|
| 비밀번호 인증 | ID/PW 입력 | 낮음 (브루트포스에 취약) |
| 공개키 인증 | 키 쌍으로 인증 | 높음 (권장) |
- 브루트포스(Brute Force): 무차별 대입 공격
- 공개키 인증은 개인키가 노출되지 않으므로 비밀번호보다 훨씬 안전하다
# 인증방향
1단계: 서버 인증 (내가 서버를 검증)
서버가 자기 공개키 제시
→ 내 known_hosts에 저장된 키와 비교
→ "이 서버 맞네" 확인
2단계: 사용자 인증 (서버가 나를 검증)
서버가 챌린지 전송
→ 내가 개인키로 서명해서 전송
→ 서버가 authorized_keys의 내 공개키로 검증
→ "이 사람 맞네" 확인
- 서버 공개키 → 내가 서버를 믿기 위해 사용
- 내 공개키 → 서버가 나를 믿기 위해 사용
2.4 전체 연결 흐름
- TCP(Transmission Control Protocol)는 인터넷에서 데이터를 주고받는 기본 통신 규약이다. SSH뿐 아니라 웹(HTTP), 이메일 등 거의 모든 인터넷 통신이 TCP 위에서 동작한다. (전화에 비유하면 “전화 연결” 단계)
- SSH 버전 정보 교환: SSH 버전마다 지원하는 암호화 알고리즘이 다르다. 이 교환으로 둘이 공통으로 쓸 수 있는 알고리즘을 결정한다. (전화에서 “안녕하세요, 저는 삼성 갤럭시입니다” → “안녕하세요, 저는 애플 아이폰입니다” → “아, 둘 다 통화 가능하네요” 단계)
- 키 교환: Diffie-Hellman 알고리즘으로 세션 키 협상 (전화에서 “통화 암호화 위해 키 교환하자” 단계)
- 호스트 키 검증: 서버 공개키로 서버 신원 확인 (전화에서 “저는 삼성 갤럭시입니다” → “아, 삼성 갤럭시 맞네요” 단계)
- 세션 키 생성: 대칭키 암호화에 사용할 세션 키 생성 (전화에서 “이 키로 통화 암호화하자” 단계)
- 사용자 인증: 비밀번호 또는 공개키로 사용자 인증 (전화에서 “저는 홍길동입니다” → “아, 홍길동님 맞네요” 단계)
클라이언트 서버
│ │
│ 1. TCP 연결 요청 (Port 22) │
├─────────────────────────────────────>│
│ │
│ 2. SSH 버전 정보 교환 │
│<────────────────────────────────────>│
│ │
│ 3. 키 교환 (Diffie-Hellman) │
│<────────────────────────────────────>│
│ │
│ 4. 호스트 키 검증 │
│<─────────────────────────────────────┤
│ │
│ 5. 세션 키 생성 (대칭키 암호화) │
│<────────────────────────────────────>│
│ │
│ 6. 사용자 인증 (비밀번호 or Key) │
├─────────────────────────────────────>│
│ │
│ 7. 암호화된 세션 시작 │
│<════════════════════════════════════>│
3 공개키 인증 메커니즘
SSH의 핵심은 공개키 인증(Public Key Authentication)이다. 비밀번호 없이도 안전하게 인증할 수 있다.
3.1 비대칭 키 쌍
개인키(Private Key): ~/.ssh/id_ed25519 ← 절대 유출 금지, 본인만 보유
공개키(Public Key): ~/.ssh/id_ed25519.pub ← 서버에 등록, 공개 가능
- 공개키로 암호화한 데이터는 대응하는 개인키로만 복호화 (암호화, encryption의 반대) 가능
- 개인키로 서명한 데이터는 공개키로만 검증 가능
- 공개키를 공개해도 개인키를 역산할 수 없다
3.2 인증 흐름
클라이언트 서버
| |
|--- 1. 접속 요청 (사용자명) --------->|
| | 서버: authorized_keys에서 공개키 확인
|<-- 2. 랜덤 챌린지(Challenge) -------|
| |
| 클라이언트: 개인키로 챌린지에 서명 |
|--- 3. 서명값 전송 ----------------->|
| | 서버: 등록된 공개키로 서명 검증
|<-- 4. 인증 성공 --------------------|
핵심: 개인키 자체는 네트워크로 전송되지 않는다. 서버는 공개키만 알고 있으며, 비밀번호 인증과 달리 인증 정보가 노출될 위험이 없다.
4 암호화 알고리즘
4.1 SSH 키 알고리즘
| 알고리즘 | 키 크기 | 보안 수준 | 속도 | 권장 |
|---|---|---|---|---|
| Ed25519 | 256 bit | 매우 높음 | 매우 빠름 | 강력 권장 |
| ECDSA | 256-521 bit | 높음 | 빠름 | 권장 |
| RSA | 2048-4096 bit | 중간 | 느림 | 레거시 호환용 |
| DSA | 1024 bit | 낮음 | 중간 | 사용 금지 (deprecated) |
최신 환경에서는 Ed25519를 사용한다. 구형 시스템과의 호환이 필요하면 RSA 4096bit를 사용한다.
4.2 세션 암호화 (대칭키)
키 교환 후 실제 데이터 전송에 사용되는 대칭키 알고리즘:
- AES-256-GCM
- AES-128-GCM
- ChaCha20-Poly1305
4.3 해시 함수 (무결성 검증)
전송 데이터가 변조되지 않았는지 확인:
- SHA-256, SHA-512
- HMAC-SHA2-256
5 SSH 설치
대부분의 운영체제에 SSH 클라이언트가 기본 내장되어 있다.
Windows 10/11: 기본 내장. 없다면 설정 → 앱 → 선택적 기능 → OpenSSH 클라이언트 추가.
macOS: 기본 내장.
Linux (Ubuntu/Debian):
6 요약
| 항목 | 내용 |
|---|---|
| SSH란 | 암호화된 원격 접속 프로토콜 (Port 22) |
| 핵심 원리 | 비대칭 암호화 (공개키 + 개인키) |
| 연결 3단계 | 서버 인증 → 키 교환 → 사용자 인증 |
| 인증 방식 | 비밀번호 (비권장) vs 공개키 (권장) |
| 권장 알고리즘 | Ed25519 |
| 주요 기능 | 원격 로그인, 파일 전송, 포트 포워딩, 터널링 |