第4章 OpenSSH を使う

Last Modified: Tue Sep 21 11:20:39 UTC 2010

さて、OpenSSH の動きがわかったところで、 この章では実際に sshd サーバデーモンが動いているマシンに 遠隔地のクライアントからログインする方法をご説明しましょう。

ここではまずクライアントもサーバも両方 UNIX マシンであり、 それぞれ OpenSSH クライアントとサーバがインストールされ、 サーバデーモンが正しく動いていると仮定しています。 Windows や Mac OS X からクライアントを使う方法については 4.6. UNIX 以外のマシンからログインする で紹介します。 なお、OpenSSH では異なる新旧 2つの SSH プロトコル (SSH1 プロトコル と SSH2 プロトコル) がサポートされており、 これらはコマンドの機能や公開鍵の形式がやや異なっています。 最近では新しい方の SSH2 プロトコルが普及しているため、この章では SSH2 プロトコルのみを扱います。 古い SSH1 プロトコルとの相互運用については 6.7.1. SSH1 プロトコルを使う を参照してください。

4.1. 公開鍵認証をつかったログイン (SSH2プロトコル)

公開鍵認証を使ってログインする場合、ユーザの手順は次のようになります:

  1. クライアント上で秘密鍵と公開鍵ペアを生成する。
  2. 公開鍵をサーバに登録する。
  3. クライアントからサーバにログインする。

1. と 3. の項では、ユーザはクライアントの上で作業します。 2. の項では、ユーザはサーバに直接 (ネットワーク経由ではなく) ログインするか、 あるいは公開鍵をサーバの管理者に送って登録してもらうよう依頼する必要があります。

4.1.2. 公開鍵をサーバに登録する では、クライアントユーザがサーバに直接ログインして作業することを前提とします。

4.1.1. クライアント上で秘密鍵と公開鍵ペアを生成する

はじめにクライアント上で秘密鍵と公開鍵ペアを生成しましょう。 OpenSSH には鍵のペアを生成する ssh-keygen というプログラムが含まれています。 これを以下のように実行します。
秘密鍵と公開鍵ペアを生成する
$ ssh-keygen -t rsa

実行例:

client$ ssh-keygen -t rsa                                         (RSA方式の鍵を生成する)
Generating public/private rsa key pair.
Enter file in which to save the key (/home/yusuke/.ssh/id_rsa):   (パス名を入力、あるいは Enter を押す)
Created directory '/home/yusuke/.ssh'.                            (ディレクトリ ~/.ssh/ が作成される)
Enter passphrase (empty for no passphrase):                       (秘密鍵につけるパスフレーズを入力する)
Enter same passphrase again:                                      (同じパスフレーズをもう一度入力する)
Your identification has been saved in /home/yusuke/.ssh/id_rsa.   (鍵が生成された)
Your public key has been saved in /home/yusuke/.ssh/id_rsa.pub.
The key fingerprint is:
23:56:6e:90:f3:98:fc:7b:2a:92:fb:46:bf:20:98:71 yusuke@client     (公開鍵の指紋が表示される)

図 generate-pubkey-pair. クライアント上で秘密鍵と公開鍵ペアを生成する

ここで使用した -t rsa というオプションは RSA 方式の鍵を生成するよう指示するものです。 OpenSSH の公開鍵認証で使える鍵には RSA と DSA という 2種類の方式があります。 どちらの鍵を使ってもそれほど差はないと考えられていますので、 ここではデフォルトの RSA 方式を使います。 バージョン 4.3p1 以降の OpenSSH では、-t rsa を指定しなくても 自動的に RSA 方式の鍵が生成されます。 [脚注: DSA 方式は、もともと RSA 方式に特許がまだ有効だったころ、 その特許を回避するために開発されたものです]

ssh-keygen は秘密鍵と公開鍵のペアを生成したあと、 それらをユーザのホームディレクトリ ~/.ssh/ に保存します (図 generate-pubkey-pair)。 このディレクトリが存在していない場合は自動的に作られます。 秘密鍵を格納したファイルは安全のためにそれ自体が暗号化されており、 ここで入力したパスフレーズはあとでそれを使用するときに使われます。 3.3.2. 秘密鍵・公開鍵ペアを使ったユーザ認証 で説明したとおり、このパスフレーズはネットワーク上には流れません。

ssh-keygen の実行後、ユーザの ~/.ssh/ディレクトリは次のようになっているはずです:

client$ ls -la ~/.ssh/                           (~/.ssh/ ディレクトリの内容を表示する)
drwx------   2 yusuke  users     104 Mar  9 07:13 ./
drwxr-xr-x  60 yusuke  users    4048 Mar  9 07:13 ../
-rw-------   1 yusuke  users    1675 Mar  9 07:12 id_rsa          (秘密鍵を格納したファイル)
-rw-r--r--   1 yusuke  users     394 Mar  9 07:12 id_rsa.pub      (公開鍵を格納したファイル)

ここで、~/.ssh/ ディレクトリのパーミッションと、秘密鍵を記録した id_rsaファイルの パーミッションがそれぞれ 700 (-rwx------、所有者のみが読み書き実行可能) と 600 (-rw-------、所有者のみが読み書き可能) になっていることに注意してください。 秘密鍵ファイルが他人から読める状態になっていると、OpenSSH クライアントはその使用を拒否します。

生成された id_rsa ファイルと id_rsa.pub ファイルはどちらも テキストファイルであり、その内容は以下のようになっています。 [脚注: なお id_rsa.pub ファイルはただ 1行のテキストファイルですが、 1行が非常に長いため、実際の端末上では何行にも分かれて見えます。]

id_rsa ファイル:

client$ cat ~/.ssh/id_rsa
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,3DF819517CEB371F

7t1IOZJdKwjVuJiUVx5WglDWbnLD9B4HB/I1etwlqFSdrweyU+V3h+xbxfEvdBQc
dXKcK0j4enTMzhBrUOjGJxS0b1TNG06O3HiLsjuTLGzm1fjmJkbDC68WkA/Nz+Si
...
0g7kSz64iYACKFXrIiuD5dNPVUhJegS37iOcPl/2h7VK6QsDzOK95g==
-----END RSA PRIVATE KEY-----

id_rsa.pub ファイル:

client$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAoIiNSHbpbrpMGTE7Dv...(中略)...r85xe/RC6WidsmebTYlZC91Lmw== yusuke@client

これ以降、この id_rsa ファイルを、クライアントの外部に持ちだす必要は決してありません。 いっぽう、公開鍵の入った id_rsa.pub ファイルは、この後サーバに登録するため、 サーバに転送する必要があります。秘密鍵のサーバへの登録方法については 4.1.2. 公開鍵をサーバに登録する で説明します。

なお、秘密鍵につけたパスフレーズを変更するには、次のようにします:
秘密鍵のパスフレーズを変更する
$ ssh-keygen -p [-f 秘密鍵ファイル]

実行例:

client$ ssh-keygen -p
Enter file in which the key is (/home/yusuke/.ssh/id_rsa):   (秘密鍵ファイルの位置を入力する、デフォルトなら Enter)
Enter old passphrase:                                        (古いパスフレーズを入力する)
Key has comment '/home/yusuke/.ssh/id_rsa'                   (秘密鍵ファイルのコメントが表示される)
Enter new passphrase (empty for no passphrase):              (新しいパスフレーズを入力する)
Enter same passphrase again:                                 (新しいパスフレーズをもう一度入力する)
Your identification has been saved with the new passphrase.  (秘密鍵ファイルが更新された)

4.1.2. 公開鍵をサーバに登録する

秘密鍵と公開鍵のペアを生成したら、 サーバに公開鍵ファイル id_rsa.pub を転送し、登録します。 登録はクライアントユーザの (サーバ上にある) ホームディレクトリ以下の ~/.ssh/authorized_keys と呼ばれるファイルに id_rsa.pub の内容を追記することによっておこないます (図 send-pubkey-to-server)。 id_rsa.pub と同様に ~/.ssh/authorized_keysファイルもまたテキストファイルで、 そこには 1行につきひとつの公開鍵が格納されています。


図 send-pubkey-to-server. 公開鍵をサーバに登録する

混乱しやすいですが、クライアントにもサーバにも ~/.ssh/ ディレクトリが必要なことに注意してください:
クライアント側の ~/.ssh/ サーバ側の ~/.ssh/
ログインに使う秘密鍵ファイル (id_rsa あるいは id_dsa) が必要。
client$ ls -la ~/.ssh/
drwx------  2 yusuke users  104 Mar 9 07:13 ./
drwxr-xr-x 60 yusuke users 4048 Mar 9 07:13 ../
-rw-------  1 yusuke users 1675 Mar 9 07:12 id_rsa
-rw-r--r--  1 yusuke users  394 Mar 9 07:12 id_rsa.pub
ログインに使う秘密鍵に対応する公開鍵 (id_rsa.pub または id_dsa.pub) を 登録した authorized_keys ファイルが必要。
server$ ls -la ~/.ssh/
drwx------  2 yusuke users  104 Mar 9 12:11 ./
drwxr-xr-x 59 yusuke users 4136 Mar 9 14:02 ../
-rw-------  1 yusuke users 1586 Mar 9 18:01 authorized_keys

※ これはサーバ上のユーザー yusuke が直接コマンドを実行した場合の出力例です。

id_rsa.pub ファイルの転送方法はどのようなものでもかまいませんが、 できるだけ信頼できる方法を使う必要があります。 なぜなら公開鍵は重要な情報であり、これが転送中に 別のものにすり替えられてしまうと、本来意図したユーザとは 別のユーザのログインが可能になってしまうからです。 別のユーザのログインを認めてしまうことになるからです。 [脚注: とはいうものの、筆者は実際のところ公開鍵の転送に電子メールを使っています。] このとき、id_rsa.pub がすり替えられていないかどうかを確かめるには、 ssh-keygen コマンドを使って公開鍵の指紋を確認します。
公開鍵の指紋を確認する
$ ssh-keygen -l [-f 公開鍵ファイル]

実行例:

server$ ssh-keygen -l -f id_rsa.pub
2048 23:56:6e:90:f3:98:fc:7b:2a:92:fb:46:bf:20:98:71 id_rsa.pub   (鍵の長さと指紋が表示される)
注意
公開鍵が同じかどうか確認するときは、 id_rsa.pub ファイルの内容を目で比べることはせず、 かならず指紋を照合するようにしてください。 id_rsa.pub ファイルの最初の数十文字はどの公開鍵でも共通です。

さて、サーバへ無事に id_rsa.pub を転送できたと仮定します。 このあと (サーバ上の) ホームディレクトリ以下にも同じ ~/.ssh/ ディレクトリを作成し、以下のようにして id_rsa.pubファイルの内容を ~/.ssh/authorized_keys ファイルに追加します:

