第24章 FTPサーバーのセキュリティ設定

LPIC-2 212.2 相当

FTPは古くからあるファイル転送プロトコルで、現在では機密性の高い用途にはSFTP(SSH経由、前々章で扱いました)が好まれる傾向にありますが、不特定多数への公開ダウンロードサイトなど、匿名アクセスを前提とした用途では今でも使われています。ここではFTPプロトコルの内部構造から、代表的なFTPサーバーソフトウェア(vsftpd・Pure-FTPd・ProFTPd)の安全な設定、ファイアウォールとの兼ね合いまでを扱います。

FTPプロトコルの構造

FTPは、他の多くのプロトコルにはない特徴的な仕組みを持っています。コマンドのやり取りを行う「制御コネクション」と、実際にファイルの中身をやり取りする「データコネクション」を、別々のTCPコネクションとして確立します。

コネクション役割ポート
制御コネクションログイン・ディレクトリ移動・ファイル一覧要求などのコマンドをやり取りする21番(サーバー側)
データコネクション実際のファイルの中身や、ディレクトリ一覧の結果を転送するアクティブモードでは20番(サーバー側)、パッシブモードでは動的な高位ポート

制御コネクションは接続している間ずっと維持されますが、データコネクションはファイル転送のたびに新しく確立され、転送が終わると切断されます。この「1つのプロトコルで2本のコネクションを使う」という構造が、後述するファイアウォール・NAT環境での特有のトラブルの根本原因になります。

アクティブモードとパッシブモードの違い

アクティブモード(サーバーの20番からクライアントへ接続を張る)
クライアント                                     サーバー
  |--- 制御コネクション確立(クライアント発信、宛先21番) --->|
  |--- PORTコマンド(クライアント側の待受ポートを通知) ------>|
  |<-- データコネクション(サーバーの20番から新規発信) -------|
  |=== ファイル転送 ============================================|

パッシブモード(クライアントがサーバーの高位ポートへ接続する)
クライアント                                     サーバー
  |--- 制御コネクション確立(クライアント発信、宛先21番) --->|
  |--- PASVコマンド ------------------------------------------->|
  |<-- サーバーの待受ポート番号を通知(例:40023番) -----------|
  |--- データコネクション(クライアント発信、宛先40023番) --->|
  |=== ファイル転送 ============================================|
モードデータコネクションの向きファイアウォール・NAT越しでの相性
アクティブサーバーの20番ポートから、クライアントが指定したポートへ新規発信するクライアント側のNAT/ファイアウォールがサーバーからの新規着信を拒否するため、失敗しやすい
パッシブクライアントが、サーバーの通知した高位ポートへ新規発信するクライアント側は発信のみで済むため制約を受けにくいが、サーバー側で高位ポート範囲の開放が必要

アクティブモードでは、サーバー側がクライアントの指定したポートへ新規に接続しに行くため、クライアントが家庭用ルーターやNATの内側にいる場合、外部からの新規着信としてブロックされて失敗することがよくあります。パッシブモードでは逆にクライアント側が接続を開始するため、この問題を回避できます。現代のインターネット利用者のほとんどがNATの内側(家庭用ルーター、モバイル回線のキャリアNATなど)にいるため、クライアント側に一切の着信設定を求めないパッシブモードが事実上の標準になっています。その代わり、パッシブモードを使うにはサーバー側でデータ転送用の高位ポート範囲を明示的に開放しておく必要があります。

FTPが平文であることの問題とFTPS/SFTPとの違い

通常のFTPは、ユーザー名・パスワードを含めすべての通信が平文でやり取りされるため、経路上での盗聴によって認証情報やファイルの中身がそのまま読み取られてしまうリスクがあります。この問題に対応する方法として、FTPSとSFTPという似た名前の2つの規格がありますが、両者は全く別物です。

