hack のためのネタ帳, etc,,,

Secure Shell のフリーな実装

公式ページ

参考になるページ等

Tips

パスワード入力のやり直し

C-u すれば良いらしい。
OpenSSH のドキュメントには見当たらない気がする。
READLINE(3) 見ると似たようなキーバーインドはあるけど kill-ring は関係してなさそう。
unix-line-discard (C-u)
       Kill backward from point to the  beginning  of  the  line.   The
       killed text is saved on the kill-ring.
良くあるキーバーインドに従ってるだけだろうか?
参考:

X11Forwarding できない場合のチェック項目

  • リモートの側の sshd_config で X11Forwarding は yes になっているか?
  • リモートの側に xauth がインストールされているか?

ローカル側の環境変数をリモート側へ自動送信する

例えば以下のような環境変数を自動で送っとくと便利である。
  • ローカル側と同じロケールで作業したい場合
    • LANG LC_*
  • X11Forwarding してるときにローカルの漢字変換を使いたい場合
    • XMODIFIERS

設定する箇所は次の通り。
ローカル側の /etc/ssh/ssh_conf に以下の項目がなければ追加
SendEnv LANG LC_*
SendEnv XMODIFIERS
リモート側の /etc/ssh/sshd_conf に以下の項目がなければ追加
AcceptEnv LANG LC_*
AcceptEnv XMODIFIERS
最後にリモート側の sshd を再起動

あと Debian で language-env 0.69 使って ~/.bashrc 設定してると
TERM=xterm の時 LANG=C で上書きされてるので以下の箇所を変更しとく必要がある。
*** .bashrc~	2011-02-09 11:01:09.000000000 +0900
--- .bashrc	2011-02-09 11:38:00.000000000 +0900
***************
*** 32,35 ****
      xterm)
        if [ "$COLORTERM" != "gnome-terminal" ] ; then
!         LANG=C
        fi ;;
--- 32,37 ----
      xterm)
        if [ "$COLORTERM" != "gnome-terminal" ] ; then
!         if [ "$LANG" = "" ] ; then
!           LANG=C
!         fi
        fi ;;
参考:

known_hosts の整理

セキュリティの向上のため、
最近の known_hosts ファイルには pkey と、一方向 hash 化された hostname の対応が記録さてている。
つまり、hostname から pkey を探すことは出来るが、pkey から hostname を探すことは出来ない。

既に不要な pkey かを判断するためには、以下の方法で hostname から pkey を総当たり的に検索するしかない。
ssh-keygen -lF $hostname -f ~/.ssh/known_hosts
オプションの意味は以下
  • -l : fingerprint で表示(付けなければ、pkey をそのまま表示する)
  • -F : 検索する hostname の指定
  • -f : known_host ファイルの指定
$hostname には
デフォルト port (=22) の場合、hostname をそのまま書く。
デフォルト以外の port (≠22) の場合、[hostname]:port のように書く。

特定のホストに関する鍵の削除は
ssh-keygen -R "hostname"

サーバーの pkey を調べる

known_hosts に記録されていないサーバーへ ssh した場合、以下のように警告が表示される。
$ ssh -p 1234 myserver
The authenticity of host '[myserver]:1234 ([127.0.0.1]:1234)' can't be established.
RSA key fingerprint is 00:01:02:03:04:05:06:07:08:09:0a:0b:0c:0d:0e:0f.
Are you sure you want to continue connecting (yes/no)? 
初回の接続で known_hosts にサーバーが登録されてない場合、サーバーの pkey から計算した fingerprint を事前調べておくことで、安全に ssh で接続できる。

各サーバーの pkey をネットワーク越しに調べるには ssh-keyscan コマンドを用いる。
ただし、ネットワーク越しに調べたのでは、なりすましが判別出来ないので、
事前にサーバー上で、サーバー自身の pkey を調べておく必要がある。
つまり、サーバー上で、自分自身の sshd に対して以下のように問合せを行なえば良い。
ssh-keyscan localhost