server$ mkdir ~/.ssh/                                   (.ssh ディレクトリを作成する)
server$ cat id_rsa.pub >> ~/.ssh/authorized_keys        (id_rsa.pub の内容を authorized_keys に追加する)

ここで cp ではなく cat を使っているのは、 ~/.ssh/authorized_keys ファイルを上書きするのではなく、 id_rsa.pub の内容をこのファイルに追加しているからです。

authorized_keys ファイルには、以下のように 複数の公開鍵を登録することができます:

$ cat ~/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAoIiNSHbpbrpMGTE7Dv...(中略)...r85xe/RC6WidsmebTYlZC91Lmw== yusuke@client  (公開鍵1)
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6H91zpdy0pXubJgEV2...(中略)...pR5ehR6hIS5BzdIF3rwjQZhI+Q== yusuke@laptop  (公開鍵2)

このような場合、新しい公開鍵を登録するときに 他の公開鍵を消してしまわないよう、公開鍵の登録には cp ではなく cat を使うくせをつけておくとよいでしょう。

4.1.3. 公開鍵認証でログインする

ではログインしてみましょう。 公開鍵認証では、サーバはクライアントが持っている秘密鍵のうち、 それに対応する公開鍵が ~/.ssh/authorized_keys ファイル中に 登録されているかどうかを調べます。対応する公開鍵があった場合、サーバは 公開鍵暗号技術をもちいてクライアントに秘密鍵の所有を証明するよう要求します。このときクライアントは id_rsa ファイル中に格納されている暗号化された秘密鍵を復元するために、 ユーザにパスフレーズの入力を促します。正しいパスフレーズが与えられると秘密鍵が復元され、 秘密鍵の所有がサーバに証明されることで、ログインが成功します (図 pubkey-authentication-in-real)。 [脚注: 厳密には、クライアントはまず自分の持っている秘密鍵に対応する 公開鍵をサーバに送ります。その公開鍵がサーバに登録されている場合、 サーバはある秘密の値をその鍵によって暗号化してクライアントに送ります。 公開鍵によって暗号化された情報を正しく復号するにはそれに対応する 秘密鍵が必要なため、もしクライアントがその値を正しく復号して 送り返してくれば、そのクライアントは対応する秘密鍵をもっていると確信できます。]


図 pubkey-authentication-in-real. 公開鍵認証を使ってログインする

ssh コマンドでログインするには、以下のように入力します。 サーバ上でも同じユーザ名を使っている場合は、"ユーザ名@" の 部分を省略してもかまいません。なお、デフォルトでは ssh は リモートホストの TCP 22番ポートに接続しますが、サーバ側の sshd のポート番号を 変えている場合 (5.5.3. パスワード推測攻撃を避ける 参照) は -p オプションでポート番号を 指定する必要があります。
ログインする
$ ssh [-p ポート番号] [ユーザ名@]ホスト名

なお、秘密鍵ファイルが ~/.ssh/id_rsa あるいは ~/.ssh/id_dsa 以外である場合は、 以下のように -i オプションを使って秘密鍵ファイルをじかに指定することもできます。
特定の秘密鍵ファイルをつかってログインする
$ ssh [-p ポート番号] [-i 秘密鍵ファイル] [ユーザ名@]ホスト名

すると、おそらく次のように表示されるでしょう。

client$ ssh yusuke@server.example.com
The authenticity of host 'server.example.com (11.22.33.44)' can't be established.
RSA key fingerprint is ac:62:6e:32:7e:6f:bc:6a:2f:a1:e5:f3:a5:db:7f:c0.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added server.example.com,11.22.33.44' (RSA) to the list of known hosts.
Enter passphrase for key '/home/yusuke/.ssh/id_rsa':  (秘密鍵のパスフレーズを入力する)
Last login: Mon Mar 13 12:01:22 2006 from xx.xx.xx.xx
server$

3.2. ホスト認証のしくみ で説明したように、そのサーバにはじめてログインしたときは そのサーバのホスト公開鍵の指紋が表示されます。ユーザはその指紋が正しいかどうかを確認し、 正しければ yes を入力します。一度この確認をしたあとは server.example.com のホスト公開鍵は ~/.ssh/known_hosts ファイルに記録されるため、 2回目以降のログインではこの質問はされなくなります。
注意
あるサーバに接続したとき、OpenSSH はそのサーバに対応するホスト公開鍵を known_hosts ファイルの中から検索しますが、ここでのホスト名は sshコマンドに渡された名前がそのまま使われます。 したがって、たとえ server.example.commail.example.com が同じ IPアドレスを指していたとしても、 OpenSSH はこの事実を考慮せず、正確にその名前で登録されているホスト公開鍵を検索します。 これは DNS 詐称によるなりすましを防ぐためです。 もし指定されたホスト名をいったん IPアドレスに変換してから保存したとすれば、 悪意ある DNS サーバがそのホスト名に別の IPアドレスを割り当てることで、 ホスト公開鍵の検証を回避できてしまうためです。 このため、たとえ同じ IP アドレスを指すホスト名でも、これまでに sshコマンドの引数として使われたことがなければ OpenSSH は ホスト公開鍵の確認を求めます。また、 DNS 詐称を検出するために OpenSSH では ホスト名とそれに対応する IPアドレスもあわせて known_hosts ファイル内に保存しています。

client$ cat ~/.ssh/known_hosts                     (known_hosts ファイルの内容を確認する)
server.example.com,11.22.33.44 ssh-rsa AAAAB3NzaC1yc2E...(中略)...NVdw1Nrs= 
        (server.example.com と 11.22.33.44 のホスト公開鍵が登録されている)
client$ ssh yusuke@server.example.com              (2回目のログイン)
Enter passphrase for key '/home/yusuke/.ssh/id_rsa':  (秘密鍵のパスフレーズを入力する)
Last login: Mon Mar 14 15:12:43 2006 from xx.xx.xx.xx
server$

ここでユーザが入力したパスフレーズはサーバには送信されず、 クライアント上で暗号化された秘密鍵を復元するためだけに使われています。 秘密鍵はふだんは id_rsa ファイルの中に暗号化されて保存していますが、 ユーザからパスフレーズを与えられると復元して使用できる状態になります。 この秘密鍵自身はサーバに送信されないので、 ユーザは秘密の情報をいっさいネットワーク上に流さずに サーバに安全にログインすることができたわけです。

エスケープシーケンス機能

サーバに対話的にログインしている時は、 エスケープシーケンス (escape sequence) が使用できます。 これは ~ (チルダ文字) で始まる特定の文字をタイプすることによって、 現在の ssh クライアントの状態を制御できる機能です。 代表的なエスケープシーケンスを表 ssh-escape-sequences に示しました。 なお、エスケープシーケンス機能が利用できるのはサーバ上に仮想端末が割り当てられているときのみであり、 リモートコマンド (4.1.4. リモートコマンドを実行する 参照) を実行するさいにはエスケープシーケンス機能は利用できません。
表 ssh-escape-sequences. よく使われるエスケープシーケンス
入力する文字列 効果
~. 現在の接続を強制的に切断する。
~^Z (Control-Z) ssh をバックグラウンド化する。
~& X11 転送を有効にしている場合、シェルを抜けた後に ssh をバックグラウンド化する。
~# 現在有効になっているポート接続の一覧を表示する。
~? エスケープシーケンスのヘルプ画面を表示する。
~C コマンドラインに入る。ポート転送を追加・停止したり、ローカルホスト上でコマンドを実行できる。
~~ 実際のチルダ文字 (~~) を入力する。

4.1.4. リモートコマンドを実行する

OpenSSH では、ログインして対話的なシェルを実行するかわりに リモートホスト (サーバ) 上で特定のコマンドを一回だけ実行し、 すぐにログアウトするという機能もあります。この場合、 ssh コマンドは与えられた引数をコマンド列として sshd に渡し、sshd は サーバ上でこのコマンド (リモートコマンド) を実行します。 このとき ssh への標準入力がサーバ上で実行されるプロセスの標準入力に転送され、 このプロセスの標準出力が ssh の標準出力に転送されます (図 remote-command)。 また、サーバ上のプロセスの終了状態もそのままクライアント上に転送され、sshコマンドの 終了状態となるので、この機能を使うことにより遠隔地のマシンのコマンドをあたかも ローカルにあるかのように実行できます。この仕組みは、分散処理システムなどで使われる RPC (リモートプロシージャコール) に似ています。 なお、この場合はサーバ上のプロセスが端末制御を行うための仮想端末 (pty) は 割り当てられず、最終ログイン時刻などのメッセージも表示されません。 サーバ上のプロセスに強制的に端末を割り当てるには -t オプションを指定します。
リモートコマンドを実行する
$ ssh [-p ポート番号] [-t] [ユーザ名@]ホスト名 コマンド 引数1 引数2 ...

実行例:

client$ ssh yusuke@server.example.com ls -l           (サーバ上で ls -l を実行する)
Enter passphrase for key '/home/yusuke/.ssh/id_rsa':  (秘密鍵のパスフレーズを入力する)
drwx------    4 yusuke   users       120 Mar 27 01:19 Mail
drwxr-xr-x    7 yusuke   users      2184 Mar 14 14:26 bin
drwxr-xr-x    5 yusuke   users       344 Feb  6 19:53 lisp
drwxr-xr-x    4 yusuke   users      1184 Mar  8 21:27 work
drwxr-xr-x   10 yusuke   users       864 Mar 25 19:44 tmp
drwxr-xr-x    7 yusuke   users       168 Mar  6 17:00 tex
client$ echo $?                                       (ssh の終了状態を見る)
0
client$ ssh yusuke@server.example.com /bin/false      (サーバ上で /bin/false を実行する)
Enter passphrase for key '/home/yusuke/.ssh/id_rsa':
client$ echo $?                                       (ssh の終了状態を見る)
1

実際には、ここで指定するリモートコマンド名と引数はすべてサーバ上でひとつにまとめられ、 シェルの -c オプションをつかって実行されるため、 [脚注: tcshbash のどちらにおいても、-c オプションは 与えられた文字列をコマンドラインとしてじかに解釈するよう指示するものです。] シェルのコマンドやワイルドカードによるファイル指定も使用できます。 また、複数個の引数を引用符 "〜" で囲んで渡しても結果は変わりません。

client$ ssh yusuke@server.example.com echo "*"           (サーバ上で echo * を実行する)
Enter passphrase for key '/home/yusuke/.ssh/id_rsa':
Mail bin lisp work tmp tex
client$ ssh yusuke@server.example.com "echo *"           (サーバ上で echo * を実行する)
Enter passphrase for key '/home/yusuke/.ssh/id_rsa':
Mail bin lisp work tmp tex

4.2. パスワード認証をつかったログイン (SSH2プロトコル)