規格正体
FTPS(FTP over TLS/SSL)既存のFTPプロトコルに、TLSによる暗号化を追加したもの。制御・データの両コネクションをTLSで保護する。21番ポートを使い続ける「Explicit」方式と、専用ポート(990番)を最初から使う「Implicit」方式がある
SFTP(SSH File Transfer Protocol)SSHプロトコルの上で動くサブシステムの1つで、FTPとはプロトコル的に無関係。1本のSSH接続(22番ポート)の中でファイル操作を行うため、制御・データコネクションの分離という問題自体が発生しない
試験対策: 名前が似ているためFTPSとSFTPを混同しがちですが、FTPSは「FTP+TLS」であり旧来のFTPの構造(制御/データコネクションの分離、アクティブ/パッシブの区別)をそのまま引き継ぎます。一方SFTPはSSHのサブシステムであり、FTPの仕組みとは根本的に別物です。SSHの章で扱ったsshd・鍵認証の知識がそのまま活きるのはSFTPの方です。

vsftpdの設定

vsftpd("very secure FTP daemon")は、名前の通りセキュリティを重視して設計されたFTPサーバーで、多くのディストリビューションで既定のFTPサーバーとして採用されています。設定ファイルは/etc/vsftpd.conf(ディストリビューションにより/etc/vsftpd/vsftpd.conf)です。実務レベルの完全な設定例を、コメント付きで示します。

/etc/vsftpd.conf の完全な例
anonymous_enable=NO              # 匿名(ログイン不要)アクセスを許可するか
local_enable=YES                 # ローカルのUnixユーザーアカウントでのログインを許可するか
write_enable=YES                 # 書き込み(アップロード・削除等)を全体として許可するか
local_umask=022                  # ローカルユーザーがアップロードしたファイルのumask

anon_upload_enable=NO            # 匿名ユーザーのアップロードを許可するか
anon_mkdir_write_enable=NO       # 匿名ユーザーによるディレクトリ作成を許可するか
anon_other_write_enable=NO       # 匿名ユーザーによる削除・リネーム等その他の書き込み操作を許可するか

chroot_local_user=YES            # ログインユーザーを自分のホームディレクトリ配下に閉じ込める
allow_writeable_chroot=YES       # chrootルートが書き込み可能でも起動を許可する(下記の500 OOPS参照)
chroot_list_enable=YES           # chroot_local_userの例外リストを使うか
chroot_list_file=/etc/vsftpd.chroot_list  # 例外リストのパス

userlist_enable=YES              # userlist_fileによるログイン可否リストを使うか
userlist_deny=YES                # YESならリスト記載ユーザーを拒否(ブラックリスト)、NOならリスト記載ユーザーのみ許可(ホワイトリスト)
userlist_file=/etc/vsftpd.user_list  # リストのパス(root等を記載し、rootでのFTPログインを禁止するのが定石)

pasv_enable=YES                  # パッシブモードを許可するか
pasv_min_port=40000              # パッシブデータ転送に使うポート範囲の下限
pasv_max_port=40100              # パッシブデータ転送に使うポート範囲の上限
pasv_address=203.0.113.10        # NAT環境で、クライアントに通知する外部(グローバル)IPアドレス

ssl_enable=YES                   # FTPS(TLS暗号化)を有効にするか
rsa_cert_file=/etc/ssl/certs/vsftpd.crt      # サーバー証明書
rsa_private_key_file=/etc/ssl/private/vsftpd.key  # 秘密鍵
force_local_data_ssl=YES         # データ転送そのものにもTLSを必須にする

xferlog_enable=YES               # 転送ログを記録するか
xferlog_file=/var/log/vsftpd.log # ログの出力先
log_ftp_protocol=YES             # FTPプロトコルのコマンドレベルのやり取りまで詳細にログするか

listen=YES                       # IPv4でスタンドアロン動作(vsftpd自身がデーモンとして待ち受ける)
listen_ipv6=NO                   # IPv6でのスタンドアロン動作(listenとlisten_ipv6は同時にYESにできない)
よくある間違い(500 OOPSエラー): chroot_local_user=YESにした状態で、ホームディレクトリ自体がそのユーザーから書き込み可能になっていると、vsftpdは既知の脆弱性クラス(書き込み可能なchrootルートを起点にした脱出攻撃)を警戒し、セッションの確立を拒否します。この際に表示されるのが500 OOPS: vsftpd: refusing to run with writable root inside chroot()というエラーです。allow_writeable_chroot=YESを設定すればこの警告を無視して起動できますが、根本的な対策としては、ホームディレクトリ自体は書き込み不可(読み取り専用)にしておき、その配下に書き込み可能な専用サブディレクトリ(例:~/uploads)を別途用意する構成の方が安全です。

