Teraterm+FFFTPによるFTPの暗号化
インターネット上には、TeraTerm と FFFTP を利用した FTP の暗号化についてよく解説されていますが、実は、制御コネクションは暗号化されていて、ここで扱われるユーザ名やパスワード等は暗号化されているが、データコネクションで通信されている実際の転送データは、全く暗号化されていないといことに言及されていません。従って、多くの方がデータ転送のほうも暗号化できていると誤解いしているようです。
ここでは、転送データは暗号化されていない理由と、その解決策の概要を示します。なお、Teraterm
+ FFFTP の具体的な設定方法は、ググッテいただければ山ほどありますので、ここでは省略します。
■SSH + FTP 通信の誤解
一般的に解説されている TeraTerm + FFFTP による FTP の暗号化通信は、実は下記のような通信形態になっており、データコネクションは全く暗号化されていません。また、SSHのデータ圧縮機能により転送が早くなるなどと書いてるサイトも多いですが、データコネクションはSSHトンネルを通過していないので、このようなご利益はありません。
何故、データコネクションがSSHトンネルを通らないかは、FTP通信の仕組みが理解できていればすぐにわかります。
- まず、FFFTPからlocalhostで待ち受けしているSSHトンネルを介して、リモートのFTPサーバに制御コネクションでログイン・認証を行う。この通信は、制御コネクション上で行われるので暗号化されている。
- 続いて、リモートのデータ(LIST)をクライアントから取得に行くが、Activeモードでは、クラアントからサーバに通知されるクライントのアドレスがlocalhostになっているため、これを受け取ったサーバは自分自身にデータコネクションを張ろうとしてしまい、全く通信できない。従って、PASVモードでアクセスすることになるが、サーバがPASVコマンドを受けるとデータコネクションの待ち受けアドレスとポートとして、自分自身の値、つまりサーバに付与されたプライベートアドレスとポートを制御コネクションを介してクライアントに通知する。(正確には、PASVコマンドを受けたときの動作をする。というのが正解である。ProFTPDやWarFTPDのようにNATルータ対策をしたデーモンの場合は、WAN側のグローバルアドレスが通知されるので、うまく動作する。)
- クライアントは、通知されたサーバの待ち受けアドレスとポートに向かってデータコネクションを張ろうとするが、サーバとクライアントが同一アドレス空間(両方ともプライベートか、両方ともグローバル。少なくともサーバはグローバル。)にいれば、アドレス関係で矛盾がないため通信できる。但し、クライアントは、サーバから通知されたサーバのアドレスに向かってデータコネクションを張るため、SSHトンネルを通らず、結果的に転送データは暗号化されない。
一方、サーバがインターネットを介してNATルータ配下にいると、
- クライアントは通知されたサーバのプライベートアドレスに接続しようとするが、インターネット上にプライベート空間があるわけがないので、一般的にはLIST表示で止まってしまう。
- NATルータ対策をしたデーモンならWAN側のグローバルアドレスが通知されるので、クライアントはそこに向かって接続にいくのでうまく通信できる。但し、SSHトンネルを通過していないので、当然、暗号化されてはいない。
- 類似の話として、ルータがFTPのPASVモード対策をしていて、PASV通信ができるケース(Bar
HG系、OPT系、DR202等)もあるが、これは、FTPの制御コネクションが21番ポートでルータを通過していて、ルータがPASVコマンドの内容を認識して自分のグローバルアドレスに変換しているので、サーバ側でNAT対策をすると逆に動作できなくなってしまう。従って、この手のルータを使用している場合、SSH
+ FTPでの通信は、一般的なFTP通信の外部公開をあきらめない限りできない。
上記のように、自宅サーバに外部からSSH + FTPでアクセスできるようにするには、以外に多くの条件がついているためなかなかうまく動作しない。動作条件を整理してみると、一般的なNATルータ配下の自宅サーバで外部からSSH
+ FTPでアクセスできるのは、
- サーバ側でFTPのPASVモード対策をしていないルータを使用し、デーモンでPASV対応している場合(WarFTPDやProFTPD等)。
- サーバ側でFTPのPASVモード対策をしているルータを使用しているが、一般的なFTPサーバの外部公開はせずに、デーモンでPASV対応している場合(WarFTPDやProFTPD等)。
しか上記対応はできないので、注意が必要である。
■データコネクションの暗号化対策
上記のような対応では、SSHで暗号化できるのは制御コネクションのみであり、データコネクションが暗号化されていないので、その対策を考えてみました。その結果はあまりにも当然な話ですが、PASVモードのデータコネクションをSSHトンネルを通るようにしてあげればよい、というのものです。
つまり、クライアントはサーバが返送した待ち受けアドレスにデータコネクションを張りにくるので、サーバからは、クライントのSSH宛てつまりlocalhostを通知してあげ、ポートとしては自分が待ち受けるポートを通知してあげれば、データコネクションはSSHトンネルを通過するようになります。また、クイライアント側では、サーバからデータコネクション用として通知されるであろう全てのポートをsshで転送しておくことで、localhostの当該ポートにFTPクライアントが接続してきて、結果としてサーバとの通信が確立することになります。但し、多くのクライアントの同時使用に対応しようとすると、PASV用ポートレンジが広くせざるを得ないため、クライアント側でそれらを全てSSH転送する設定が必要であり設定が大変になるので、同時利用は制限せざるを得ないと思います。
■サーバの設定
ここでは、おやじが使用しているWindows用としてWarFTPD、Linux用としてProFTPDの設定方法を示します。これらのデーモンにこだわる必要はないですが、NATルータ対策ができるデーモンでなければ対応はできません。なお、それぞれのデーモンの基本的な設定は、おやじの別コンテンツを参考にしてください。ここでは、PASVでサーバ公開できている前提で説明します。
◆WarFTPDの場合
設定は、非常に簡単であり、nat.confを以下のように少し設定変更して再起動すれば終わりである。
- nat.conf のlocalhost の設定を以下のように変更する。ポートレンジは、一般ftp通信とは別のポートでレンジで設定するとよい。ここでは5ポート分確保した。
localhost 0 localhost 3000-3004
- 実は上記だけで問題ないと思ったのだが、Windowsでcygwin + SSH でSSHを動かしている場合は、FTPデーモンからみると何故かlocalhostからのアクセスではなく、サーバ機自身のプライベートアドレスでアクセスしてくる。従って、下記のようにサーバ機自身のアドレスに対しても、1項と同様の設定を行う。
192.168.1.100 0 localhost 3000-3004
なお、サーバ機は家庭内端末の一部でもあるので、nat.confは以下の順に記載すること。
- localhost 0 localhost 3000-3004 (SSH転送)
- 192.168.1.100 0 localhost 3000-3004 (SSH転送:サーバ機)
- 192.168.1.0/24 0 0 0 (家庭内端末)
- 0/0 0 aconusftp.aconus.com:5 4000-4029 (インターネット)
上記のように設定を変更・追加して、再起動すればサーバ側の設定は終了である。なお、今回、追加したデータコネクション用のポートはSSHトンネルを介して設定されるので、ルータでのポートマッピングは不要です。
◆ProFTPDの場合
ProFTPDの場合は、inetdモードで動作していることが前提となり、新たに、ssh転送専用の設定を追加します。standaloneモードでもできますが、その場合は、インターネット上への外部公開や家庭内での一般的なFTP転送を行わないことが前提になります。
- ProFTPDは、WarFTPDのようにクライアントアドレスに応じた制御ができないため、ポート番号を通常のFTPと別にすることにより対応せざるを得ない。具体的には、SSH転送専用の制御コネクション用のポートをデフォルトの21番以外で1つ決める。ここでは、10021とした。このポートは、クライアント側の設定に関係してくる。
- 現状の proftpd.conf をベースに下記ディレクティブを変更したproftpd1.conf
を新規に作成する。他のディレクティブはSSH転送の使用目的に応じて適宜変更する。
- Port : 21 -> 10021
- MasqueradeAddress: aconusftp.aconus.com -> localhost
- PassivePorts : 5000 5029 -> 3000 3004
- /etc/services に既存サービス名とぶつからないこのサービス専用のサービス名を登録し、反映させるためxinet.d
を再起動する。ここでは、sshftpとした。
# echo "sshftp 10021:tcp # proftpd (SSH)" >>
/etc/services
# /etc/init.d/xinetd restart |
- 続けてxinetd 用の起動ファイル(ex. proftpd_ssh)を作成する。ポイントは、service
は上記で設定した新サービス名、server_args でssh用のconfファイルを設定し、このサービスはlocalhost以外から起動できないように、only_fromで指定することである。
# default: on
# description: The ProFTPD FTP server
service sshftp
{
flags = REUSE
socket_type = stream
wait = no
user = root
server = /usr/sbin/proftpd
server_args = -c /etc/proftpd1.conf
bind = 192.168.1.100
only_from = localhost
log_on_failure += USERID
disable = no
} |
- 既存の起動ファイルに、
no_access = localhost
を追加する。その後、xinet.dを再起動しておく。
■クライアントの設定
teraterm のSSH転送に制御コネクション用として以下のように設定する。
◆WarFTPDの場合
- Forward local port:21
- to remote machine :ホスト名もしくはIPアドレス
- port : 21
◆ProFTPDの場合
- Forward local port:21
- to remote machine :ホスト名もしくはIPアドレス
- port : 10021
◆データコネクション用の設定
続いて、データコネクション用は、どのポートが通知されるか不明なため、リザーブされたポート全て(3000〜3004)を1ポートづつSSH転送に設定する。
[3000の例]
- Forward local port:3000
- to remote machine :ホスト名もしくはIPアドレス
- port : 3000
■動作確認
実際に動かしてみると、確かにSSHトンネルでデータも暗号化されて通信できるのですが、さすがにLinuxでもSSHを通過する分遅くはなりますが、十分実用になると感じました。しかしながら、Windows環境では、FTPやSSH単体(SCP)ではそれなりの速度がでるのですが、SSH
+ FTPになると何故かダウンロードのみ42KB/s程度しかでず、とても使い物にはなるとは思えませんでした。 パケットを見た限りでは、このケースでは約3倍のパケットが通過しており、Windows版SSHが中継で暗号化するときのみ、非常に分割ロスがでているように見えました。試しに、異なるデーモン(GuildFTP)でも全く同じような速度でしたので、ボトムネックはSSHに間違いありません。これでは、素直にSCPを使ったほうがよいと思いました。
おやじの環境での測定結果を下記に示しておきますので、参考にしてください。
OS |
アクセス構成 |
Upload |
Download |
時間(sec) |
速度(KByte/s) |
時間(sec) |
速度(KByte/s) |
Linux |
ProFTPD |
0.64 |
6,253 |
0.38 |
10,531 |
ProFTPD + SSH |
1.16 |
2,485 |
3.85 |
1,039 |
SSH |
2.04 |
1,962 |
3.73 |
1,073 |
Windows |
WarFTPD |
0.36 |
11,116 |
0.71 |
5,637 |
WarFTPD + SSH |
5.43 |
737 |
94.72 |
42 |
SSH |
4.64 |
862 |
8.53 |
469 |
- サーバ機: Celeron 1.4G, Memory 512MByte, Windows2000 pro sp4
- クライアント機: Pentium4 2.6G HT, Memory 1GByte DC, WindowsXP sp2
Top Pageへ