公開鍵認証をつかわない場合、OpenSSH では伝統的な UNIX のパスワードをつかった ログインもできます。ただしこの場合、パスワードの盗難に注意する必要があります (3.2.2. なりすましによるパスワードの盗難 参照)。 したがって、あるサーバにはじめて接続する時にはあらかじめそのサーバのホスト公開鍵を確認し、 実際の接続時に表示される指紋と比較できるようにしておくことが大切です。

サーバのホスト公開鍵とホスト秘密鍵は通常 sshd の設定ファイルと同じディレクトリに 格納されています。ホスト公開鍵は一般ユーザにも読めるようになっているので、 ユーザはそのサーバに遠隔地からログインする前に、 以下のように ssh-keygen コマンドを使ってホスト公開鍵の指紋を調べておきます:

server$ ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key.pub  (RSA公開鍵の指紋を表示する)
2048 ac:62:6e:32:7e:6f:bc:6a:2f:a1:e5:f3:a5:db:7f:c0 /etc/ssh/ssh_host_rsa_key.pub
server$ ssh-keygen -l -f /etc/ssh/ssh_host_dsa_key.pub  (DSA公開鍵の指紋を表示する)
2048 ac:62:6e:32:7e:6f:bc:6a:2f:a1:e5:f3:a5:db:7f:c0 /etc/ssh/ssh_host_dsa_key.pub

パスワード認証のさいは、この値をどこかにメモしておくか、 サーバ管理者に問い合わせるなどして、事前に指紋を知っておくことが必要です。 その後、サーバに接続して正しい指紋が表示されれば ユーザは安心してパスワードを入力することができます。 ssh コマンドの使い方そのものは公開鍵認証のときと変わりません。

client$ ssh yusuke@server.example.com
The authenticity of host 'server.example.com (11.22.33.44)' can't be established.
RSA key fingerprint is ac:62:6e:32:7e:6f:bc:6a:2f:a1:e5:f3:a5:db:7f:c0.   (ホスト公開鍵の指紋が正しいことを確認する)
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added server.example.com,11.22.33.44' (RSA) to the list of known hosts.
yusuke@server.example.com's password:    (パスワードを入力する)
Last login: Mon Mar 13 12:05:06 2006 from xx.xx.xx.xx
server$

本書では、特別な事情がある場合をのぞき公開鍵認証を使うことをおすすめします。 公開鍵認証では、たとえ何らかの理由で秘密鍵につけたパスフレーズが推測されてしまったとしても、 秘密鍵ファイルそのものを持っていなければログインされてしまうことはありません。 しかし、パスワード認証ではパスワードさえ知っていれば誰でも そのサーバにログインできてしまいます。 また、パスワード認証では、たとえ暗号化された形とはいえパスワードが ネットワーク上を流れます。いずれにせよ公開鍵認証ほど安全ではありません。
サーバ管理者からみたパスワード認証の問題点
ユーザは、覚えやすいパスワードにしようとするあまり、 簡単に推測が可能なパスワードをつけてしまうことがよくあります。 ユーザの名前や誕生日はもちろんのこと、 辞書に載っている単語や簡単な日本語をローマ字にしたものを パスワードとして使うのは危険です。 インターネット上では、とくに 2005年ごろから辞書に載っている単語を組み合わせ ユーザ名とパスワードを多数生成し、それらを用いてサーバに繰り返しログインを試みる攻撃が多発しています。 ユーザ名としては日本語の名前を試した攻撃例も見つかっています。 そのため、パスワード認証を許可するときはパスワードの選び方に 十分注意するとともに、不審なログインの形跡がないかどうか 気をくばるようにしてください。 5.1.4. パスワード認証を安全に使うには ではパスワード認証を安全に使う方法を、 5.5.3. パスワード推測攻撃を避ける ではパスワードの推測攻撃を防ぐ方法を紹介します。

4.3. ファイル転送

OpenSSH には、サーバにログインして直接シェルを動かす ssh コマンドに加えて、 ファイルを転送するためのコマンド scpsftp も用意されています。 これらはそれぞれ昔の UNIX に含まれていた rcpftp を 模倣したもので、ssh コマンドと同じ認証方式を使い、 暗号化されたファイル転送をおこないます。

scpcp コマンドで通常のファイルをコピーする感覚で簡単に使えますが、 効率が悪く、大量のファイルを転送する用途には向きません。また、scpコマンドは 実装の拠りどころとなる規格が策定されていないため、一部の SSH サーバでは互換性を期待できないこともあります。 いっぽう sftp コマンドは SSH プロトコルの一部として正式に定義されていますが、 こちらは ftp コマンドと同じく、一度 sftp コマンドで ログインし、内部でさらに別のコマンドを呼び出すという形をとっており、 シェルとの連携はうまくありません。

この節では、これら scpsftp に加えて、 ネットワークを介したファイルの大量転送に適した rsync コマンドと OpenSSH とを併用する方法、 さらに、Emacs 上のツールである TRAMP を使用する方法を紹介します。

4.3.1. scp をつかったファイル転送

scp コマンドの使い方は簡単です。 通常の cp コマンドでパス名を指定するかわりに、 サーバ上にあるファイルを scp コマンドで [ユーザ名@]ホスト名:パス名 のように指定すればよいのです。ユーザ名がクライアントとサーバ上で同じ場合はユーザ名の入力を省略できます。 scpコマンドは内部で sshコマンドを呼び出しているため、 sshと同じく、最初にホスト認証が行われ、ユーザは 公開鍵認証のパスフレーズ (あるいは、パスワード認証の場合はサーバ側のパスワード) を 入力する必要があります。

また scp では cp コマンドと同様、 転送元として複数のファイルを指定することもできます。
scp の使い方
(クライアントからサーバへファイル転送)
$ scp [オプション] パス名1 [パス名2 ...] [ユーザ名@]ホスト名:[パス名]

(サーバからクライアントへファイル転送)
$ scp [オプション] [ユーザ名@]ホスト名:パス名1 [[ユーザ名@]ホスト名:パス名2 ...] パス名

なお、サーバ上のパス名として絶対パスを指定しなかった場合は、そのサーバ側のホームディレクトリからの 相対パスとみなされます。代表的なオプションを 表 scp-command-options にまとめました。
表 scp-command-options. scp コマンドのオプション
オプション説明
-q 進捗を表示しない (quiet)。
-r ディレクトリを再帰的に転送する (recursive)。
-p 転送元ファイルの更新日時やパーミッションも反映させる (preserve)。
-P ポート番号 デフォルト (TCP 22番) 以外のポート番号に接続する。

以下に典型的な実行例を示します。

  (サーバ上の /etc/motd ファイルをカレントディレクトリに転送する)
$ scp yusuke@server.example.com:/etc/motd .
Enter passphrase for key '/home/yusuke/.ssh/id_rsa':  (秘密鍵のパスフレーズを入力する)
motd                                      100%  120     0.1KB/s   00:00
  (book.html と book.pdf をサーバの自分のホームレディレクトリ上に転送する)
$ scp book.html book.pdf yusuke@server.example.com:
Enter passphrase for key '/home/yusuke/.ssh/id_rsa':  (秘密鍵のパスフレーズを入力する)
book.html                                 100%   86KB  85.7KB/s   00:01
book.pdf                                  100%  194KB  67.1KB/s   00:03
  (mail/ ディレクトリ全体をサーバのホームレディレクトリ上にある work/ ディレクトリ内に転送する、
     このとき進捗状況を表示しない)
$ scp -r -q mail/ yusuke@server.example.com:work/
Enter passphrase for key '/home/yusuke/.ssh/id_rsa':  (秘密鍵のパスフレーズを入力する)
$

ファイルを何度かに分けて転送する場合は、 繰り返しパスフレーズを入力するのはわずらわしいと思うかもしれません。 このような場合は、認証エージェントを使うと便利です。 詳しくは 4.4. 認証エージェントを使う を参照してください。

4.3.2. sftp をつかったファイル転送

sftp コマンドは、 従来ファイル転送につかわれていた ftp コマンドに似ています。 ユーザはまずサーバにログインし、その後 sftp 内部の転送コマンドを入力することで ファイルを転送します。いくつものファイルを選びながら転送したり、 サーバ側の転送先を確認しながら転送したりしたい場合は、繰り返しログインをおこなわなければならない scp コマンドよりも効率的ですが、同時にいくつものコマンドを入力する 必要があるため、ファイルを 1つだけ転送するような場合に使うのはやや面倒です。

sftp コマンドも ssh と同じく、 最初にユーザ名とホスト名を指定してログインします。 オプションではポート番号も指定できます。
sftp の使い方
$ sftp [-oPort=ポート番号] [ユーザ名@]ホスト名[:ディレクトリ名]

実行例:

$ sftp yusuke@server.example.com                  (サーバに接続する)
Connecting to server.example.com...
sftp> ls -l                                       (ファイルの一覧を表示)
drwx------    4 yusuke   users       120 Mar 27 01:19 Mail
drwxr-xr-x    7 yusuke   users      2184 Mar 14 14:26 bin
drwxr-xr-x    5 yusuke   users       344 Feb  6 19:53 lisp
drwxr-xr-x    4 yusuke   users      1184 Mar  8 21:27 work
drwxr-xr-x   10 yusuke   users       864 Mar 25 19:44 tmp
drwxr-xr-x    7 yusuke   users       168 Mar  6 17:00 tex
sftp> cd tex                                      (リモート側のカレントディレクトリを変更する)
sftp> ls -l                                       (ファイルの一覧を表示)
-rw-r--r--    1 yusuke   users       816 May 23  2005 init.tex
-rw-r--r--    1 yusuke   users       431 Sep 29  2004 wide.sty
-rw-r--r--    1 yusuke   users    155290 Dec 16 17:31 yusuke.bib
sftp> get yusuke.bib                              (yusuke.bib をローカルに転送)
Fetching /home/yusuke/tex/yusuke.bib to yusuke.bib
/home/yusuke/tex/yusuke.bib             100%  152KB 151.7KB/s   00:01
sftp> quit                                        (sftp を終了する)
$

ftp と同様、sftp にも 「カレントディレクトリ」という概念があります。 コマンド実行時にディレクトリ名を指定しておくと、クライアントは ログイン後、そのディレクトリに移動します。 ログインすると、"sftp>" というプロンプトが表示され、 表 sftp-commands. のような内部コマンドが使用可能になります。 [脚注: ここに挙げた以外にも chown, chgrp, lmkdir, lumask, progress, version などの コマンドがありますが、使用頻度が低いので割愛してあります。詳しくは sftpコマンドの マニュアルを参照してください。] ftp コマンドを使ったことのある方なら、おそらく操作はたやすいでしょう。 [脚注: OpenSSH をインストールするとき configure のオプションで --with-libedit を指定していると、sftp 内でも Emacs ライクなキー操作による 行編集が使えます。ただし、シェルとは違ってファイル名補完はサポートされていません。]