chroot_list_enableとchroot_list_fileを使うと、全ユーザー一律ではなく例外を設けられます。chroot_local_user=YESの場合、リストに記載されたユーザーは例外的にchrootされなくなります(逆にchroot_local_user=NOの場合は、リストに記載されたユーザーだけがchrootされます)。userlist_enable/userlist_deny/userlist_fileの組み合わせでは、パスワード入力を求める前の段階でユーザー名だけを見てログイン可否を判定でき、rootのような特権アカウントをFTPログインの対象から明示的に除外するのに使われます。

listen・listen_ipv6を使うスタンドアロン方式に対し、古典的な運用としてxinetd経由で必要な時だけvsftpdを起動する方式もあります。この場合listen=NOにした上で、xinetd側に設定を持たせます。

/etc/xinetd.d/vsftpd の例
service ftp
{
    disable      = no
    socket_type  = stream
    protocol     = tcp
    wait         = no
    user         = root
    server       = /usr/sbin/vsftpd
}

匿名FTPの構成

不特定多数へファイルを公開するダウンロードサイトなどでは、匿名アクセスを有効にすることがあります。匿名ユーザーがアクセスするルートディレクトリ(慣例的に/srv/ftp)は、所有者をroot(またはFTP専用の管理ユーザー)にし、匿名ユーザー自身には書き込み権限を持たせない(755程度のパーミッション)のが基本です。

$ sudo chown root:root /srv/ftp   # 正常時は無出力
$ sudo chmod 755 /srv/ftp         # 正常時は無出力
$ ls -ld /srv/ftp
drwxr-xr-x 3 root root 4096 Aug 21 09:20 /srv/ftp

この行のこの値に注目: chown・chmodはどちらも成功時は無出力なので、実際に反映されたかはls -ldで確認します。drwxr-xr-xのうち、所有者(root)以外の書き込みビット(w)が立っていないことが、匿名ユーザーによる書き換えを防ぐポイントです。

注意(warezの踏み台化): 匿名アップロードまで無制限に許可してしまうと、そのFTPサーバーが違法コンテンツ(いわゆる「warez」)の一時的な配布拠点として、第三者に無断で悪用される危険があります。攻撃者がアップロードしたファイルへの直リンクを不特定多数に流通させ、あなたのサーバーの帯域とディスクを消費させるという被害が典型的です。匿名アップロードを許可する場合は、必ず次の対策を組み合わせてください。
  1. アップロード先ディレクトリを、公開ダウンロード領域とは別の専用ディレクトリに分離する
  2. アップロード先ディレクトリを「書き込みはできるが一覧取得・ダウンロードはできない」権限にする(アップロードされたファイルがその場ですぐ外部から取得できないようにする)
  3. 定期的にアップロード内容を確認し、不審なファイルがあれば速やかに削除する
匿名アクセスを許可しつつ、アップロード先を安全に分離する設定例
anonymous_enable=YES
anon_upload_enable=YES
anon_mkdir_write_enable=NO
anon_umask=077
anon_root=/srv/ftp
アップロード専用ディレクトリの権限設定(書き込みはできるが中身は見えない)
$ sudo mkdir /srv/ftp/incoming          # 正常時は無出力
$ sudo chown ftp:ftp /srv/ftp/incoming  # 正常時は無出力
$ sudo chmod 733 /srv/ftp/incoming      # 正常時は無出力
# 733 = 所有者は読み書き実行可、グループ・その他は書き込み・実行のみ(読み取り不可)
# ディレクトリの実行権限だけではファイル名を知らない限り中身を読めないため、
# 一覧取得や推測によるダウンロードのハードルを上げられる
$ ls -ld /srv/ftp/incoming
drwx-wx-wx 2 ftp ftp 4096 Aug 21 09:22 /srv/ftp/incoming

この行のこの値に注目: drwx-wx-wxのグループ・その他の欄にr(読み取り)が含まれていないことが重要です。これにより、匿名ユーザーはファイルを書き込めても、他人がアップロードしたファイル名をlsで一覧取得できません(実行ビットだけがあるため、正確なファイル名を知っていれば個別にアクセスすること自体は可能です)。

