1. FTPの全体像と設計思想
- 1-1. そもそもFTPって何?
- 名前:File Transfer Protocol (RFC959が基本仕様)
- トランスポート層:TCPを使用
- 目的:OSやファイルシステムが違うマシン間でファイルやディレクトリ情報をやりとりするための汎用プロトコル
重要ポイント
FTPは、「状態を持つアプリケーションプロトコル」だということです。
HTTP/1.0は基本ステートレスですが、FTPはログイン状態・カレントディレクトリ・転送モードなどをサーバ側がセッションごとに記憶しています。
2. コントロール接続とデータ接続
FTPの一番大事なポイントはここです。
2-1. ポート番号と役割
コントロール接続(接続用)
- TCPポート:通常
21/tcp(サーバ側) - 用途:ログイン、コマンド送信、レスポンス受信
- 特徴:セッション中ずっと張りっぱなしの長期コネクション
データ接続(ファイル・リスト転送用)
- TCPポート:原則的には任意(アクティブ/パッシブで使い方が変わる)
- 用途:ファイルの実データ、ディレクトリリストを流す
- 特徴:必要なときだけ張って、転送が終わったら切る短命コネクション
つまり:
「コントロール接続で"次こうしてね"と会話し、
データ接続で"実データだけ淡々と流す"」
という二段構えの設計です。
3. アクティブモードとパッシブモード
3-1. アクティブモード(active)
歴史的なオリジナル方式。
流れはざっくりこうです(クライアントをC、サーバをSとします):
- C → S:
21/tcpにコントロール接続を張る - C → S:
PORT h1, h2, h3, h4, p1, p2コマンド送信- 「これからデータ転送したいので、クライアント側のIP:PORTはこれです」と伝える
- ポート番号 =
p1 * 256 + p2
- C → S:
RETR filenameなどのデータ転送コマンド - S → C: 上で指定されたIP:PORTにサーバ側からTCP接続を張る
- そのTCPコネクション上でファイルデータを流す
問題点:
- サーバからクライアントへの「受動側への接続」が必要
- 今日のNAT環境・ファイアウォール環境だと非常にやりづらい
- クライアントがプライベートIPだったり、外から入ってくる通信が遮断されたりする
→これを解決するために生まれたのが パッシブモード
- クライアントがプライベートIPだったり、外から入ってくる通信が遮断されたりする
3-2. パッシブモード(passive)
いま主流の方式。
流れはざっくりこうです:
- C → S:
21/tcpにコントロール接続 - C → S:
PASVコマンド送信 - S → C:
227 Entering Passive Mode (h1, h2, h3, h4, p1, p2)- ここでサーバは自分のIP:PORT(データ用)を教える
- C:そのIP:PORTに対してクライアント側からTCP接続を張る
- C → S:
RETR filenameなどのコマンド(順番は実装によって少しバリュエーションあり) - データ接続上でファイル転送
特徴:
- NAT越えがしやすい:クライアントから外(サーバ)へ接続するだけ
- Webブラウザ組み込みFTPクライアントなどはほぼPASV
3-3. コントロール接続とデータ接続のタイミング
典型的には:
- コントロール接続確立
- ログイン(
USER / PASS) - 転送モードなどの設定(
TYPE,MODE,STRU) - データ接続の準備(
PASVまたはPORT) - データ転送コマンド(
RETR,STOR,LISTなど) - 転送終了 → データ接続クローズ
- 度々 4 ~ 6 を繰り返す
- セッション終了(
QUIT) → コントロール接続クローズ
4. コマンドとレスポンス(テキストプロトコル)
FTPはテキストベースのプロトコルです。
HTTPやSMTPと同じノリで、行単位でコマンドや応答をやりとりします。
4-1. コマンド形式
- ASCII文字列 + CRLF(
\r\n) - 例:
USER alice\r\nPASS secret\r\nLIST \r\nRETR file.txt\r\n
4-2. レスポンス形式:3桁コード + メッセージ
サーバからクライアントへの応答:
- 例:
220 (vsFTPd 3.0.3)-
220がステータスコード - 後ろは人間向けメッセージ(クライアントは必須ではない)
-
コードの分類(先頭桁):
-
1xx:処理開始(続行中)「今やってるから待ってて」 -
2xx:成功 -
3xx:追加情報が必要(パスワード入れて、など) -
4xx:一時的エラー(再試行で治るかも) -
5xx:恒久的エラー(コマンドが不正など)
例:ログイン時の会話
S: 220 FTP server ready
C: USER yamachan
S: 331 Password required for yamachan
C: PASS secret
S: 230 User logged in, proceed
5. 転送モード・ファイル構造・表現形式
FTPは、異なるOS間のファイル転送を強く意識して設計されています。
そのため、「ファイルの構造」「転送モード」「表現形式」という概念があります。
5-1. 表現形式(TYPE)
TYPEコマンドで設定します。代表的なもの:
-
TYPE A:ASCIIモード- テキストファイル用
- 改行コード変換などを行う(例:CRLF ⇔ LF)
-
TYPE I:Image(バイナリ)モード- いわゆる「バイナリ転送」
- データをそのまま8bitバイト列で送る
注意点:
ZIP, JPEG, EXEなど、テキストじゃないものはASCIIモードだと壊れます。
5-2. ファイル構造(STRU)
-
STRU F:File structure(普通のバイト列) *現代ではほぼこれだけ -
STRU R:Record structure(レコード単位) -
STRU P:Page structure(ページ単位)
実装的には多くのサーバ/クライアントが STRU F しかサポートしていません。
5-3. 転送モード(MODE)
-
MODE S:Stream mode(基本これ) -
MODE B:Block mode -
MODE C:Compressed mode
MODE S では、TCPストリームをそのまま流し、転送終了はTCPのFINで検出します。
6. ディレクトリ操作とパス
FTPサーバは、セッションごとにカレントディレクトリを持ちます(シェルと同じ考え方)。
主なコマンド:
-
PWD:Print Working Directory(今どこ?) -
CWD path:Change Working Directory -
CDUP:親ディレクトリへ -
LIST [path]:UNIXのls -l的な一覧 -
NLST [path]:名前だけのリスト -
MKD:ディレクトリ作成 -
RMD:ディレクトリ削除 -
DELE:ファイル削除 -
RNFR/RNTO:リネーム元 / 先
実装的なポイント
サーバ側はユーザごとに:
- ルートディレクトリ(chrootやhomeディレクトリ)をセット
- そこからの相対パスでFTPの仮想ファイルシステムを構成
パスの解釈(/ の扱い、シンボリックリンクなど)はサーバ実装次第ですが、
クライアントは基本的に「UNIXっぽいパス」として扱います。
7. 認証とアカウント
7-1. ユーザ名・パスワード
典型的な流れ:
- サーバ接続後に
220などの挨拶 USER name-
331 Password required(パスワード要求) PASS password-
230 User logged in(成功)
セキュリティ上の注意:
- ユーザ名・パスワードを平文で送る
- データも暗号化されない
- 盗聴されれば丸見え
これが、後で出てくる FTPSやSFTPが必要な理由 です。
7-2. Anonymous FTP
よくある公開サーバは:
USER anonymous-
PASS メールアドレス(形だけのことも多い)
としてログインできる仕組みを持っています。
8. FTPとNAT/ファイアウォール問題
FTPが嫌われる技術的理由のひとつがこれです。
- FTPのコントロール接続内(アプリケーションレベルのテキスト)に IPアドレスやポート番号が埋め込まれる
- 例:
PORT 192,168,1,10,19,136 - 例:
227 Entering Passive Mode (203, 0,113,5,195,80)
- 例:
- NATやファイアウォールが普通にTCPレベルだけを見ていても、
- どのポートがデータ接続として使われているか分からない
- そもそも埋め込まれているIPがプライベートアドレスだったりする
そのため、
- FTPを正しく通すには「FTP ALG (Application-Lebel Gateway)」や「FTP aware firewall」が必要
- コントロール接続の中身をパースして、
動的にフィルタルールを開けたり、埋め込まれたIPを書き換えたりする
- コントロール接続の中身をパースして、
これはHTTPやSFTPなど、簡単な1コネクション + ポート固定 + アプリ層にIPを書かないプロトコルが好まれるようになった一因です。
9. セキュリティ拡張:FTPSとSFTPの違い
「FTPが危険だから暗号化したい」となったとき、紛らわしい2つがあります。
9-1. FTPS(FTP over SSL/TLS)
- ベースはあくまでもFTP(コマンドもPORT/PASVもそのまま)
- そこにSSL/TLSを載せる
- パリエーション:
- Implicit FTPS:最初からTLSで(ポート990など)
- Explicit FTPS:普通に21で接続してから
AUTH TLSコマンドでTLSへ切り替え
特徴:
- 中身はほぼFTPなので、NATやファイアウォールの面倒くささは残る
- ただしコントロールもデータも暗号化できる
9-2. SFTP(SSH File Transfer Protocol)
- 名前がややこしいけどFTPとは完全に別プロトコル
- SSH(通常
22/tcp)の上で動作 - 単一のTCPコネクション内で複数の"チャネル"をmultiplex
- PORT/PASVもないし、テキストコマンドでもない
つまり:
FTPS = 「FTPをTLSで包んだもの」
SFTP = 「SSHベースの全く別プロトコル」
という違いです。名前だけ似ている別物。
10. プロトコルレベルの一連の例(実際の会話イメージ)
10-1. パッシブモードでファイルをダウンロードする例
C: (TCP connect to server:21)
S: 220 FTP server rady
C: USER yamachan
S: 331 Password required for yamachan
C: PASS secret
S: 230 User logged in, proceed
C: TYPE I
S: 200 Type set to I
C: PASV
S: 227 Entering Passive Mode (203,0,113,5,195,80)
# 195,80 → ポート番号 = 195 * 256 + 80 = 50000
C: (TCP connect to 203.0.113.5:50000) ← データ接続
C: RETR file.bin
S: 150 Opening BINARY mode connection for file.bin (12345 bytes)
(ここでデータ接続上で12345バイトが流れる)
(転送完了後サーバ or クライアントがデータ接続をclose)
S: 226 Transfer complete
C: QUIT
S: 221 Goodbye.
(TCP close)
おまけ:
ポート番号の計算方法(上記と別のやり方)
203,0,113,5,195,80
コンマ区切りの後ろから2つの数字をそれぞれ16進数に変換
→ それらを連結
→ 再度、10進数に変換
pythonで実行すると...
$ python
Python 3.13.7 (main, Aug 15 2025, 12:34:02) [GCC 15.2.1 20250813] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> hex(195)
'0xc3'
>>> hex(80)
'0x50'
>>> int('c350', base=16)
50000
11. まとめ:FTPの「深いところ」を掴むポイント
- コントロール接続とデータ接続の2本立て
- 21番はあくまで制御用
- 実データは別ポートで転送
- アクティブ/パッシブモード
- Active:サーバからクライアントへ接続(PORT)
- Passive:クライアントらサーバへ接続(PASV)
- NAT/Firewallの問題の主要因
- 状態を持つプロトコル
- サーバがセッションごとにログイン状態やカレントディレクトリを保持
- TYPE/STRU/MODEの設定もセッションの状態の一部
- テキストベースのコマンドと3桁レスポンスコード
-
USER,PASS,RETR,STOR,LISTなど -
1xx ~ 5xxのステータスコード
-
- セキュリティ的には古い
- プレーンなFTPは暗号化なし(ユーザ・パスワード含め)
- FTPS(TLS化したFTP)とSFTP(SSH上の別プロトコル)を区別する