基本的なコマンド
表 sftp-commands. sftp の内部コマンド一覧 (一部省略あり)
コマンド説明
ヘルプを表示:
 help あるいは ?
コマンドのヘルプを表示します。
リモートディレクトリの内容を表示:
 ls [オプション] [パス名]
リモート (サーバ側) のディレクトリの内容を一覧表示します。 パス名を指定しない場合はリモートのカレントディレクトリの内容が表示されます。 通常の ls コマンドと同じく、 -a (ドットで始まるファイルも表示), -l (詳細な情報を表示), -t (更新日時でソート) などのオプションが使用できます。
ローカルディレクトリの内容を表示:
 lls [オプション] [パス名]
ローカル (クライアント側) のディレクトリの内容を一覧表示します。 パス名を指定しない場合はローカルのカレントディレクトリの内容が表示されます。 ここで指定されたオプションは、ローカルの lsコマンドに渡されます。
リモート→ローカル転送:
 get [-P] リモートパス名 [ローカルパス名]
ファイルをローカル (クライアント側) に転送します。 ローカルパス名が指定されない場合は、(クライアントの) カレントディレクトリ上に転送されます。 -P オプションを指定すると、 ファイルのパーミッションや更新日時をリモート側のファイルに揃えます。 なお、ディレクトリをまるごと転送することはできません。
ローカル→リモート転送:
 put [-P] ローカルパス名 [リモートパス名]
ファイルをリモート (サーバ側) に転送します。 リモートパス名を指定しない場合は、(サーバの) カレントディレクトリ上に転送されます。 -P オプションが指定すると、 ファイルのパーミッションや更新日時をローカル側のファイルに揃えます。 なお、ディレクトリをまるごと転送することはできません。
リモートのカレントディレクトリ変更:
 cd リモートパス名
リモート (サーバ側) のカレントディレクトリを変更します。
ローカルのカレントディレクトリ変更:
 lcd リモートパス名
ローカル (クライアント側) のカレントディレクトリを変更します。
リモートのカレントディレクトリのパス名を見る:
 pwd
リモート (サーバ側) のカレントディレクトリのパス名を表示します。
ローカルのカレントディレクトリのパス名を見る:
 lpwd
ローカル (クライアント側) のカレントディレクトリのパス名を表示します。
sftp を終了する:
 exit または quit
ログアウトし、sftp を終了します。
その他のコマンド
表 sftp-commands. sftp の内部コマンド一覧 (一部省略あり)
コマンド説明
リモートのファイル名を変更:
 rename 旧パス名 新パス名
リモート (サーバ側) のファイルあるいはディレクトリ名を変更します。 UNIX の mv コマンドとは異なり、ファイルやディレクトリの移動には使えません。 また、すでに存在するファイル名を上書きすることはできません。
リモートのファイルを消去:
 rm パス名
リモート (サーバ側) のファイルを削除します。 UNIX の rm コマンドとは異なり、ディレクトリをまるごと削除することはできません。
リモートのパーミッションを変更:
 chmod パーミッション パス名
リモート (サーバ側) ファイルのパーミッションを変更します。 UNIX の chmod コマンドとは異なり、 ディレクトリ中のファイルすべてを変更することはできません。
リモートのディレクトリを新規作成:
 mkdir パス名
リモート (サーバ側) で新しいディレクトリを作成します。
リモートのディレクトリを削除:
 rmdir パス名
リモート (サーバ側) のディレクトリを削除します。 そのディレクトリ中にまだファイルが存在している場合はエラーになります。
リモートのシンボリックリンクを作成:
 symlink リンク先パス名 リンク元パス名
リモート (サーバ側) にシンボリックリンクを作成します。 そのリンク元のパス名がすでに存在している場合はエラーになります。
ローカルでシェルを実行:
 ! コマンド あるいは ! のみ
ローカルのクライアント上でシェルを呼び出し、コマンドを実行します。 コマンドが指定されていない場合は、子プロセスとしてシェルを起動します。

sftp の大きな欠点は、 ディレクトリをまるごと再帰的に転送できないことです。 このため、大量のファイルを一度に転送する場合は rsync を使うことをおすすめします (4.3.3. rsync をつかったファイル転送 参照)。 より対話的な機能を望む場合は、 UNIX で Emacs エディタを使っている方なら、 TRAMP というパッケージを使う方法があります (4.3.4. TRAMP をつかったファイル転送 参照)。

4.3.3. rsync をつかったファイル転送

rsync は OpenSSH の一部ではありませんが、 ネットワーク経由で大量のファイルを転送したり、 バックアップをおこなったりするためのツールとして普及しています。 ほとんどのオペレーティングシステムでは標準でパッケージが提供されており、 OpenSSH との連携もあらかじめ考慮されいるため、インストールしておくことをおすすめします。 ソースコードからインストールする場合は rsync の公式サイト [脚注: http://www.samba.org/rsync/] からダウンロードしてください。 なお、rsync はクライアントとサーバの両方にインストールする必要があります。

古いバージョンの rsync で OpenSSH を使った転送をするためには、 あらかじめクライアント上で環境変数 RSYNC_RSHssh を指定しておく必要があります: [脚注: rsync-2.6.6 以降のバージョンはデフォルトで ssh を使うようになっているので、 環境変数を指定する必要はありません]

(bash を使っている場合)
$ export RSYNC_RSH=ssh
(tcsh を使っている場合)
% setenv RSYNC_RSH ssh

rsync の使い方は scp に似ており、いたって簡単です。 ただしディレクトリを再帰的に転送する場合、パス名の指定方法に違いがあるので注意してください。 [脚注: rsync では、転送元のディレクトリ名の最後にスラッシュ (/) がつくか つかないかで意味が大きく違います。ディレクトリ名の最後にスラッシュがつかない場合、 それはそのディレクトリをまるごと (そのディレクトリを含めて) 転送することを意味しますが、 ディレクトリ名の最後にスラッシュがつく場合、それはそのディレクトリ中の個々の項目を転送することを意味します。 たとえば、X というディレクトリの中に Y と Z という 2つのファイルがあるとして、 rsync -a X dest/ はディレクトリ X をまるごと dest/ の中に転送し、 dest/X というディレクトリをつくります (dest/ がない場合は自動的に作成されます)。 いっぽう、rsync -a X/ dest/ は X の中にある全てのファイル (Y と Z) を dest/ の中に転送しますが、ディレクトリ X そのものは転送しません。]
rsync の使い方
(クライアントからサーバへファイル転送)
$ rsync -a [オプション] パス名 [パス名 ...] [ユーザ名@]ホスト名:[パス名]

(サーバからクライアントへファイル転送)
$ rsync -a [オプション] [ユーザ名@]ホスト名:パス名 [[ユーザ名@]ホスト名:パス名 ...]

実行例:

(サーバ上の /opt/yusuke というディレクトリのコピーを、ローカルの backup/ ディレクトリの中に作成する)
$ rsync -a yusuke@server.example.com:/opt/yusuke backup

(サーバ上の yusuke ホームディレクトリ中の work というディレクトリを、ローカルの work/ ディレクトリと同期させる)
$ rsync -a yusuke@server.example.com:work/ work/

ここで使用している -a オプションはディレクトリの再帰的な転送を可能にするもので、 これは同時にパーミッションや更新日時、シンボリックリンクなども正しく複製します。 rsyncscp に比べはるかに多くの機能をサポートしており、 単なるディレクトリの転送だけでなく、新しく更新したファイルのみを転送したり、 特定のパターンにマッチするファイルを除いたりすることもできます。 よく使われるオプションを表 rsync-options. に示しました。詳細については rsync のマニュアルを参照してください。
表 rsync-options. よく使われる rsync のオプション
オプション説明
-a ディレクトリを再帰的に転送し、パーミッションや更新日時、 シンボリックリンクなどの情報を可能なかぎり忠実に複製する (archival)。
-u 更新モード (update)。より新しいファイルが転送先にある場合は、そのファイルを転送しない。
-b バックアップ (backup)。転送先のファイルを上書きする場合、古いファイルのバックアップを作成する。
-v 冗長表示モード (verbose)。転送するファイル名を逐一表示する。
-z 圧縮を使用する (gzip)。 OpenSSH の設定ですでに通信の圧縮を指定している場合は、 このオプションは必要ありません。
-e "コマンド" ssh のかわりに実行するコマンドを指定する。 ssh で接続する際にオプションが必要な場合は、 -e "ssh -p22" のように指定できます。
--delete 転送元にはないファイルが転送先のディレクトリにあった場合、そのファイルを削除する。
--exclude パターン 指定されたパターンに合致するファイル名を無視する。

rsync のしくみ

rsync はクライアントとサーバの両方で実行されます。 まずクライアント側で実行された rsync コマンドが、 内部で sshコマンドを呼び出し、サーバ側の rsync を リモートコマンドとして実行します (図 rsync-client-server)。 その後、この 2つのプロセスは それぞれローカルとリモート上にある転送元と転送先のファイルを比較し、 ネットワーク転送量を最小限に抑えるような差分を送信します。 そのため、rsync はネットワーク経由で安全にバックアップをするのに最適です。 6.1.3. rsync を使ってネットワーク経由でバックアップする では rsync をつかった定期的なバックアップの方法を紹介しています。


図 rsync-client-server. rsync のしくみ

4.3.4. TRAMP をつかったファイル転送

TRAMP は Emacs エディタ上で動く sshコマンドのフロントエンドで、 Emacs 上の dired コマンドに似たインターフェイスを用いて サーバ上のファイルを直接編集することができます。

TRAMP は、GNU TRAMP のページ [脚注: http://www.gnu.org/software/tramp/] から入手できます。Emacs がデフォルトで参照するディレクトリに 正しくインストールすると、Emacs の起動と同時に TRAMP が 使用可能になっているはずです。TRAMP では リモートホストと通信するのにいくつかの異なる方法を選べますが、 最新版ではデフォルトで "ssh" が選択されています。 したがって、公開鍵認証 (あるいはパスワード認証) をおこなう準備が できてさえいれば、Emacs の C-x C-f (find-file) コマンドで

Find file: /ユーザ名@ホスト名:パス名
のようなパス名を開くことでリモートホスト上のファイルを直接編集できます。
TRAMP の実行画面
 /ssh:yusuke@server.example.com:/home/yusuke/tex:
 total 192
 drwxr-xr-x    2 yusuke   users      4096 Dec 16 17:31 .
 drwxr-xr-x    7 yusuke   users      4096 Mar  6 17:00 ..
 -rw-r--r--    1 yusuke   users       816 May 23  2005 init.tex
 -rw-r--r--    1 yusuke   users       431 Sep 29  2004 wide.sty
 -rw-r--r--    1 yusuke   users    155290 Dec 16 17:31 yusuke.bib




--EE:%%-F1  tex   01:58   (Dired by name)--L5--C58--All---------------------
Reading directory /ssh:yusuke@server.example.com:/home/yusuke/tex/...done

TRAMP は一度設定してしまえば大変便利なのですが、 sshコマンドを呼び出してリモートのシェルに対話的に コマンドを送信しているため、安定性の面でやや問題があります。 また、TRAMP は Emacs が起動しているあいだ ssh を つなぎっぱなしにするため、セキュリティ的にも疑問が残ります。 OpenSSH を使い慣れたユーザが頻繁にファイル転送を行うときのみ使用するのがよいでしょう。
注意: TRAMP が動かない場合は
リモートホストのシェルプロンプトの設定によっては、 TRAMP はうまく動かないことがあります。筆者の環境では、以下のような設定を .emacsファイルに書く必要がありました。
(custom-set-default tramp-methods
  '(("ssh" 
     (tramp-login-program "ssh")
     (tramp-copy-program nil) 
     (tramp-remote-sh "/bin/sh") 
     (tramp-login-args (("%h") ("-e" "none") ("-t") ("/bin/sh")))
     (tramp-copy-args nil) 
     (tramp-copy-keep-date-arg nil)
     (tramp-password-end-of-line nil))))