anon_umask=077を設定しておくと、アップロードされたファイル自体のパーミッションも本人以外読み取り不可になり、ディレクトリ権限と合わせて二重に保護できます。

Pure-FTPdの主要オプション

Pure-FTPdは、vsftpdと並んでよく使われるもう1つのFTPサーバーです。vsftpdが設定ファイルベースであるのに対し、Pure-FTPdは起動時のコマンドラインオプションで細かく制御する点が特徴です。

オプション意味
-l認証方式(authバックエンド)を指定する。例:-l unix(Unixアカウント)、-l puredb:/etc/pure-ftpd/pureftpd.pdb(専用DB)、-l pam(PAM連携)
-Aすべてのユーザーをchroot化する(vsftpdのchroot_local_user=YESに相当)
-E匿名(anonymous)ユーザーのログインを禁止する
-jホームディレクトリが存在しないユーザーに対して自動作成する
-Pパッシブモード時にクライアントへ通知する外部IPアドレス(vsftpdのpasv_addressに相当。NAT環境で必要)
-pパッシブモードのポート範囲を指定する(例:-p 40000:40100)
-YTLSの強制レベルを指定する(0=無効、1=TLSを許可するが必須にはしない、2=TLS必須)
$ sudo pure-ftpd -A -E -j -P 203.0.113.10 -p 40000:40100 -Y 2
Aug 21 09:25:03 : pure-ftpd: (SSL support: on)
Aug 21 09:25:03 : pure-ftpd: Trusted-IP support: no
Aug 21 09:25:03 : pure-ftpd: Uploads/Downloads ratio: none / none

この行のこの値に注目: フォアグラウンドで起動すると(-Bでデーモン化しない限り)、起動時のログがそのまま端末に表示されます。SSL support: onで暗号化が有効になっていること、指定した-Y 2(TLS必須)が反映されていることをこの起動時ログで確認できます。実運用ではsystemdユニット経由で起動し、通常はデーモン化(バックグラウンド常駐)してこのログはsyslogへ送られます。

Debian系では、これらのオプションを起動コマンドに直接書く代わりに、/etc/pure-ftpd/conf/以下に、オプションに対応した名前のファイルを作り、その中に値だけを書く方式が使われます。起動スクリプト(pure-ftpd-wrapper)がこのディレクトリを読み取り、実際のコマンドライン引数を組み立てます。

/etc/pure-ftpd/conf/ 以下のファイル例
$ cat /etc/pure-ftpd/conf/ChrootEveryone
yes
$ cat /etc/pure-ftpd/conf/PassivePortRange
40000 40100
$ cat /etc/pure-ftpd/conf/TLS
2

ProFTPdの位置づけ

ProFTPdは、vsftpd・Pure-FTPdとは異なり、Apacheのhttpd.confに似た「ブロック構造」の設定構文を採用しているのが最大の特徴です。Apacheの運用経験があれば、直感的に設定を読み書きしやすい点が支持されています。

/etc/proftpd/proftpd.conf の例(Apache風の構文)
<VirtualHost ftp.example.com>
    ServerName "Example FTP Server"
    User ftp
    Group ftp

    <Anonymous /srv/ftp>
        User ftp
        Group ftp
        UserAlias anonymous ftp
        RequireValidShell off
        <Limit WRITE>
            DenyAll
        </Limit>
    </Anonymous>
</VirtualHost>

ProFTPdはモジュール構成も豊富で、データベースと連携した仮想ユーザー管理(mod_sql)や、複数のFTPサイトを1つのプロセスでホストするバーチャルホスト機能など、大規模・複雑な要件に対応しやすい設計になっています。一方、vsftpdやPure-FTPdは、よりシンプルで攻撃対象領域を絞った構成を志向しており、単純なファイル配布・アップロード用途であればこちらが選ばれることが多くなっています。

ファイアウォールとの兼ね合い

パッシブモードを使う場合、サーバー側で開放したポート範囲(pasv_min_port〜pasv_max_portなど)を、ファイアウォール側でも確実に許可しておく必要があります。

nftablesでの許可例
nft add rule inet filter input tcp dport 21 accept
nft add rule inet filter input tcp dport 40000-40100 accept

