ssh サービスを保護する方法はたくさんあると思います。
http://kumaneko-sakura.sblo.jp/article/1275428.html では、接続元ポート番号を制限することで ssh サービスが稼動していることをポートスキャンにより捕捉されないようにする手法について紹介しました。
でも、利用者が不特定多数である場合、接続可能な接続元ポート番号の範囲を隠し続けることは困難です。誰かがうっかりポート番号の範囲を洩らしてしまうかもしれません。
そこで、 http://kumaneko-sakura.sblo.jp/article/372199.html では、標準の ssh ログイン認証後に追加の認証を行わせることでブルートフォース等による不正侵入に対抗できるようにする手法について紹介しました。
ただし、この手法はログイン後に対話的な操作ができることを前提にしているため、 scp や sftp のようにログイン後に直ちに処理を行うプログラムには適用できませんでした。そのようなプログラムへの対策として http://kumaneko-sakura.sblo.jp/article/434756.html では、アクセス可能な範囲を限定するという手法について紹介しました。
今回、いくらか制約が増えるものの scp や sftp のようなプログラムにこの手法を適用することに成功したので紹介します。主な制約は以下の点です。
- ssh ログイン時に仮想端末が割り当てられないため、「プロンプトが表示されない」「 Ctrl-D でシェルを終了できない」など、操作性が劣る。
- クライアント側とサーバ側の両方に専用のプログラムを用意する必要がある。
- クライアント側プログラムは ssh プログラムを直接呼び出してはいけない。
- サーバ側のログインシェルとして既存のシェルを使うことができない。
使用するプログラムは以下の3つです。説明用に解りやすい名前にしてありますが、実際に導入する際は他の名前にして構いません。
- ssh_wrapper (クライアント側で使用)
- login_shell (サーバ側で使用)
- scp+sftp_wrapper (サーバ側で使用)
ログインシェルに -c オプションを指定して実行されるプログラムは、標準入出力の 1 バイト目からそのプログラム用のデータがやり取りされることを期待しています。そのため、プロンプトのように予期せぬデータが紛れ込むと正しく動作することができません。
今回の手法は、標準入出力を用いてやり取りされるプログラム用のデータの前に認証用のデータを挿入する必要があるので、どこからプログラム用のデータが始まるのかをはっきりさせなければいけません。そのため、如何に確実に同期を取るかが重要です。
ssh_wrapper と scp+sftp_wrapper ではプリアンブルとして 256 バイトの連続する 0 が出現したらプログラム用のデータの始まりであると判断するようにしています。もし、認証を行っている間にプリアンブルと同じデータが出現してしまった場合、正しく動作することができなくなります。
scp や sftp は -S オプションを使って ssh プログラムの場所を指定することができます。今回の手法は、このオプションを使って ssh の代わりに ssh_wrapper を実行し、 ssh_wrapper の中で対話的な操作を行わせます。
scp+sftp_wrapper.c を scp+sftp_wrapper.c として保存し、以下のようにコンパイルしてください。
|
gcc -Wall -O3 -o /bin/scp+sftp_wrapper scp+sftp_wrapper.c
|
login_shell.c を login_shell.c として保存し、以下のようにコンパイルしてください。
|
gcc -Wall -O3 -o /bin/login_shell login_shell.c
|
ssh_wrapper.c を ssh_wrapper.c として保存し、以下のようにコンパイルしてください。
|
gcc -Wall -O3 -o /bin/ssh_wrapper ssh_wrapper.c
|
サーバ側の準備として、ユーザのログインシェルを変更します。例えば demo というユーザの場合は以下のようにします。
|
usermod -s /bin/login_shell demo
|
クライアント側は、以下のように scp や sftp を起動する際に -S オプションを使って ssh ではなく ssh_wrapper を使うようにします。
|
sftp -S /bin/ssh_wrapper demo@example.com
|
|
scp -p -S /bin/ssh_wrapper demo@example.com:/home/demo/test.txt ~/
|
ssh でログインすると、 login_shell が -c というオプションを指定された状態で実行されます。
login_shell は -c というオプションで指定された処理を環境変数 ORIGINAL_COMMAND に保存してから /bin/sh を実行します。
この段階で追加の認証を行うようにしてください。振る舞いを制限するには TOMOYO Linux の強制アクセス制御機能を使ってください。
そして、追加の認証が終わって本来の処理を行う準備が整ったら、 scp+sftp_wrapper を実行してください。
scp+sftp_wrapper はプリアンブルを送受信して同期を確認後、環境変数 ORIGINAL_COMMAND で指定された処理を実行します。処理が終了後、 ssh 接続が閉じられるはずです。結果的に、ログインシェルに -c コマンドで渡された処理を実行後切断するのと同等の処理が行われたことになります。
今回のプログラムでは ssh_wrapper の中で端末を開いて手動で追加認証情報をやり取りさせるようにしましたが、 ssh_wrapper を改造すれば自動で追加認証情報をやり取りできるようにすることも可能でしょう。お好みの認証方式を作成して使ってください。既存の認証方式に囚われないのが利点ですので、思う存分、あなただけのアイデアを活用してください。