これは生の pkey なので、fingerprint を調べるには、以下のように ssh-keygen コマンドを通す。
ssh-keyscan localhost > /tmp/pkey
ssh-keygen -vlf /tmp/pkey
ssh-keygen のオプションの意味は以下
  • -v : verbose. -l オプション使用時に ASCII art 表現も併せて表示させたい場合に付ける。
  • -l : fingerprint の計算
  • -f : pkey ファイルの指定

ssh-keygen への pkey 入力がファイル限定(?)なので、上記のように一旦リダイレクトで、ファイルを経由させる必要がある。
名前付きパイプが使えそうなものだが、2011-09-18現在、Debian の openssh-client 1:5.8p1-7 だと、生のファイルじゃないと通らない。

2016-02-12:
OpenSSH 6.8/6.8p1 以降、鍵の fingerprint 生成アルゴリズムが md5 から sha256/base64 に変更になったとの事。
ssh-keygen では -E オプションでこのアルゴリズムを変更出来るらしい。
ssh には fingerprint 生成アルゴリズムの切替機能がないので、
手元に旧 fingerprint の情報しかない場合、一旦 ssh-keygen で新旧対照する必要がある。
簡易的にはこんな感じか?
ssh-keycomp () { ( local tmp=$(mktemp -u); trap "rm $tmp" 0; ssh-keyscan "$1" > $tmp; ssh-keygen -E md5 -lf $tmp; ssh-keygen -lf $tmp; ); }

参考:

known_hosts に記録を残さないで接続

メンテナンスやテストなどで一時的に立ち上げた ssh サーバーに頻繁に繋いていると、一時的な pkey が known_hosts へ記録されてゴミの山になる。
このように、永続的でない pkey を持つサーバーに接続する場面では、いちいち known_hosts に記録を残したくない。
方法は簡単で -o UserKnownHostsFile オプションを用いて適当に捨て場所を指定してやれば良い。
ssh -o UserKnownHostsFile=/dev/null 192.168.0.1
いきなり /dev/null へ捨てるのが不安なら一時ファイル(例えば /tmp/known_hosts 等)に出力しても良いかもしれない。
以下のように -y オプションを用いれば ~/.ssh/id_rsa.pub 相当のものが生成出来るらしい。
ssh-keygen -f ~/.ssh/id_rsa -y
参考:
base64 encode された鍵を base64 decode して md5sum を取ったものらしい。
以下のようにすると同じ fingerprint が出て来ることを確認出来る。
cat ~/.ssh/id_rsa.pub | awk '{print $2;}' | base64 -d | md5sum
ssh-keygen -l -f ~/.ssh/id_rsa.pub
参考:
~/.ssh 以下の SSH キーは
秘密鍵は PEM 形式なので OpenSSL でそのまま使えるのだが、
秘密鍵は OpenSSH の独自形式(?)(RFC4716 形式を1行に展開したような形式) になっているので、
そのままでは OpenSSL で処理出来ない。
このため ssh-keygen -e で PKCS8 形式に export する必要がある。
それぞれの形式に export するには、以下のようにすれば良い。
ssh-keygen -f ~/.ssh/id_rsa.pub -e -m PKCS8   > id_rsa.pub.PKCS8
ssh-keygen -f ~/.ssh/id_rsa.pub -e -m PEM     > id_rsa.pub.PEM     # これは OpenSSL では使えない???
ssh-keygen -f ~/.ssh/id_rsa.pub -e -m RFC4716 > id_rsa.pub.RFC4716 # これは OpenSSL では使えない
あとは以下のようにすれば RSA による暗号化と復号化が行える。
openssl rsautl -encrypt -inkey ~/.ssh/id_rsa           < file           > file.encrypted # RSA 秘密鍵に含まれる公開鍵による暗号化
openssl rsautl -encrypt -inkey id_rsa.pub.PEM   -pubin < file           > file.encrypted # RSA 公開鍵から PEM 形式で export した公開鍵による暗号化 (pubkey が上手く読めない模様)
openssl rsautl -encrypt -inkey id_rsa.pub.PKCS8 -pubin < file           > file.encrypted # RSA 公開鍵から PKCS8 形式で export した公開鍵による暗号化
openssl rsautl -decrypt -inkey ~/.ssh/id_rsa           < file.encrypted > file.decrypted # RSA 秘密鍵による復号化
公開鍵暗号なので、秘密鍵は相手に渡してはいけない。
従って、まず相手に何らかの方法で公開鍵を渡し、その公開鍵で暗号化してもらったものを、こちらで復号化するという使い方になる。
此方から相手に送る際は、何らかの方法で入手した相手の公開鍵で暗号化する必要がある。

