📚 네트워크 · 패킷 분석 › 02. 포트 · 프로토콜 분석 — 64편
이전 글: 63. FTP Active·Passive 모드와 보안 · 다음 글: 65. SSH
SFTP(SSH File Transfer Protocol) 는 SSH 연결 안에서 동작하는 파일 전송 프로토콜입니다. 이름이 비슷하지만 FTP에 암호화를 더한 것이 아닙니다. FTP의 명령·응답 코드·데이터 연결 분리 구조는 63. FTP Active·Passive 모드와 보안에서 다뤘고, SFTP는 이와 전혀 다른 바이너리 프로토콜입니다.
SSH 자체의 구조와 인증은 65. SSH와 SSH 구조 이해에서 다루므로, 이 글은 포트·프로토콜 관점에서 SFTP가 어떻게 보이고 어디에 흔적이 남는가에 집중합니다.
| 방식 | 포트 | 기반 | 연결 구조 | 암호화 |
|---|---|---|---|---|
| FTP | 21 (+데이터 포트) | 자체 프로토콜 | 제어·데이터 연결 분리 | 없음 |
| FTPS | 21(명시적) / 990(암묵적) | FTP + TLS | 제어·데이터 연결 분리 | TLS |
| SFTP | 22 | SSH 서브시스템 | 연결 하나에 모두 포함 | SSH |
| SCP | 22 | SSH | 연결 하나 | SSH (OpenSSH 9.0부터 scp가 기본적으로 SFTP 프로토콜 사용) |
SFTP 세션은 SSH 연결을 먼저 맺은 뒤, 그 안에서 "sftp 서브시스템을 실행해 달라"고 요청하는 방식입니다.
클라이언트 192.168.10.30:51514 → 서버 192.168.10.20:22
↓
① TCP 3-Way Handshake
② SSH 버전 문자열 교환 (평문: "SSH-2.0-OpenSSH_...")
③ 키 교환 → 이후 모두 암호화
④ 사용자 인증 (비밀번호 / 공개키) → 인증 로그 기록
⑤ 채널 열기 + "subsystem: sftp" 요청 → sshd가 서브시스템 요청 기록
↓
⑥ sshd가 sftp-server(또는 내장 internal-sftp) 실행
⑦ 같은 채널 안에서 OPEN / READ / WRITE / CLOSE 등 요청·응답
↓
파일 목록·내용·명령 모두 22번 포트의 암호화된 연결 하나 안에서 이동
서버 설정은 sshd_config의 Subsystem 줄로 정해집니다.
| 항목 | Rocky Linux | Ubuntu |
|---|---|---|
| 기본 서브시스템 경로 | /usr/libexec/openssh/sftp-server | /usr/lib/openssh/sftp-server |
| 내장 구현 | internal-sftp (공통, Chroot 환경에 주로 사용) | 동일 |
| 인증 로그 | /var/log/secure | /var/log/auth.log |
-l INFO 같은 로그 레벨을 지정해야 남습니다.ChrootDirectory와 ForceCommand internal-sftp로 특정 디렉터리 밖을 보지 못하게 하고 셸 사용을 막는 것이 일반적입니다.| 관찰 | 대화형 셸 접속 | SFTP 파일 전송 |
|---|---|---|
| 패킷 크기 | 키 입력 단위의 작은 패킷 다수 | 큰 패킷이 한 방향으로 연속 |
| 방향별 바이트 | 양방향이 비교적 작고 비슷 | 다운로드면 서버→클라이언트, 업로드면 반대가 압도적 |
| 서버 로그 | 세션 오픈, 명령 기록(설정 시) | subsystem request for sftp, 파일 open/close(설정 시) |
실습 예시 — 본인 소유 VM(서버 192.168.10.20)에서 파일 단위 로그를 켜고 흔적을 확인합니다.
# /etc/ssh/sshd_config 의 Subsystem 줄을 로그 레벨 포함으로 변경 (배포판 경로 확인 후)
# Rocky: Subsystem sftp /usr/libexec/openssh/sftp-server -l INFO
# Ubuntu: Subsystem sftp /usr/lib/openssh/sftp-server -l INFO
sudo sshd -t # 설정 문법 확인
sudo systemctl restart sshd # Ubuntu는 서비스 이름이 ssh: sudo systemctl restart ssh
# 클라이언트(192.168.10.30)에서 접속해 파일 하나 다운로드
sftp labuser@192.168.10.20
# sftp> get report.txt
# sftp> bye
# 서버 로그 확인
sudo grep -E 'sftp|subsystem' /var/log/secure # Rocky
sudo grep -E 'sftp|subsystem' /var/log/auth.log # Ubuntu
로그 형식 예시(값은 환경마다 다름, 타임스탬프·호스트 생략):
sshd[4120]: Accepted password for labuser from 192.168.10.30 port 51514 ssh2
sshd[4123]: subsystem request for sftp by user labuser
sftp-server[4124]: session opened for local user labuser from [192.168.10.30]
sftp-server[4124]: open "/home/labuser/report.txt" flags READ mode 0666
sftp-server[4124]: close "/home/labuser/report.txt" bytes read 20480 written 0
sftp-server[4124]: session closed for local user labuser from [192.168.10.30]
bytes read는 서버가 파일에서 읽은 양(=다운로드), written은 서버에 쓴 양(=업로드)입니다.
ForceCommand로 분리합니다(SSH 보안 설정).| 흔적 위치 | 확인할 수 있는 것 |
|---|---|
| 방화벽 세션 로그 | 22번 세션의 지속 시간, 방향별 바이트 (대량 전송 여부) |
| IDS/IPS | SSH 버전 문자열, 비정상 포트의 SSH 탐지 |
| sshd 인증 로그 | 로그인 성공·실패, subsystem request for sftp |
| sftp-server 로그 (설정 시) | 파일 경로, 읽기·쓰기 바이트, 삭제·이름 변경 |
관제자가 확인할 질문
오탐 주의: 백업·배포 자동화는 정기적으로 큰 SFTP 전송을 만듭니다. 주기·계정·목적지가 일정한지 기준선과 비교한 뒤 판단합니다. SSH 트래픽이 패킷에서 어떻게 보이는지는 03. Wireshark 패킷 분석 영역 140. SSH Traffic 이해에서 다룹니다.
-l INFO)을 설정해야 남습니다.