4.4. 認証エージェントを使う

4.4.1. 認証エージェントを使ったログイン

これまで説明してきた公開鍵認証を使ったログインでは、 ログインのたびに秘密鍵を復元するためのパスフレーズを入力する必要がありました。 しかし、いろいろなホストに繰り返しログインしなければならないような状況では、 パスフレーズの入力がユーザの負担となってしまいます。公開鍵認証を使うことの大きなメリットのひとつに、 ユーザが認証エージェント (authentication agent) を使って、 パスフレーズ入力を省略できることがあげられます。

認証エージェント (3.3.3. 認証エージェントを使った認証 参照) とはユーザにかわって認証を行ってくれるプログラムのことで、 その本体は、ssh クライアントとは別個に起動する ssh-agent と呼ばれるプログラムです。 これは OpenSSH のパッケージに含まれており、 その他のプログラムとともに自動的にインストールされます。

まずは使ってみることにしましょう。 ユーザは ssh コマンドの実行に先立って あらかじめ ssh-agent を起動しておき、 パスフレーズを入力して復元した秘密鍵を登録します。 ssh-agent を起動するには 2通りのやり方がありますが、 ここでは ssh-agent の子プロセスとしてシェルを起動する方法を紹介します。 (tcshを使っている方は、以下の例で ssh-agent bash と実行するかわりに ssh-agent tcsh と実行してください。)
注意
本書では ssh-agent を引数なしで起動することはおすすめしません。 引数なしで ssh-agent を起動した場合、これはまったく異なる動きをします。 引数なしで ssh-agent を起動してしまった場合は、 ps コマンドで ssh-agent のプロセス ID を確認し killしてください。 詳しくは 4.4.4. 認証エージェントを使う際の注意 を参照してください。
認証エージェントを起動する
(bash を使っている場合)
$ ssh-agent bash

(tcsh を使っている場合)
$ ssh-agent tcsh  

実行例:

client$ ssh-agent bash                   (認証エージェントを起動する)
(以後、子プロセスのシェル)

ssh-agent は引数として渡されたコマンド名を子プロセスとして実行します。 ここではまず ssh-agent コマンドの子プロセスとして、 さらにシェルを起動させています。

client$ ps                               (プロセス一覧を見る)
  PID TTY      STAT   TIME COMMAND
14928 pts/7    S      0:00 -bash
15016 pts/7    S      0:00 bash                       (子プロセスのシェル)
15017 ?        S      0:00 ssh-agent bash
15026 pts/7    R      0:00 ps x

では次に ssh-add コマンドを使って秘密鍵を登録します。
認証エージェントに秘密鍵を追加する
$ ssh-add [秘密鍵ファイル]  

実行例:

client$ ssh-add                                        (認証エージェントに秘密鍵を追加する)
Enter passphrase for /home/yusuke/.ssh/id_rsa:         (秘密鍵のパスフレーズを入力する)
Identity added: /home/yusuke/.ssh/id_rsa (/home/yusuke/.ssh/id_rsa)

ssh-add コマンドは親プロセスである ssh-agent と通信し、 パスフレーズの入力によって復元された秘密鍵を ssh-agentプロセスのメモリ上に登録します。 鍵が登録されているかどうかは、ssh-add -l を実行することにより確認できます。
認証エージェントが保持している鍵を確認する
$ ssh-add -l  

実行例:

client$ ssh-add -l                                     (認証エージェントの持っている鍵の一覧を表示する)
2048 23:56:6e:90:f3:98:fc:7b:2a:92:fb:46:bf:20:98:71 /home/yusuke/.ssh/id_rsa (RSA) (鍵の指紋が表示される)

こうすることにより、これ以後 パスフレーズを入力しなくても sshコマンドで サーバにログインできるようになります。

client$ ssh server.example.com                         (サーバにログインする)
Last login: Mon Mar 15 08:47:11 2006 from xx.xx.xx.xx  (パスフレーズの入力は要求されない)
server$

ひとたび秘密鍵を登録してしまえば、パスフレーズの入力なしで、 同一のサーバに繰り返しログインできるはずです:

...
server$ logout                                         (サーバからログアウトする)
Connection server.example.com closed.

client$ sftp server.example.com                         (ふたたび SFTP でログインする)
Connecting server.example.com...                         (パスフレーズの入力は要求されない)
sftp>

最後に、サーバへのログインが必要なくなったら、exit を入力して このシェルを終了します。すると同時に ssh-agent も終了し、 メモリ上の秘密鍵は失われます:

client$ exit                                           (子プロセスを終了する)
(元のプロセスのシェルに戻る)
client$ ps                                             (プロセス一覧を見る)
  PID TTY      STAT   TIME COMMAND
14928 pts/7    S      0:00 -bash
15821 pts/7    R      0:00 ps x
client$ ssh-add -l                                     (認証エージェントの持っている鍵の一覧を表示する)
Could not open a connection to your authentication agent. (認証エージェントと通信できない)

まとめると、認証エージェントを使う手順は以下のようになります:

  1. すべての ssh コマンドの実行に先だって、ssh-agent を起動する。
  2. ssh-add コマンドを実行してパスフレーズを入力し、ssh-agentプロセスに秘密鍵を登録する。
  3. ssh コマンドを実行してサーバにログインする。(パスフレーズは要求されない)
  4. すべての ssh コマンドの実行が終わったあと、ssh-agent プロセスを終了する。
    [脚注: ssh-agent が必要とされるのは認証の時だけなので、 実際には最後の認証を終えてしまったら、あとは ssh を終了するまえに ssh-agent を終了してもかまいません。]

4.4.2. 認証エージェントの動作

認証エージェントを使う場合、3つのプログラム (ssh, ssh-agent および ssh-add) が 協調して動作するため、そのしくみはやや複雑です。 UNIX では伝統的に「あるコマンドは、ひとつの仕事だけを実行して終了する」という 考え方が一般的です。sshコマンドもこの考え方に沿って設計されています。 そのため ssh コマンドが秘密鍵を扱う場合は、毎回ユーザが パスフレーズを入力してディスク上の暗号化された秘密鍵を復元してやらねばならず、 ssh が終了すると復元された鍵は失われてしまいます。

ssh-agent はこの問題を解決するため、 ssh コマンドとは別のプロセスとして起動し、 ssh と通信するという方法を採用しています。 これは個人用のデーモンプロセスのようにふるまい、 通常すべての sshコマンドが実行される前に起動され、 すべてのユーザ認証が終わるまで走りつづけることになります (図 timeline-ssh-agent)。


図 timeline-ssh-agent. sshssh-agent

サーバが「秘密鍵の所有を証明せよ」と要求してきたとき、 ssh コマンドは、最初に認証エージェントと通信しようと試みます。 認証エージェントがその秘密鍵を保持していれば、 ssh コマンドはユーザにパスフレーズの入力を求めることなく、 認証エージェントにサーバからの要求 (チャレンジ) を中継します。 認証エージェントは秘密鍵をつかって、それを所有していることの証明 (レスポンス) を生成し、ssh コマンドを経由してサーバに送信します。 ssh-agent は秘密鍵を一度使用したあとも破壊せずメモリ中に 保持しつづけるので、サーバからのチャレンジに何度でも応えることができます。 こうしてユーザはパスフレーズを一度入力するだけで サーバに繰り返しログインできるというわけです。

OpenSSH では、ssh-agentssh との通信に UNIX ドメインソケットを使っています。UNIX ドメインソケットは同一ホスト上で動いている プロセス同士が通信するための機構で、ファイルシステム上では あたかも読み書きできるファイルのようにふるまいます。 OpenSSH では、このソケットのパス名は SSH_AUTH_SOCK という 環境変数に格納されると決められています。 したがって、現在認証エージェントが使用可能かどうかは 環境変数 SSH_AUTH_SOCK を調べることでも判定できます。

client$ echo $SSH_AUTH_SOCK        (SSH_AUTH_SOCK の値を確認する)
                                   (中身は空)
client$ ssh-agent bash             (認証エージェントを起動する)
(以下、子プロセスのシェル) client$ echo $SSH_AUTH_SOCK (SSH_AUTH_SOCK の値を確認する) /tmp/ssh-EWMhQ17474/agent.17474 (通信用ソケットのパス名が入っている) client$ ls -l $SSH_AUTH_SOCK (通信用ソケットの実体を確認する) srw------- 1 yusuke users 0 Mar 18 17:07 /tmp/ssh-EWMhQ17474/agent.17474 client$ exit (認証エージェントを終了する)
(親プロセスのシェルに戻る) client$ echo $SSH_AUTH_SOCK (SSH_AUTH_SOCK の値を確認する) (ふたたび中身は空) client$ ls -l /tmp/ssh-EWMhQ17474/agent.17474 ls: /tmp/ssh-EWMhQ17474/agent.17474: No such file or directory (通信用ソケットは削除されている)

ssh を起動したとき、ssh はまずこの SSH_AUTH_SOCK という環境変数が設定されているかどうかを調べ、 設定されている場合はここで指定されている通信用ソケットを使って、 ssh-agent との通信をこころみます。ssh-agent が存在している場合、 ssh はサーバからの認証要求をすべて ssh-agent に中継します。 また認証エージェントに秘密鍵を登録する ssh-add も 同じ UNIXドメインソケットを使って ssh-agent と通信し、 ssh-agentプロセスが保持している秘密鍵の追加や削除を行います (図 interaction-ssh-agent)。


図 interaction-ssh-agent. 各コマンドの連携