公開鍵の受け渡しは、普通は man in middle で改竄されるところまで心配する必要はないはずなのでメールか web で渡せば十分だろう。
どうしても心配なら電話等で fingerprint を確認すればなんとかなるはず。
また、公開鍵暗号である RSA は遅いので、実用的には AES 等の共通鍵暗号で暗号化して、RSA でその共通鍵を暗号化するという使い方になる。

あと rsautl に対応する dsautl, ecutil 等のサブコマンドが見当たらなかったので DSA と ECDSA による encrypt/decrypt する方法は要調査。
pkeyutl は RSA は通るけど DSA と EC はなぜか上手くいない。鍵の作り方が悪いのか???
追記: 2015-03-18
DSA と ECDSA は電子署名の規格なので、公開鍵による暗号化と復号化 (encrypt, decrypt) は出来ない模様。
署名と検証 (sign, verify) は問題なく出来た。
openssl pkeyutl # EC ALGORITHM では sign, verify で ECDSA と derive で ECDH をサポートしているとの事。
以下のようにすると ECDH により同じ値が得られる。
openssl pkeyutl -derive -inkey my_ecdsa   -peerkey your_ecdsa.pub
openssl pkeyutl -derive -inkey your_ecdsa -peerkey my_ecdsa.pub
毎回同じ値しか得られないので、どちらか一方が使い捨ての ec ペアを使えば良いのかな?

追記: 2015-03-23
ECDSA キーペアと AES256 による暗号化スクリプトを書いてみた。 新しく ECDSA キーペアを生成して暗号化した場合、その場で秘密鍵を破棄すると、相手以外には自分も含めて誰も(現状では天文学的な確率でしか)復号出来なくなるはず。
秘密鍵の機密性について担保出来てさえいるなら、普通はそこまでする必要はない筈だけど。

参考:
~/.ssh/config に以下のように並べておくと上の方から順に試されるみたい。
IdentityFile ~/.ssh/id_ecdsa
IdentityFile ~/.ssh/id_rsa
パスワード認証したい場合は -o PubkeyAuthentication=no 付けとけば OK
特定の鍵を突っ込みたいときは -i id_seckey 付けとけば OK
ついでに -o PasswordAuthentication=no も付けても良いかも。
公開鍵認証する際
~/.ssh/authorized_keys は 644 でも問題ないが
~/.ssh は 700 じゃないと駄目みたい
あと owner にも注意
chmod 700 ~/.ssh のつもりで chown 700 ~/.ssh なんてしてしまい、しばらく頭を抱えてる羽目に陥ったのは内緒だ
~/.ssh/authorized_keys にはいろいろと設定が出来る模様。
1行に全部押し込むのでちょっと可読性に問題があるが、例えばトンネル自動起動用としてパスフレーズを外した秘密鍵に対するペア用の公開鍵なんかをなるべく安全に使いたい場合があったとして、以下のようにすると IP を制限して、さらに cat の入力待ちで何も出来ない状態に出来る。
from="192.168.1.xxx/32",command="echo -e \"Tunnel: waiting forever.\nC-D to exit.\";cat" 〜pubkey〜
そこから更にサーバー側でローカルに ssh かけてパスワード認証でログイン待ちさせるなら以下のようにしても悪くないだろう。
from="192.168.1.xxx/32",command="echo -e \"Tunnel: waiting forever.\nC-D to exit.\";ssh -oPubkeyAuthentication=no localhost" 〜pubkey〜
参考:
20190514: 追記
起動時にトンネルを掘って screen 上で維持したいような場合は以下
多段 ssh で、各段、パスフレーズ省略した共通の鍵で、
踏み台となる 1 段目の remote-1st-host では port forwarding を許可せず、
目的地となる 2 段目の remote-2nd-host では port forwarding を許可する
みたいな設定