ただし、Linuxのnetfilter(接続追跡機構)にはnf_conntrack_ftpという専用のヘルパーモジュールが用意されています。このモジュールをロードしておくと、制御コネクション上でやり取りされるPASV応答の内容をカーネルが実時間で解析し、そこで合意されたデータポートへの接続を「関連(RELATED)」として動的に追跡・許可できます。これにより、ファイアウォール側で広いポート範囲を静的に開放しなくても、ESTABLISHED,RELATEDを許可する一般的なルールだけでFTPのパッシブ接続が通るようになります。

$ sudo modprobe nf_conntrack_ftp   # 正常時は無出力
$ lsmod | grep nf_conntrack_ftp
nf_conntrack_ftp       16384  0
nf_conntrack          172032  2 nf_conntrack_ftp,nf_nat

この行のこの値に注目: lsmodの出力にnf_conntrack_ftpの行が表示されれば、モジュールが正しくロードされています。3列目(Used by相当)の0は、まだこのモジュールに依存している他のモジュール・接続がないことを示します。恒久的にロードしたい場合は、/etc/modules-load.d/以下にモジュール名を1行書いたファイルを追加します。

注意: nf_conntrack_ftpは、制御コネクションの中身(PASV応答の平文)を解析することで動作します。FTPS(TLSで制御コネクションを暗号化したもの)を使っている場合、ファイアウォールはその中身を読み取れなくなるため、このヘルパーは機能しなくなります。FTPSを使う場合は、conntrackヘルパーに頼らず、パッシブポート範囲を静的にファイアウォールで開放しておく必要があります。

ログの確認とトラブルシューティング

vsftpdはログを/var/log/vsftpd.log(xferlog_std_formatを有効にすると標準のxferlog形式)に記録します。

$ tail -f /var/log/vsftpd.log
Thu Aug 21 09:30:12 2026 [pid 5522] [alice] OK LOGIN: Client "192.168.1.50"
Thu Aug 21 09:30:45 2026 [pid 5522] [alice] OK DOWNLOAD: Client "192.168.1.50", "/home/alice/report.pdf", 245760 bytes, 512.34Kbyte/sec
Thu Aug 21 09:31:02 2026 [pid 5540] [?] FAIL LOGIN: Client "198.51.100.23"
$ grep "FAIL" /var/log/vsftpd.log      # ログイン失敗を抽出
Thu Aug 21 09:31:02 2026 [pid 5540] [?] FAIL LOGIN: Client "198.51.100.23"
Thu Aug 21 09:31:05 2026 [pid 5541] [?] FAIL LOGIN: Client "198.51.100.23"
Thu Aug 21 09:31:09 2026 [pid 5542] [?] FAIL LOGIN: Client "198.51.100.23"

この行のこの値に注目: FAIL LOGINの行にある[?]は、ログイン自体が失敗したためユーザー名を特定できなかったことを表します。同一の送信元IP(この例では198.51.100.23)から短時間に何度もFAIL LOGINが続く場合は、ブルートフォース攻撃の兆候であり、fail2banのようなツールでの自動遮断や、ファイアウォールでの当該IPの遮断を検討します。

接続できないときの切り分け手順は、次の順序で確認すると効率的です。

  1. サービス自体が起動しているかを確認する(systemctl status vsftpd)
  2. 制御コネクション(21番ポート)に到達できるかを確認する(telnet server 21やnc -zv server 21)。ここで失敗する場合はファイアウォールやlisten設定自体を疑う
  3. ログインまでは成功するが、ファイル一覧取得(ls)やダウンロードで止まる場合は、データコネクションの確立に失敗している可能性が高い。クライアントをアクティブモードに切り替えて試し、アクティブでは成功するがパッシブでは失敗する(あるいはその逆)場合、原因はモードに応じたポート開放の問題に絞り込める
  4. パッシブモードで失敗する場合は、サーバーのpasv_min_port〜pasv_max_portがファイアウォールで開放されているか、NAT環境であればpasv_addressが正しい外部IPアドレスに設定されているか(サーバーの内部IPをそのまま通知していないか)を確認する

特にpasv_addressの設定漏れは、サーバーがNATの内側にある構成(クラウド環境など)で頻発するつまずきポイントです。クライアントに通知されるIPアドレスが内部プライベートIPのままだと、クライアントはそのアドレスへ到達できず、一覧取得や転送だけが原因不明のまま止まって見えます。