認証エージェントをつねに子プロセスから使わなければならないのは、 この環境変数 SSH_AUTH_SOCK の内容を sshコマンドや ssh-addコマンドに伝える必要があるためです。 UNIX では、あるプロセスの環境変数を他のプロセスから操作できません。 ただし、新しいプロセスを親プロセスから起動するときだけは環境変数を「継承する」ことができます。 そのため ssh-agent は認証エージェントを使うプロセスを子プロセスとして起動し、 SSH_AUTH_SOCK 環境変数を継承するようになっています (図 inherit-env-with-ssh-agent)。


図 inherit-env-with-ssh-agent. SSH_AUTH_SOCK を子プロセスに継承する

4.4.3. 認証エージェントを転送する

認証エージェントには、 ユーザがあるサーバを経由してさらに別のサーバにログインするときに、 現在使っている認証エージェントを「転送」できるという機能があります。 あるサーバからさらに別のサーバへログインしなければならない場合を 考えてみましょう (図 multiple-login)。


図 multiple-login. あるサーバから別のサーバへログインする

サーバ 2 にログインするには、 サーバ 1 上の ssh コマンドで公開鍵認証を行わなくてはなりません。 しかしこのためにはサーバ 1 上に秘密鍵の入った id_rsa ファイルを 置く必要がありますし、ネットワーク経由でこの秘密鍵を復元するためのパスフレーズを入力する必要があります。 このような場合、認証エージェントの転送機能を使うと、 サーバ 2 にログインするときも、クライアントの認証エージェントが保持する秘密鍵を 使うことができます。
認証エージェントの転送を許可してログインする
$ ssh -A [ユーザ名@]ホスト名

実行例:

client$ ssh-agent bash                           (認証エージェントを起動する)
...
client$ ssh -A yusuke@server1.example.com        (エージェントの転送を許可してサーバにログイン)
Last login: Mon Mar 15 08:47:11 2006 from xx.xx.xx.xx  (パスフレーズの入力は要求されない)
server1$ ssh yusuke@server2.example.com          (さらにべつのサーバにログインする)
Last login: Mon Mar 04 17:21:09 2006 from xx.xx.xx.xx  (パスフレーズの入力は要求されない)
server2$ 

ssh コマンドに -Aオプションをつけると、 クライアントはローカルで動いている認証エージェントの情報をサーバ 1 に通知し、 サーバ 1 上の sshd デーモンが認証エージェントとしても機能するようになります。 この状態でさらにサーバ 2 へのログインを試みると、 サーバ 2 による認証の要求はサーバ 1 の sshsshd を経由してクライアントの ssh に中継され、 さらにそこから ssh-agent へと中継されることになります (図 relaying-authentication-agent)。


図 relaying-authentication-agent. 認証エージェントの転送

サーバ 1 にログインした後で環境変数 SSH_AUTH_SOCK の値を確認してみると、 クライアントの SSH_AUTH_SOCK とは別の値が入っていることに気づくでしょう。 この通信用ソケットはサーバ 1 上で動いている sshd が用意したもので、このデーモンが クライアントの認証エージェントの機能を「転送」していることを示しています。

client$ ssh-agent bash                           (認証エージェントを起動する)
client$ echo $SSH_AUTH_SOCK                      (SSH_AUTH_SOCK の値を確認する)
/tmp/ssh-EWMhQ17474/agent.17474
client$ ssh -A yusuke@server1.example.com
Last login: Mon Mar 15 08:47:11 2006 from xx.xx.xx.xx
server1$ echo $SSH_AUTH_SOCK                     (SSH_AUTH_SOCK の値を確認する)
/tmp/ssh-mgdxeOv740/agent.740                                     (別のパス名が入っている)

4.4.4. 認証エージェントを使う際の注意

認証エージェントは便利ですが、以下のような点に注意してください。

信頼できるマシン上でのみ動かす

認証エージェントは「信頼できるマシン」でのみ使用されることを前提にしています。 これはリモートのサーバに認証エージェントを転送したときにもあてはまります。 UNIX ドメインソケットを用いた ssh-agent プロセスと ssh プロセスの通信は 暗号化されていないため、もしそのユーザ以外のプロセスが この通信用ソケットにアクセスできると、そのプロセスは 簡単にそのユーザになりすますことができてしまいます。 [脚注: ただし ssh-agent は秘密鍵そのものを相手に渡すわけではないので、 プロセスのメモリ空間に直にアクセスしないかぎり、復元された状態の秘密鍵が 盗まれることはありません。] 同様に、リモートのサーバ上に転送された認証エージェント (実体は sshd プロセス) と ssh プロセスの通信も暗号化されていません。 通常、認証エージェントは通信用ソケットのパーミッションを そのユーザのみがアクセス可能なように設定しますが、root 権限で動いているプロセスは このパーミッションを無視できます。 したがって、認証エージェントを使うマシン、および転送をになうサーバはその管理者を含め、 十分に信頼できる必要があります。

「秘密鍵の置きっぱなし」に注意する

デフォルトでは、ssh-agent は 一度復元した秘密鍵を終了するまで保持しつづけます。 これは実のところ危険です。あるクライアントを長時間使いつづけている場合、 ssh-agent を立ちあげたまま放置しておくことは、 サーバにログインしたままで長時間席を離れるのと同じ危険がともないます。 このため ssh-add には認証エージェントが保持する 秘密鍵の生存時間を指定する機能があります。
生存時間を指定して秘密鍵を追加する
$ ssh-add -t 秒数 [秘密鍵ファイル]  

実行例:

$ ssh-add -t 3600                 (1時間だけ有効な秘密鍵を認証エージェントに追加する)

この方法で追加された秘密鍵は、指定された時間が経過すると自動的に 認証エージェントによってメモリ中から消去されます。同じ秘密鍵をふたたび使用したい場合には 再度 ssh-add コマンドでパスフレーズを入力しなければなりません。 なお、-t オプションをつけない場合、秘密鍵の生存時間は ssh-agent 起動時に指定された値になります。 デフォルトではこの値は無限大 (ssh-agent が終了するまで保持しつづける) になっています。 秘密鍵の生存時間を指定した安全な認証エージェントの使い方については 5.1.3. 認証エージェントの使用を支援する を参照してください。

また、以下のように ssh-add -D コマンドを実行することで 認証エージェントに登録されている鍵をいったんすべて削除することができます。
認証エージェントの鍵をすべて削除する
$ ssh-add -D  

実行例:

client$ ssh-add -l                                     (認証エージェントの持っている鍵の一覧を表示する)
2048 23:56:6e:90:f3:98:fc:7b:2a:92:fb:46:bf:20:98:71 /home/yusuke/.ssh/id_rsa (RSA)
client$ ssh-add -D                                     (認証エージェントの鍵をすべて削除する)
All identities removed.
client$ ssh-add -l
The agent has no identities.                                     (鍵は削除された)

認証エージェントの起動方法に注意する

ssh-agent にはもうひとつ別の起動方法があります。 ssh-agent を引数なしで実行すると、ssh-agent は子プロセスのシェルを起動せず、 ssh-agent を実行したシェルと並列にバックグラウンドで走ります。 このとき ssh-agent は標準出力に 環境変数 SSH_AUTH_SOCK を設定するシェルのコマンド列を出力します。 シェルはこのコマンド列を eval により実行することで通信用ソケットの位置を 獲得します。この方法は本書ではおすすめしません。 なぜなら子プロセスを使った方法よりもわかりにくいうえに、 認証エージェントを終了し忘れる可能性があるからです。 認証エージェントに子プロセスのシェルを起動させるようにすれば、 このシェルを終了したときに確実に認証エージェントも終了します。 しかし、それでも ssh-agent を手動で起動すると、 うっかり引数なしで起動してしまうミスを犯してしまうかもしれません。 そのため本書では、ログイン時に自動的に認証エージェントが起動されるように あらかじめ管理者がクライアントを設定しておくことをおすすめします。 この方法については ユーザがログインした瞬間から ssh-agent を走らせる を参照してください。

4.5. X11 転送を使う

OpenSSH を使うとリモートホスト上で通常の端末ベースのアプリケーションに加えて、 X11 による画面描画をおこなうアプリケーション (X クライアント) を 実行することができます。

UNIX で伝統的に使われている画面描画システムである X Window System (X11) は、画面の描画をクライアント・サーバモデルでおこなっています。 通常ローカルホスト上で xtermfirefox などの X11 アプリケーションを実行すると、これらのプログラムは 別に走っている X サーバプロセスと通信して画面制御を行います。 ここで実際に画面描画を行っているのは X サーバプロセスで、 X11 アプリケーションはこのプロセスに描画を要求するクライアントです。 このとき、Xサーバと通信するためのネットワークソケットの位置は環境変数 DISPLAY に 格納されると取り決められており、各 X11 アプリケーションは環境変数 DISPLAY の 値をもとに Xサーバと通信します (図 xserver-local)。


図 xserver-local. ローカルホスト上の Xサーバ と Xクライアント

従来の X Window System では、ユーザがリモートホストにログインした際、 外部のホストからローカルな Xサーバの通信用ソケットにアクセスすることを許していました (図 xerver-danger)。しかしこの通信は暗号化されていなかったため、 X クライアントが画面に表示した内容や、ユーザからのキーボード入力が ネットワーク上の第三者に盗聴されてしまうという危険性がありました。 また、この状態では第三者が通信内容に手を加え、 ユーザのマシンにアクセスすることも可能です。


図 xserver-danger. リモートホストとローカルな Xサーバとの暗号化されていない通信 (危険)

OpenSSH では、通常の文字ベース (端末ベース) の通信に加えて、 リモートホストとローカルな X サーバの間の通信も暗号化することができます。 OpenSSH はサーバとクライアント間で複数の情報を同時に送受信できるように設計されており、 文字ベースの情報だけでなく X11 の通信や、その他の TCP 通信なども 暗号化することが可能です。 [脚注: TCP 通信の暗号化 (ポート転送) については 6.2. ポート転送 を参照してください。] 具体的にはユーザがログインしたサーバ上の sshd デーモンが 擬似 Xサーバとしてふるまい、リモートホスト上の Xクライアントの要求を ローカルな Xサーバに中継します (図 xserver-forwarding)。 これを X11 転送 (X11 forwarding) と呼びます。 この間もリモートホスト上で実行されている通常のシェルとの 端末ベースの通信も同時並列的に行われます。


図 xserver-forwarding. OpenSSH による X11 通信の暗号化

OpenSSH で X11 転送を使うには、まずサーバ側の sshd の設定を変更する必要があります。 OpenSSH のデフォルトの設定では X11 転送は禁止されているため、 ユーザが X11 転送を使うためには、まずシステム管理者が サーバ上の sshd_config設定ファイルを以下のように 修正します。 [脚注: sshdサーバデーモンの設定を変える詳しい方法については 5.2. sshd を安全に設定する を参照してください。]
X11 転送を許可する
sshd_config設定ファイル:
X11Forwarding yes