local host の ~/.ssh/config
Host	remote-2nd-host
	ProxyCommand	ssh -oIdentityFile=~/.ssh/seckey_for_tunnel remote-1st-host
	IdentityFile	~/.ssh/seckey_for_tunnel
	LocalForward	localhost:10080 remotehost:80
	PermitLocalCommand	yes
	LocalCommand	echo "Tunnel is opened."
1段目の remote host の ~/.ssh/authorized_keys
command="nc remote-2nd-host 22",no-port-forwarding 〜pubkey_for_tunnel〜
2段目の remote host の ~/.ssh/authorized_keys
command="echo -e \"Waiting forever.\nCtrl-D to exit.\"; cat" 〜pubkey_for_tunnel〜
password authentication が有効な環境で ~/.ssh/authorized_keys へ秘密鍵をコピーする場合、
local から以下のようにすれば一発だった。
ssh-copy-id <remote host name>
既に登録がある場合、-f オプションで強制的に追加も出来るようだ。
一方で削除は remote host 上で ~/.ssh/authorized_keys の当該行を削除するしかない模様。
X, Y の 2 台のホストがあって、X 経由で Y に転送したいとした場合、~/.ssh/config に以下のように設定しておけばよい。
Host    Y
        ProxyCommand    ssh -W %h:%p X

Trouble Shooting

以下のような操作をした場合に terminal が固まってしまう場合がある。
  • ある程度行数あるファイルを cat する
  • ある程度のファイル数のあるディレクトリを ls -l する
  • lv や byobu 等 ncurses 使ってるコマンドで画面をスクロールする
どうも ssh client の down stream に不具合が生じているらしいのだが up stream は生きているらしく、キーボードを叩くと画面出力は返ってこないもののサーバー側でコマンド等は実行されているという不思議な状況。
ただし exit しても接続が切れなくって who コマンドで pts を確認しておいて、接続している sshd を kill すると Write failed: Connection reset by peer でようやく接続が切れような状況。

Jambo Frame 対応してもらいたくて ssh server 動いてる Ubuntu Server 側の ifconfig で mtu 16110、ssh client 動いてる Windows 7 の NIC デバイスドライバー詳細設定タブの Jambo Frame で 9KB MTU を設定してたんだけど、これがまずかった模様。
とりあえず freeze した状態で server 側を mtu 1500 にすると、freeze から復帰出来た。
と言うことで、MTU の設定をデフォルトの 1500 にしておくと問題は解決した。

Jambo Frame 対応は、設定詰める必要がありそう。
とりあえず、mtu 16110 の Ubuntu Server 13.04 と 9KB MTU の Windows 7 だと頻繁に発生。
mtu 16110 の Ubuntu Server 13.04 と mtu 6128 の Ubuntu Desktop 12.04 LTS だと今のところこの不具合は確認出来てない。

参考:
OpenSSH 7.0 では脆弱性対策のため DSA(ssh-dss) がデフォルトでは無効にされたらしい。
この結果、接続先のサーバーが古いと以下のようなエラーで接続出来ない場合がある。
Unable to negotiate with xxx.xxx.xxx.xxx: no matching host key type found. Their offer: ssh-dss
セキュリティ的にはサーバーをバージョンアップするのが筋だが、サーバーが自分の管理下になくて対応してもらえないような場合、仕方がないので ~/.ssh/config に以下の様な設定を追加しておくと ssh-dss を有効に出来る模様。
servername
    HostKeyAlgorithms ssh-dss
Cygwin が Linux や BSD よりも先行して OpenSSH の新しいバージョン入れてたりするので、特に Cygwin から古いサーバーに接続する際に問題が出易い。

参考:
追記: 2016-07-04
言うまでもないが、~/.ssh/config に設定しなくても ssh に以下のオプションを与えても良い。
-o HostKeyAlgorithms=ssh-dss

関連

コメントをかく


「http://」を含む投稿は禁止されています。

利用規約をご確認のうえご記入下さい

Wiki内検索

フリーエリア

管理人/副管理人のみ編集できます