確認クイズ

Q1. FTPが、コマンドのやり取りとファイルの中身の転送を、別々のTCPコネクションとして確立する仕組みで、コマンドのやり取りを行うコネクションは何と呼ばれますか?

解説: 制御コネクション(21番ポート)はログインやコマンドのやり取りを行い、実際のファイルの中身は別途確立されるデータコネクションで転送されます。

Q2. アクティブモードでデータコネクションが確立される向きはどれですか?

解説: アクティブモードでは、サーバー側がクライアントの指定したポートへ新規に接続しに行きます。クライアント側にNAT/ファイアウォールがあると、この新規着信が拒否されやすくなります。

Q3. パッシブモードが現在の事実上の標準になっている主な理由はどれですか?

解説: パッシブモードではクライアントが接続を開始するため、着信を必要とせず、NAT/ファイアウォールの内側にいるクライアントでも問題が起きにくくなります。

Q4. FTPSとSFTPの関係として正しいものはどれですか?

解説: FTPSは既存のFTPプロトコルにTLS暗号化を追加したものです。SFTPはSSHプロトコル上で動くサブシステムであり、FTPのプロトコル構造とは無関係です。

Q5. vsftpdでchroot_local_user=YESの状態で、ホームディレクトリがユーザー自身から書き込み可能になっていると表示されるエラーはどれですか?

解説: 書き込み可能なchrootルートを起点にした脱出攻撃を警戒し、vsftpdはこのエラーでセッションの確立を拒否します。根本対策としては、ホームディレクトリを読み取り専用にし、書き込み可能なサブディレクトリを別途用意するのが安全です。

Q6. userlist_enable=YES、userlist_deny=YESの組み合わせで、userlist_fileに記載されたユーザー名の扱いはどれですか?

解説: userlist_deny=YES(既定値)の場合、userlist_fileに記載されたユーザー名はログインを拒否されるブラックリストとして機能します。rootをここに記載し、FTPログインの対象から除外するのが定石です。

Q7. 匿名FTPで、アップロードを許可する際に必須とされる対策はどれですか?

解説: 匿名アップロードを許可する場合、アップロード先を公開領域と分離し、書き込みはできても一覧取得・ダウンロードはできない権限にしておかないと、warezの踏み台化などの被害につながります。

Q8. Pure-FTPdの起動オプションのうち、パッシブモード時にクライアントへ通知する外部IPアドレスを指定するものはどれですか?

解説: -P(大文字)はパッシブモード時に通知する外部IPアドレスを指定します。-p(小文字)はパッシブポートの範囲を指定するオプションで、混同しやすいので注意が必要です。

Q9. ProFTPdの設定構文の特徴として正しいものはどれですか?

解説: ProFTPdは、Apacheに似たVirtualHost/Anonymous/Limitなどのブロック構造を持つ設定構文を採用しており、Apacheの運用経験があれば読み書きしやすいのが特徴です。

Q10. nf_conntrack_ftpモジュールの役割として正しいものはどれですか?

解説: nf_conntrack_ftpは、制御コネクション上のPASV応答をカーネルが解析し、合意されたデータポートへの接続をRELATEDとして動的に追跡・許可するヘルパーモジュールです。

Q11. FTPS(TLSで制御コネクションを暗号化したFTP)を使う場合、nf_conntrack_ftpが機能しなくなる理由はどれですか?

解説: nf_conntrack_ftpは制御コネクションの中身を解析して動作しますが、FTPSでは制御コネクションがTLSで暗号化されるため、ファイアウォールはPASV応答の内容を読み取れず、このヘルパーは機能しなくなります。

Q12. ログインまでは成功するが、ファイル一覧取得やダウンロードで止まる場合の切り分け方法として適切なものはどれですか?

解説: アクティブモードとパッシブモードで挙動が変わるかを確認することで、データコネクションの確立に関する問題を、モードに応じたポート開放の問題に絞り込めます。

Q13. NAT環境のサーバーでpasv_addressの設定を忘れた場合に起きがちな問題はどれですか?

解説: pasv_addressを設定していないと、NAT環境ではクライアントに内部プライベートIPアドレスが通知されてしまい、クライアントはそのアドレスへ到達できずデータコネクションが確立できません。