この後、クライアントから X11転送を使うには sshコマンドで ログインするときに -Xオプションを指定します。 現在のところこの指定はログイン時に行う必要があり、 ログインしたあとで設定を変えることはできません。
X11 転送を許可してログインする
$ ssh -X [ユーザ名@]ホスト名

実行例:

client$ ssh -X yusuke@server.example.com               (X11転送を許可してログインする)
Enter passphrase for key '/home/yusuke/.ssh/id_rsa':
Last login: Mon Mar 24 18:00:09 2006 from xx.xx.xx.xx
server$ xterm &                                    (サーバ上で xterm を起動する)
[1] 4454
server$

X11 転送をしている間はクライアント上の ssh コマンドが ローカルな X サーバにとっての実質的なクライアントとなります。 したがって、X11 転送を行うにはローカルマシン上で ssh コマンドを 実行するときに環境変数 DISPLAY の値が正しく設定されている必要があります。 通常、ローカルな xterm ウィンドウの中などから ssh を実行した場合、 環境変数 DISPLAY はすでに正しく設定されているので、 特別な操作は必要ありません。 なお、この環境変数 DISPLAY はログインしたサーバ上では 異なる値に設定されています。以下の例でサーバ上の DISPLAY に格納されている localhost:10.0 という値は、 サーバ上の sshd プロセスが設置した擬似 Xサーバの通信用ソケットです。 この値はサーバにログインした時に自動的に設定されます。 また、リモートで走っている X11 アプリケーションは通常どおり 環境変数 DISPLAY の値をたよりに Xサーバと通信するので、 これによってリモートホスト上のアプリケーションは何も意識することなく、 暗号化された通信を使用できるわけです。

client$ echo $DISPLAY                                  (環境変数 DISPLAY の値を確認する)
:0.0
client$ ssh -X yusuke@server.example.com
Enter passphrase for key '/home/yusuke/.ssh/id_rsa':
Last login: Mon Mar 24 18:02:11 2006 from xx.xx.xx.xx
server$ echo $DISPLAY                                  (環境変数 DISPLAY の値を確認する)
localhost:10.0

なお、X11転送を使ってバックグラウンドで X11 アプリケーションを 走らせている場合は、たとえリモートホストのシェルからログアウトした後も、 すべての X11 アプリケーションが終了するまで ssh は 走りつづけることに注意してください。これは ssh が 依然として X11 アプリケーションによる通信を転送する必要があるためです。 このような場合は、エスケープシーケンス (4.1.3. 公開鍵認証でログインする 参照) を使うことで、 ログアウト後に X11転送を続けている ssh プロセスを バックグラウンド化することができます。

実行例:

client$ ssh -X yusuke@server.example.com
Enter passphrase for key '/home/yusuke/.ssh/id_rsa':
Last login: Mon Mar 24 18:00:09 2006 from xx.xx.xx.xx
server$ xterm &
[1] 4454
server$ exit
logout                                          (サーバ上で実行した xterm が終了するまで待っている)
(ここで ~& を入力する)
~& [backgrounded]                                (ssh がバックグラウンド化された)
client$

X11転送を使ううえでの注意

OpenSSH のデフォルトの設定で X11 転送が禁止されているのには 理由があります。認証エージェントの転送 (4.4.4. 認証エージェントを使う際の注意 参照) と同じように、 X11 の転送はログインしたサーバが信頼できない場合には悪用される危険があるからです。 たとえば、通常は環境変数 DISPLAY で指定されている 通信用ソケットにはログインしたユーザ以外がアクセスすることはできませんが、 リモートマシン上で root 権限をもっているプロセスならアクセスできます。 X11 の描画要求の中には同じ画面上に表示されている別のウィンドウにアクセスする機能もあるので、 リモートマシン上で X11 転送が悪用されると、ユーザの画面上にある別のウィンドウの 内容が盗み見られてあり、ウィンドウの勝手な文字が入力されたりする危険があります。

このため OpenSSH ではサーバからクライアントに転送される X11 描画要求のうち、 危険なものをあらかじめ禁止しています。具体的には、サーバ上のプロセスが所有していない ウィンドウの中身を見ることや、xrdb などのコマンドで Xサーバのリソースデータベースの内容を改変することなどです。 これらの X11 要求を禁止することで悪用の被害は最小限に抑えることができますが、 ウィンドウ内容をダンプする xwdxmag などの プログラムは正しく動きません。

client$ ssh -X yusuke@server.example.com
Enter passphrase for key '/home/yusuke/.ssh/id_rsa':
Last login: Mon Mar 24 18:02:11 2006 from xx.xx.xx.xx
server$ xwd
X Error of failed request:  BadWindow (invalid Window parameter)
  Major opcode of failed request:  3 (X_GetWindowAttributes)
  Resource id in failed request:  0xc0000d
  Serial number of failed request:  46
  Current serial number in output stream:  47
server$

このような現象を回避するために OpenSSH では「信頼された X11 転送」 (Trusted X11 Forwarding) の機能も用意されています。 信頼された X11 転送では、危険な描画要求をふくむ X11 のすべての通信が 転送されます。sshコマンドに -Y オプションを 与えることにで信頼された X11 転送をつかったログインが可能ですが、 このオプションを使うのは、サーバが管理者を含めて十分に信頼できる時のみにしてください。
信頼された X11 転送を許可してログインする
$ ssh -Y [ユーザ名@]ホスト名

4.6. UNIX 以外のマシンからログインする

この節では Windows や Mac OS X 上で、OpenSSH 以外の SSH クライアントを 使う方法を説明します。なお Windows 上の擬似 UNIX 環境である Cygwin には OpenSSH の sshコマンドが含まれているため、ユーザはこれまで紹介した通りの方法で sshコマンドや認証エージェントを使えます。

4.6.1. Windows 上で PuTTY を使用する

PuTTY は Windows 上で広く使われている SSH クライアントです。 軽量かつ小型であり、フロッピーディスク一枚に入るサイズであることから、 なにかの都合で Windows マシンを使わなければならい事態となっても容易に使うことができます。 また、日本語の表示・入力を可能にするパッチも用意されています。

PuTTY の入手

PuTTY は公式配布サイト [脚注: http://www.chiark.greenend.org.uk/~sgtatham/putty/]、 あるいは日本語パッチの配布サイト [脚注: http://hp.vector.co.jp/authors/VA024651/#PuTTYkj_top] からダウンロードできます。 公式配布サイトからは補助ツールもダウンロードできるので、 putty.exe (クライアント) のほかに、 puttygen.exe (秘密鍵と公開鍵の生成・変換ツール) と pageant.exe (認証エージェント) もダウンロードしておくとよいでしょう。 また、この puttygen.exe は後述する WinSCP を使用するときにも必要になります。

秘密鍵・公開鍵ペアを作成する

OpenSSH クライアントと同じく、PuTTY でも公開鍵認証が使用できます。 補助ツールである puttygen.exe を使うと、 秘密鍵と公開鍵のペアを生成できます。PuTTY で秘密鍵を生成すると、 これは .ppk という拡張子で保存されます。

この .ppk という秘密鍵の形式は OpenSSH の id_rsa で使われている形式とは互換性がないため、 OpenSSH の ssh-keygen で作成した秘密鍵を PuTTY で使用するには、あらかじめ puttygen.exe を使って .ppk 形式に変換しておく必要があります。 まず puttygen.exe を起動し、"Conversions" メニューから "Import Key..." を選択します。秘密鍵ファイルを選んでパスフレーズを入力すると 図 puttygen のように秘密鍵に関する情報が表示されます。 この後 "Save Private Key" ボタンを押して .ppk 形式を 保存してください。


図 puttygen. puttygen.exe で OpenSSH の秘密鍵を変換する

ログインする

PuTTY を実行すると、最初に図 putty-session. のような ウインドウが表示されます。ここに接続先のホスト名とポート番号を入力して 「Open」ボタンを押すと、黒い端末ウィンドウが現われ、ユーザ名と パスワード (あるいはパスフレーズ) の入力が促されます。


図 putty-session. PuTTY のログイン・ウインドウ

公開鍵認証をおこなう場合は、左側の Category: から 「Connection - SSH - Auth」という項目を選び、Private key file for authentication: に対して、 .ppk形式の秘密鍵ファイルへのパス名を指定します (図 putty-pubkey)。 この後「Open」ボタンを押し、端末ウィンドウ中でパスフレーズを入力すると 公開鍵認証がおこなわれます。


図 putty-pubkey. 秘密鍵ファイル (.ppk形式) を指定する

なお、OpenSSH と同じように、あるホストにはじめて 接続した場合はホスト公開鍵が不明であるとの警告が表示されます (図 putty-warning)。ここで「Yes」を押すとそのホスト公開鍵が Windows のレジストリに追加され、「Cancel」を押すと接続を拒否します。 「No」を押した場合はホスト公開鍵をレジストリに追加せずに接続を続行します。 パスワード認証を使う場合は必ずホスト公開鍵の指紋を確認したうえでログインするようにしてください (3.2.1. ホスト認証はなぜ必要か 参照)。


図 putty-warning. PuTTY のホスト認証画面

認証エージェントを使う

PuTTY でも認証エージェントがサポートされています。 使い方は簡単です。putty.exe と同じフォルダ内に pageant.exe を置いておき、putty.exe を起動する前にこれを実行するだけです。 pageant.exe を実行すると画面右下のタスクトレイにアイコンが表示されます。 あとはこのアイコンを右クリックして表示されるメニューから「Add Key」を選択し、 秘密鍵ファイル (.ppk形式) を追加してください。 この後メニューから「New Session」を選択すると putty.exe が起動され、ログインの際に 自動的に認証エージェントと通信し公開鍵認証を行うようになります。


図 pageant. pageant.exe の画面

4.6.2. Windows 上で WinSCP を使用する

WinSCP [脚注: http://www.winscp.org/] は Windows 上で動く SFTP クライアントで、 エクスプローラ風の直観的なインターフェイスを備えています。 公開鍵認証には PuTTY の秘密鍵と同じ .ppk 形式の秘密鍵ファイルを使用するため、 シェルの使用は PuTTY で行い、ファイル転送は WinSCP を併用するといった 使い方に向いています。

WinSCP のログイン画面は PuTTY に似ています (図 winscp-login)。 ここでホスト名とポート番号およびユーザ名を入力したあと、 秘密鍵ファイルを指定して「Login」を押します。 パスフレーズが正しく入力されるとリモートのディレクトリが表示されます (図 winscp-file)。


図 winscp-login. WinSCP のログイン・ウインドウ

図 winscp-file. WinSCP を使用しているところ

4.6.3. Mac OS X 上で Fugu を使用する

Fugu[脚注: http://rsug.itd.umich.edu/software/fugu/] は Mac OS X 上で動くファイル転送クライアントです。 これは内部で OpenSSH の sftp プログラムを使用しており、 OpenSSH の秘密鍵ファイルやオプションなどもそのまま使えます。 また、ポート転送をおこなう機能もあります。


図 fugu. Fugu の画面

Fugu における認証方法は OpenSSH とまったく同じです。 公開鍵認証を使う場合は、あらかじめ OpenSSH の ssh-keygen コマンドで id_rsa ファイル (あるいは id_dsa ファイル) を作成し、 ホームディレクトリの ~/.ssh/ 以下に置いておきます。 なお、Mac OS X では秘密鍵・公開鍵ペアを生成したり、 秘密鍵のパスフレーズを変更するのに SSH Agent という グラフィカルなツールを使うこともできます (これも内部で OpenSSH を使っています)。 [脚注: http://www.phil.uu.nl/~xges/ssh/ ]

サーバに接続したあとは、Finder のウィンドウと同様に ドラッグ & ドロップでファイルを転送することができます。

4.7. 個人用の設定ファイルでさらに快適に

ssh コマンドにはさまざまなオプションがありますが、 これらを毎回いちいち指定するのは面倒です。 また、環境によっては異なるホストで別々のポート番号や 秘密鍵ファイルを使用しなければならないことがあり、 これらをすべて覚えておくことはユーザにとって負担です。 そのため OpenSSH では各ユーザが ホスト名ごとに異なるオプションを記録する設定ファイルを作成することができます。 ssh コマンドは与えられたホスト名によって これらの設定を自動的に読み込み使用します。

4.7.1. 個人用設定のつくりかた

ssh コマンドの個人用設定は クライアント上の ~/.ssh/config というファイルに記録することが 決められています。~/.ssh/config はテキストファイルであり、 以下に示すような形式になっています。
~/.ssh/config ファイルの例
# univ. lab
Host server.example.com
    Port 1729
    ForwardX11 yes

# my home server
Host myhome
    HostName homeserver.example.net
    IdentityFile ~/.ssh/id_rsa_home
    User euske

# common settings
Host *
Compression yes

これは一般的なテキストエディタを使って変更します。 上の例を使うと、たとえば以下のようにタイプするだけで、 ユーザは斜体で書かれているコマンドと同等の結果を得られることになります。

実行例:

client$ ssh server.example.com(ssh -p 1729 -X yusuke@server.example.com と同じ)
client$ ssh myhome(ssh -i ~/.ssh/id_rsa_home euske@homeserver.example.net と同じ)
client$ rsync -a myhome:/home/yusuke/data .(rsync が内部で呼びだす ssh にも同様のオプションが使われる)

~/.ssh/config ファイルが便利なのは、単純にホスト名ごとの 異なるオプションを指定できるだけでなく、ホスト名の「エイリアス」を指定できることです。 上の例では ssh myhome とタイプするだけで、実際には homeserver.example.net に接続でき、しかもログインするユーザ名まで指定できます。 さらにこのホスト名によるオプション指定は sftprsync を 使った場合でも有効です。 [脚注: これは sftprsync などのプログラムが 内部で ssh コマンドを呼び出しているためです。] このため複数のサーバにログインするような状況では、 多少時間をかけても ~/.ssh/config ファイルを作成することは 十分に価値があります。
注意
たとえホスト名のエイリアスを設定しても、OpenSSH 内部では エイリアスは本物のホスト名に置換されています。 そのため known_hosts ファイルでは ssh で入力した名前ではなく、 HostName 設定項目で指定した本物のホスト名が使われます。 とくにハッシュ化された known_hosts ファイル (5.8.2. known_hosts ファイルの内容をハッシュ化する 参照) を 使っているときは known_hosts ファイルに格納されている名前と ssh で入力した名前が異なるので注意が必要です。

4.7.2. ~/.ssh/config ファイルの文法

~/.ssh/config ファイルの各行には、 1行にひとつの設定項目を記述します。 '#' 以降はコメントとみなされます。 上の例では字下げは見やすさのためのものであり、実際には必要ありません。 各設定項目には "Host" を指定するか、あるいは 表 config-options. に示す項目のどれかを指定します。
表 config-options. よく使われる設定ファイルの項目
設定項目機能
Port ポート番号 接続するポート番号を指定する。(-p オプションに相当、4.1.3. 公開鍵認証でログインする 参照)
User ユーザ名 ログインするユーザ名を指定する。(user@host の user部分に相当)
HostName ホスト名 ログインするサーバのホスト名を指定する。(user@host の host部分に相当)
IdentityFile 秘密鍵ファイル名 公開鍵認証に使う秘密鍵ファイルを絶対パス名で指定する。 そのユーザのホームディレクトリを表すのには ~ が使える。 (-i オプションに相当、4.1.3. 公開鍵認証でログインする 参照)
ForwardAgent yes 認証エージェントの転送を許可する。(-A オプションに相当、4.4.3. 認証エージェントを転送する 参照)
ForwardX11 yes X11 転送を許可する。(-X オプションに相当、4.5. X11 転送を使う 参照)
ForwardX11Trusted yes 信頼された X11 転送を許可する。(-Y オプションに相当、4.5. X11 転送を使う 参照)
Ciphers 暗号化方式1,暗号化方式2,... 暗号化に使う方式を指定する。方式は複数個指定でき、最初に指定したものがもっとも優先して使われる。 なお、カンマの間にスペースを入れてはいけない。 [脚注: SSH1 プロトコルを使っている場合は Ciphers ではなく Cipher という項目であり、指定できる暗号化方式は 1種類のみです。]
Compression yes 圧縮を有効にする。
HostKeyAlias ホスト名 ホスト公開鍵を検証するとき、ユーザが指定した名前のかわりに このホスト名known_hosts ファイルを検索する。(6.4.2. ポートを変えて複数のホストにログインする 参照)
CheckHostIP no ホスト公開鍵を検証するとき、そのホスト名の IPアドレスで known_hosts ファイルを検索するのを禁止する。 (6.4.2. ポートを変えて複数のホストにログインする 参照)

Host 指定では、sshコマンドで指定する サーバのホスト名を指定します。すべてのホストを指定するワイルドカード (*) も 使用できます。~/.ssh/config ファイルは、先頭の行から順に 読み込まれていきます。ある Host 指定が現れると、 それ以降の設定項目はすべてその Host で指定された ホスト名のみに適用されます。Host 指定がまだ一度もファイル中に 現れていないときや、Host * が指定されているときは、 その設定項目はすべてのホスト名に対して適用されます。
Host指定の適用範囲
IdentityFile ~/.ssh/id_rsa_yusuke         ] すべてのホストに適用される
Protocol 2                                ]

# univ. lab
Host server.example.com
    Port 1729                             ] ホスト server.example.com に適用される
    ForwardX11 yes                        ]

# my home server
Host myhome
    HostName homeserver.example.net       ] ホスト myhome に適用される
    IdentityFile ~/.ssh/id_rsa_home       ]
    User euske                            ]

# common settings
Host *
Compression yes                           ] すべてのホストに適用される

なお、ssh コマンドではシステム全体にわたる 設定ファイルもサポートされています。OpenSSH の設定ファイル用ディレクトリ (/etc/ssh など) にある ssh_config設定ファイルには、 ssh コマンドのデフォルトの設定項目が記述されています。 このファイルは OpenSSH をインストールした状態ではすべて コメントアウトされていますが、~/.ssh/config ファイルで 指定されていない設定項目については ssh_config設定ファイルの値が使用されます。 また ssh-o オプションを 使うことで、これらの設定項目をコマンドラインからじかに指定することも可能です。
設定項目をコマンドラインから指定する
$ ssh [-o設定項目1=値1] [-o設定項目2=値2] ... [その他のオプション] ...

4.7.3. 設定を変えて OpenSSH を高速化する

なお、表 config-options. に挙げた設定項目のうち Ciphers 設定項目 と Compression 設定項目 をうまく使うと 遅いネットワーク接続での通信速度をやや向上させることができます。 具体的には Compression 設定項目で圧縮を許可し、 Ciphers 設定項目でなるべく高速な暗号化アルゴリズムを優先して 利用するようにします。 [脚注: 現在サポートされている暗号化アルゴリズムでは arcfour が一番速いようです。] なお、実際に圧縮が有効になるかどうかや、どの暗号化アルゴリズムが使われるかはサーバ側の 設定にも依存するため、クライアント側でこれらの設定を変更したからといって 必ずしもつねに通信が速くなるとはかぎりません。
注意
Ciphers 設定項目で設定する暗号化アルゴリズムの数は減らさないようにしてください。 相手の SSH サーバのバージョンによっては、blowfish や arcfour などの 暗号化アルゴリズムはサポートされていないことがあります。 その場合、Ciphers に使用可能な暗号化アルゴリズムが含まれていないと ssh コマンドは "no matching cipher found" という エラーを出して終了してしまいます。
高速な暗号化アルゴリズムと圧縮を使用する
Compression yes
Ciphers arcfour,blowfish-cbc,aes128-cbc,cast128-cbc,aes192-cbc,aes256-cbc,3des-cbc
コラム - OpenSSH を使ってもパスワードは推測される
どんなに OpenSSH で通信内容を暗号化したところで、 「通信をしている」という事実自体は隠すことができません。 とくにユーザがシェルを使う OpenSSH では、 TCP/IP パケットの流量からユーザのキーの打鍵間隔が 推測できてしまいます。また、OpenSSH のパスワード認証では 入力したパスワードは一度にサーバに送られますが、古いバージョンの SSH では、 「パスワードが 4文字以下の場合は 1パケットで送られるので、 それが 4文字以下であることが外部にバレてしまう」という欠陥がありました。

カリフォルニア大学バークレー校の Songらによる研究では、 たとえユーザが OpenSSH を使っていても、打鍵間隔の測定によって 実際にパスワードの推測範囲を大幅に狭められることがわかっています。 ユーザが OpenSSH でサーバにログインし、 そこで sudosu を使ったとします。 このときユーザが入力したパスワードはエコーバック (画面表示) されません。 したがって OpenSSH のパケットを観察すると、このときは 「行き (クライアント→サーバ)」のパケットのみが送信され、 「帰り (サーバ→クライアント)」のパケットは送信されないため、 これがパスワード入力であることがわかってしまうのです。 Song らは人間の指が異なるキーの間を動くのにかかる時間を計算し、 統計的な手法を使って打鍵間隔からパスワード文字列をある程度まで 推測することに成功しています。

このことを考えると、たとえ OpenSSH を使っていても、 ネットワークを経由したパスワード入力はなるべく避けたほうがよさそうです。

参考文献: Dawn Xiaodong Song, David Wagner and Xuqing Tian, "Timing Analysis of Keystrokes and Timing Attacks on SSH", USENIX Security Symposium, 2001.


Yusuke Shinyama