せきゅぽろ 15

標的型攻撃に関して

一つ目のテーマは、トレンドマイクロの平原 伸昭さんによる、標的型攻撃に関するお話でした。

2、3年前までは遠い海の向こうの話、というイメージだった標的型攻撃も、最近は日本でも標的型攻撃だと思われる事例が報道されたり、すっかり身近(?)になってきました。

もっとも印象に残った言葉は「注目すべきは不正な活動ではなく、不審な活動」。

そもそも「不正な活動」なら、アンチウィルス製品や IPS の類で検知できるけど、本当に標的型攻撃が行われている時は、明確に不正な活動ではなく、管理者がやっているのと同じ事が行われている、ということです。

例えば、管理共有を使ったファイルのコピーや PsExec などのツールの利用など、それ自身は不正とは言えない処理があり、それらを「点」として捉えると、白黒つかないけど、じゃぁ、それらが「どこから」「いつ」といったところまできちんと調べると、「それはおかしい」ということに気づくことになります。

逆に、そういった動きが「怪しい」と分かるように、普段の運用環境をきちんと整理しておく事が大切だよなぁ、と思いました。

あと、実際のマルウェア解析の一端を紹介してくれました。

いろいろツールはあるんだけど、まずは OllyDbg を使って、どんな動きなのかを知る、というところからスタートするそうです。特に、インシデント対応の場合は、通常のマルウェアのようには時間をかけられないので、どんなファイルを保存するのか、どんなレジストリを書き込むのか、といった辺りを、OllyDbg で Win32API にブレークポイントをはって確認し、被害範囲を把握する、といった感じだそうです。

プライバシー周りのお話

二つ目のテーマは、北大大学院教授の町村 泰貴先生による「オンライン・プライバシー」でした。

まずは、そもそもの話、ということで「個人情報」と「プライバシー」の違いといったところで、個人情報に関しては個人情報保護法によって規定されているけど、プライバシーに関しては法的に明確に規定されてない、ということでした。故に、プライバシー侵害に関しては、民法 709 条に基づく民事での損害賠償はあっても、刑事罰はありません。ただ、プライバシー侵害の中に名誉毀損も含まれる場合もあって、名誉毀損になれば刑事罰の対象になるそうです。

で、私も最近聞いたキーワードで「忘れられる権利」というのがあるのですが、さすがに広まってしまった情報を全て回収して消すことは不可能だけど、一度与えた情報をいつでもオプトアウトできるようにすべきだろう、という話でした。

プライバシー保護の必要条件として、町村先生が挙げていた項目は、上記の「忘れられる権利」の他に、情報の収集・理由に関して十分な情報が与えられる「インフォームド・コンセント」と、収集・利用した側が漏洩防止に十分なセキュリティを施す「データ漏洩防止の保証」を挙げられていました。

現在、この辺をまとめた「パーソナルデータの利用・流通に関する研究会の報告書」に関して、総務省パブリックコメントを募集中だそうです*1

次回は

次回は 7/20 に Yahoo の 戸田 薫さんが、ワンタイムパスワードに関してお話してくれるそうです。...って、今、大変な時じゃないのかなぁ。

ちなみに、次回は「気象兵器」のまっちゃさんもいらっしゃるようです(^^;

セキュアな rsync - 実践編

理論編(id:JULY:20111127)を書いてから、既に1年半も経ってしまいましたが*1、ようやく実践編です。

2台のホストは

ホスト名
コピー元 master.example.com
コピー先 slave.example.com

とします。SSH は slave.example.com から master.example.com へ接続します。

rsync 用のユーザの作成

双方のホスト上で rsync 用のユーザを作ります。このユーザは普通にログインする必要が無いので、ログインシェルを /sbin/nologin にしておきます(後述しますが、とりあえずこの時点では、ログインシェルは /sbin/nologin としておきます)ホームディレクトリも必要ありません。

あとは基本的には任意ですが、多くのディストリビューションで 500 番以上の UID を一般ユーザに割り当てる習慣があるので、500 番未満が良いでしょう*2

# groupadd -g 480 rsync
# useradd -d / -M -u 480 -s /sbin/nologin -g rsync rsync

ssh のホストベース認証

これについて書いているサイトは多いので、省略... でも良いのですが、一応、書いてみます。

鍵の用意

多くの Linux ディストリビューションでは、最初に sshd が起動された時に生成するようになってます。/etc/ssh の下に、下記のようなファイルがあると思います。

秘密鍵 公開鍵 対応プロトコルバージョン
ssh_host_key ssh_host_key.pub Version 1
ssh_host_dsa_key ssh_host_dsa_key.pub Version 2
ssh_host_rsa_key ssh_host_rsa_key.pub Version 2

今時、SSH1 のプロトコルを使う必要は無いので、「ssh_host_dsa_key、ssh_host_dsa_key.pub」か「ssh_host_rsa_key、ssh_host_rsa_key.pub」のどちらかを使う事になります。違いは公開鍵暗号として、DSA を使うか、RSA を使うか、ということですが、現在は RSA を使うのが一般的です*3

これらの生成済みのファイルは、「このホストを認証してもらうための鍵」です。今回の例では、slave.example.com 側のファイルです。

もし無ければ*4ssh-keygen で生成します。

$ ssh-keygen -f ssh_host_rsa_key -t rsa -N ''
Generating public/private rsa key pair.
Your identification has been saved in ssh_host_rsa_key.
Your public key has been saved in ssh_host_rsa_key.pub.
The key fingerprint is:
......

-f は出力するファイル名で、このファイル名で秘密鍵が生成されます。このファイル名に「.pub」が付いた名前で、対応する公開鍵のファイルが保存されます。-t は公開鍵暗号の暗号方式で rsa をして、-N はパスフレーズの指定で、「-N ''」とする事で、パスフレーズ無しの鍵が作られます*5

鍵の配備

今回は、slave.example.com が、master.example.com認証してもらう立場なので、slave.example.com のホスト公開鍵を、master.example.com にコピーします。

認証する側では、/etc/ssh/ssh_known_hosts ファイルに公開鍵の内容を追記します。認証される側で ssh サーバが動いているのであれば、認証する側のホスト上で下記のようにすると、/etc/ssh_known_hosts ファイルに公開鍵を追記できます。

# ssh-keyscan slave.example.com >>/etc/ssh/ssh_known_hosts
ホストとユーザの制限

認証する側の/etc/ssh/shosts.equiv で、許可するホストとユーザ名を指定できます。ただし、sshd_config の次の項目を確認する必要があります。

IgnoreRhosts
yes にすると、ユーザのホームディレクトリにある .shost ファイルを無視します。これが no になっていると、/etc/ssh/shosts.equiv に記述が無くても、エンドユーザレベルで許可されている可能性があります。

今回は master.example.com の管理者による制限を行いたいので、IgnoreRhosts は yes にします*6

shosts.equiv の記述自体は簡単で、認証を許可するホスト名とユーザ名を記述します。ユーザ名は省略可能で、その場合は記述したホストの全てのユーザを許可します*7。slave.example.com から master.example.com へ接続するユーザを user1 とすると、shosts.equiv の内容は以下のようになります。

slave.example.com user1

しかし、今回の場合、

ユーザ ホスト ユーザ ホスト
rsync slave.example.com rsync master.example.com

という接続になります。shosts.equiv に書くのは、あくまでも、認証してもらう側のホスト上のユーザなので、

slave.example.com rsync

となります。

sshd_config の設定

先述の IgnoreRhosts に加えて、残っているのは、そもそもホストベース認証を有効にするための設定です。

HostbasedAuthentication
ホストベース認証の有効/無効を設定します。これと似たものに RhostsRSAAuthentication がありますが、これは SSHプロトコルバージョン 1 用の設定で、プロトコルバージョン 2 で使われるのは、この HostbasedAuthentication です。

ssh_config の設定

ssh クライアント側の設定で必要なのは、下記の2項目です。

HostbasedAuthentication
ホストベース認証の有効/無効を設定します。ここは sshd_config の時と同様です。
EnableSSHKeysign
ホストベース認証時にクライアントサイドで動く補助プログラム ssh-keysign を有効にします。

ssh_config は、Host キーワードを使って、特定の接続先にだけオプションを適用する事ができます。ssh のサーバになるホスト名をして、

Host master.example.com
    HostbasedAuthentication yes

とすれば、ホストベース認証を使う相手先を master.example.com だけに絞る事ができます。ただしEnableSSHKeysign は、この Host キーワードによる指定の外側に記述する必要があります。

EnableSSHKeysign yes

Host master.example.com
    HostbasedAuthentication yes

sudo の設定

rsync コマンドを cron に設定して実行する側は、

  • 一般ユーザの cron で実行する。
  • 面倒だし、分かりづらくなるので、/etc/cron.daily とかに設定してしまう。

の2つの方法が考えられます。後者であれば、rsync をスケジュール起動する側(ここでは、slave.example.com)では、sudo の設定は不要です。

前者であれば、/etc/sudoers で、rsync を実行する時のユーザで、rsync を root 権限で実行できるようにする必要があります。仮にその時のユーザアカウントが rsync-user であれば、

rsync-user localhost=(root) NOPASSWD:/usr/bin/rsync

と記述し、後述の requiretty に関する記述を追加した上で、「sudo rsync 〜」と、sudo 経由で rsync を実行します。

逆に、ssh 経由で rsync を呼び出される方は sudo の設定は必須です*8

rsync ALL=(root) NOPASSWD:/usr/bin/rsync

これで、rsync を root 権限で呼び出せるようにはなったのですが、多くのディストリビューションの /etc/sudoers で、

Defaults    requiretty

という行が入っています。これは、sudo を使ってコマンドを呼び出す際、端末としてログインしている状態である事を要求します。リモート側で実行される sudo rsync は、ログインセッションでは無いので、除外してやる必要があります。ここで、

Defaults    !requiretty

としたり、コメントアウトする例を見かけますが、これだと、全ての sudo の実行で、ログインセッション以外での sudo 実行を許可する事になります。rsync ユーザだけ、ログインセッション以外での実行を許可するためには、

Defaults:rsync  !requiretty

という行を追加します。

rsyncコマンドライン

ポイントは2つです。

通信を、sudo 付きの ssh 経由にする

「-e」オプションで ssh を指定するのですが、その際、「-e 'sudo -u rsync ssh -l rsync'」と、sudo 経由で、かつ、ユーザ名付きにする必要があります。こうすることで、

  • ローカル側の rsync が呼び出す sshrsync ユーザで実行する。
  • 呼び出された ssh は、接続先の rsync ユーザに対して繋ぎに行く。

という動作になります*9。この時の「-u」で指定するユーザ名は、master.example.com の shosts.equiv で指定したユーザ名と合致している必要があります。今回は、ssh を実行するユーザ(-u rsync)と、接続先のユーザ(-l rsync)が同じなので、「-l rsync」は省略可能です。

リモート側で実行される rsync を sudo 付きにする。

「--rsync-path='sudo rsync'」とします。これを忘れると、リモート側の rsync は「rsync アカウント権限で rsync を実行」する事になり、読み出しに root 権限が必要なファイルが取得できなくなります。

全体としては、こんな感じのコマンドラインになります。

rsync -a -e 'sudo -u rsync ssh -l rsync' --rsync-path='sudo rsync' master.example.com:コピー元 コピー先

非 root ユーザでこれを実行する場合は、この手前に sudo を付けます。

コピー元の rsync ユーザの制限

実は、動作を確認している中で、ここでつまずきました。目指す rsync の実行は、

  1. slave.example.com 側で rsync を実行。
  2. その rsync が「ssh -l rsync」として ssh を実行。
  3. 繋がれた master.example.com では「sudo rsync 〜」を実行。

となります。冒頭、rsync ユーザのログインシェルを「/sbin/nologin」としていますが、そうするとすると、ssh でつながった直後に切断され、3 番目の「sudo rsync 〜」を実行できなくななります。

なので、普通の「/bin/bash」などをログインシェルにしてしまえば、これまでの設定で目的が果たせます。

... ただ、なんとかしたい。rsync 実行の為だけに用意したアカウントで、slave.example.com から繋いだ時だけとは言え、rsync ユーザに許可されている任意のプログラムが実行できる、というのは、どうにも格好悪い。rssh を使えば、scp や sftp、rsync 用に絞ることも可能だけど、今回は sudo 経由で rsync を呼び出すので、これは使えない...。

で、あれこれ調べまわった挙句*10、ログインシェルを自作しました*11

#!/bin/sh
if [ "$1" != "-c" ]; then
    exit 0
fi

if (expr "$2" : 'sudo  *rsync  *--server  *--sender ' >/dev/null); then
    echo -n "$2" | egrep -q '[^\][;<>]|&&|\|\|'
    if [ $? -eq 0 ]; then
        exit 0
    fi
    /bin/sh "$@"
else
    exit 0
fi

ssh 経由でリモート側で呼び出される rsync コマンドには「--server」というオプション付きで呼び出されます。で、今回のケースのように、リモート側からローカル側へダウンロードする場合、「--sender」というオプションも付きます。

これらのオプション付きの rsync が sudo 経由で呼ばれ、かつ、途中に「;」や「&&」「||」といった、更に別のコマンドを呼び出す事が可能なメタ文字や、リダイレクト用の文字が含まれていない場合にのみ、処理を実行できるようにしています。

このシェルスクリプトを例えば「/usr/local/bin/rsyncshell」というファイル名で保存し、

usermod -s /usr/local/bin/rsyncshell rsync

といった具合に、ログインシェルに設定すれば完成です。

但し、このログインシェルスクリプト、通常のシェルをログインシェルにするよりは制限がかかっている状態になっていますが、

  • 他のプログラムを実行するための回避策が他に無いか?
  • メタ文字に対するチェックが、同期対象のパス名に ASCII 以外の文字が含まれているケースで問題がないか?

といったところは十分に検証されていません。後者の問題が無ければ、通常のシェルを指定するよりはマシ、といった程度に考えて下さい。

また、あくまでも「マスターからダウンロードする rsync」という前提にしています。というのは、不用意にリモート側の $(HOME)/.bashrc などを書き換えないように、と思うと、ダウンロードする方が安全ではないかと思ったからです。

まとめ

全体をまとめると、こんな感じになります。

  • コピー先の root ユーザで rsync を実行し、コピー元からダウンロードする方向にする。
  • rsync の通信は ssh 経由とし、ssh の認証はホストベース認証にする。
  • コピー元となるホストの sshd の設定で、相手のホストと、その時の相手ホスト上のユーザにのみ、ホストベース認証を許可する。
  • コピー元のとなるホストでは、rsync 用のユーザに対して sudo 経由で rsync 実行を許可する。
  • できれば、コピー元の rsync 用ユーザは、制限付きのログインシェルにする。
  • コピー先での rsync の実行は、-e で特定のユーザ名を使った ssh 接続を実現し、--rsync-path で相手側の rsync を sudo 付きで呼び出すようにする。

*1:時間がかかった理由は、本文中にもあるログインシェルの問題と、sudo の requiretty をまるごと無効にしないための方法、あと、我が家の中途半端な IPv6 環境のせい、とか、いろいろありまして...

*2:RHEL / CentOS Ver.6 以降、490 番台に、特定のプログラムが使うアカウントが配置されるケースがあるので、ちょっと気を付ける必要があります。

*3:OpenSSH の ssh-keygen が DSA の鍵を生成する場合、鍵長が 1024 bit に制限される、というのが、RSA が推奨される理由になってます。DSA 自体は 1024 bit より長い鍵長もあるけど、現状、実際に使えるのは 1024 bit のみ、ということのようです。参照: DSA鍵の鍵長 | dodaの日記 | スラド

*4:sshd が動作しているホストであれば、必ずあるはずです。

*5:この時、生成した秘密鍵を置くパスに関して、どこにどんな名前で保存しても、設定ファイルで指定できそうな気もするのですが、ちょっと分かりませんでした。秘密鍵を読み出すのは、ssh クライアントプログラムから呼び出される ssh-keysign というプログラムなのですが、ssh-keysign の manpage を見ても、固定のパス名しか書いてありません。ちょっと謎...

*6:一応、デフォルトは yes です。

*7:ただし、root は除く

*8:「ALL」のところをホスト名で制限したいのですが、ssh 経由の時にこの sudoers のホストによる制限は効かないようです。参照:HowTO: Sudoers Configuration - 「Note: This applies to computers running application services. If you connect to a machine via ssh, this does not apply.」

*9:/etc/sudoers に、「root ALL=(ALL) ALL」といった行があることが前提です。普通、入っていると思います。

*10:もちろん、rbash や rksh などの Restricted Shell も検討しました。

*11:元ネタは http://www.oreillynet.com/linux/blog/2006/05/restricting_rsync_over_ssh.html

せきゅぽろ 14

まずは、昨年、シマンテック社主催で開催された高校生向けの CTF、「シマンテック サイバーセキュリティチャレンジ」に参加した札幌国際情報高校の「もやしーず」と、ネットエージェントの松田和樹さんのパネルディスカッション、だったんですが、全編オフレコという事で、内容に関してはなにも書けません。

う〜ん、どうなんだろう。オフレコにしなきゃいけない程の事だったんですかねぇ >シマンテックさん。

で、後半は松田和樹さんによる、「オンラインゲームにおけるセキュアコーディング」ということで、ゲームの「チート」(「ズル」の類)をテーマにしたセキュリティのお話しでした。

チート自体は、かつては、国内でのゲームが専用ゲーム機に偏っていた事もあって、PC でのゲームが盛んだった海外に比べると少なかったのが、最近は急激にカジュアル化しているそうです。

で、典型的なチートの例として、ニセのハイスコアをたたき出す、という話で、URL のパラメータにスコアそのものがあったり、json のデータに埋め込まれていたり、といった、「改ざんして下さい」と言わんばかりの例もあったり、じゃぁ、そういった事を防ぐために具体的にどんな方策があるのか、といった話から始まりました。

で、改ざん防止にリプレイデータを、と思っても、「で、そのリプレイデータって本物?」ということで、例えば、人脈を駆使して本当にうまい人にやってもらう、といったソーシャルハッキング(?)もあれば、Bot による自動操作や、自動操作が難しいゲームに関しては、プログラムのメモリ空間を監視や、API のフックを使ったツールを作って、プレイの補助をさせる、といった事まであるそうです。そこまでがんばれば、そのハイスコアも努力の結果と言えなくもないですが...

で、オンラインゲームに求められるセキュリティ、という事になるのですが、実は、個々の必要な対策はゲーム固有のものでは無い、といった印象でした。それを如実に表している言葉が「クライアントからの通信は一切信用してはいけない」。

ゲームに限らず、ネットワークに関連するプログラムなら、当然の前提です。昨今だと、通信に限らず、データファイルを読み込む時でも、矛盾のあるデータが入っているかもしれない、という事を意識しておかないと、単なるバグのつもりがセキュリティ上の脆弱性となるご時世です。入力データが正しいかどうか、矛盾する通信や、あり得ない手順の通信に対してきちんとブロックできるか、トランザクション処理のように排他が必要な処理を適切行っているか、といった、セキュアプログラミングの基本とも言えるお話でした。

ただ、これらが、特にオンラインゲーム業界できちんと出来ていない事には、ちょっと業界特有の事情もあるようです。

元々、専用ゲーム機でゲームを作っていたようなところから、オンラインゲームの世界に入ってくると、必要なスキルが違ってきます。例えば、

  • クライアント/サーバ型のシステム
  • ネットワーク・通信
  • データベース
  • 運用管理

といったスキルが必要になってきますが、これらの技術は元々、セキュリティ問題が普通に存在する分野です。自分はゲームの開発は全く無縁で、サーバの構築・運用が仕事としては多いですが、そこから見ると当然気にするポイントの事が、「ゲームを作る」とこから始まっている人には、なかなか理解されていない、という現実があるようです。まぁ、これはゲーム業界に限らず、例えば組み込み業界も、同様の問題があったり、多かれ少なかれ、「開発者」はセキュリティに無頓着、というのはありますね。

あと、オンラインゲームの場合は、サービス・インがスタートラインで、しかも、定期的に人を惹きつけるためのイベントを打ったり、と、充分にセキュリティに時間・コストをかけられない、という業界の事情もあるようです。

ということで、セキュアコーディングの基本が大切、というのを再認識するお話しでした。

時間が足りなくなって、ちょっと尻切れトンボになったのが残念でしたが、セキュアコーディングの基本を押さえたスライド資料だったので、公開できる範囲で公開してもらえると、教科書として良さそう、と思いました。

途中、ネタとして登場した、「ポケットモンスター ピカチュウバージョン」にある、任意の Z80 バイナリが実行できる脆弱性はすごかった。これ、CVE 番号とか、JVNDB 番号とか付かないんですかね(^^;

Google Safe Browsing の診断結果が更新された。

このサイトで過去 90 日間に Google がテストした 3532 ページのうち 266 ページで、ユーザーの同意なしに不正なソフトウェアがダウンロードされ、インストールされていたことが判明しました。Google が最後にこのサイトを巡回したのは 2013-03-05 で、このサイトで不審なコンテンツが最後に検出されたのは 2013-03-04 です。

昨日と比べると、全然ちがってますね。これだと、

  • 診断結果として表示しているのは、ブロックする前の情報で、実は既に問題が発見されていた。
  • 今になって、その情報が診断結果のページに表示されだした。

という可能性が高そうですね。

よーく見ると、昨日の画面の右下に「更新: 16 時間前」と書いてあるので、私がこのページを見たのが確か、昨日の夕方頃だったはずなので、3/4 深夜から 3/5 の未明での診断結果だったと思われます。

mainichi.jp がいつからブロックされていたかは分かりませんが、mainichi.jp にかぎらず多くのページがブロックされた話は、昨日の午前中からあったと記憶してます。

何れにしても、

  • 「ブロックされている」という状態

  • 診断結果

が一致していなかった可能性もあります。

う〜ん、外してしまったかも...。

にしても、既にブロック状態にあるのに、辿れる診断結果が古いままだったら、「なんのこっちゃ?」だよなぁ。

Google Safe Browsing の判断基準

大手サイトが Google Safe Browsing でブロックされたニュースがありました。

「毎日jp」など「不正なソフトウェアが存在する可能性」でGoogleからブロック - ITmedia NEWS

文中に

Googleがブロックしている理由は不明だが、

と書かれていますが、診断画面をよく見ると、おそらくこんな理由だろう、というのが分かります。

毎日新聞を例に診断結果を見てみます。

現在のところ、このサイトは疑わしくないと認識されています。

と書かれています。これだと「じゃぁ、なんでブロックされているんだぁ?」になりますが、真ん中ぐらいに

このサイトは 5 個のネットワーク(AS4694 (IDC), AS2516 (KDDI), AS17506 (UCOM) など)でホストされていたことが判明しました。

と書かれています。

この「AS」の後ろに突いた番号は、おそらく、ルーティングプロトコルの BGP で使われる AS 番号だと思われます。

で、この AS 番号が書かれたところのリンク先を見てみます。AS4694 の情報を見てみると、

このネットワークで過去 90 日間に Google がテストした 8409 個のサイトのうち、90 個のサイト(www.medianetjapan.com/2/20/fasshion/devota/, pixiv.net/, brazil-propolis.jp/ など)のコンテンツで、ユーザーの同意なしに不正なソフトウェアがダウンロードされ、インストールされていたことが判明しました。

と書かれています。

と言うことは、mainichi.jp のサーバが置かれているところと同じ AS 番号で認識されるネットワーク中に、マルウェアを配るサイトがあった、という事になります。

つまり、

  • mainichi.jp 自体には、今のところ問題は見つかっていない。
  • でも、近くにあるサーバがマルウェアを配っていた。

という状況だと思われます。

おそらく、Google 側としては、悪質なサイトと同一のネットワークを、緊急避難的にブロックしたのでしょう。同一ネットワークのサーバにマルウェアが広まっている可能性を考慮した上で、ひとまず、同一 AS 番号のネットワークをブロックし、個々のサイトに関しては、Google がクロールした結果から大丈夫と判断できれば、随時解除されていく、といった所ではないかと想像します。

この辺、オフィシャルな文章があると、「これが理由だ!」と言えるんですけどねぇ。

OpenLDAP 上のパスワード情報

OpenLDAP で userPassword アトリビュートにパスワード情報を保存する場合、推奨はソルト付き SHA(SSHA)とされていると思います。実際、CentOS Ver 6.3 上の OpenLDAP に付いてくる slappasswd コマンドは、オプションを指定しないデフォルトは、SSHA の形式を出力します。

しかし、高速な GPU が廉価に販売され、その GPU を駆使して並列計算をすると、ブルートフォースによる解析が、実用的な時間で成功するようになりました。

去年の 12 月に飛び込んできた、「NTLM ハッシュが 8 文字までのパスワードなら5時間版」*1は衝撃的で、私もそのことを日記に書きました*2。NTLM ハッシュは Unicode で表現されたパスワード文字列の MD4 ハッシュ値で、SHA-1 よりは出力されるハッシュ値の bit 長も短く、1つのハッシュ値を求める時間はおそらく、SHA-1 より MD4 の方が短いとは思いますが、それでも、何百倍、何千倍も違う、という事ではないでしょう。

http://www.cryptopp.com/benchmarks.html

上記サイトに、様々はハッシュ値計算や暗号化処理のベンチマーク結果がありますが、MD5SHA-1 の比較で、およそ2倍(MD5 の方が高速)という結果になっています。MD4 がどのくらいになるのか分かりませんが、大きく見積もっても 10 倍にはならないと思います。

仮に、SHA-1 の計算が MD4 より 10 倍の時間がかかる、としても、先の「5時間半」は「55 時間」にしかなりません。2日余りで必ず解ける、という事になってしまいます。「塩加減は重要? - JULYの日記」でも書きましたが、ソルトの有無は Rainbow Table 対策にはなっても、ブルートフォース対策にはなりません。

また、実際に SHA の値を単一の GPU で 33 日間で見つけられたという2年前の記事*3もあります*4

ブルートフォース対策にはストレッチング、なのですが、自分で作る Web アプリケーションならともかく、LDAP のパスワードフィールドに対して、独自のストレッチングを行う OpenLDAP 用の overlay や plugin を作る、というのも気が引けます。

{CRYPT} は crypt(3)

OpenLDAP のパスワード・スキームに、{CRYPT} というのがあります。これは、古くから UNIX 系 OS の /etc/passwd や /etc/shadow のパスワード・フィールドに記述するされる形式で、古典的には ASCII のパスワード文字列を DES の鍵として、全ビット 0 のデータを出発点に、繰り返し暗号化した結果になります*5

しかし、今時、この DES を使った形式の値を保存している物を見ません。商用 UNIX でも、Linux でも、10 年以上前から、MD5 を使った形式などに変わってきています。

これは、このパスワード・フィールドに記述する内容を計算する crypt という C 言語用の関数を拡張する形で実現されました。具体的には crypt の引数に渡すソルトで、先頭 3 文字に特別な意味を持たせ、それによって計算処理を変えるようになっています。例えば、「$1$」で始まったソルトが渡されたら、MD5 を使った計算処理を行う、といった感じです。今では MD5 の代わりに SHA-256、SHA-512 を使った形式もあり、最近の Linux ディストリビューションでは SHA-512 を使う「$6$」になっています。

ところが、設定したパスワードとソルトから MD5 の値を求めようとしても、実際に /etc/shadow に書き込まれた物とは、似ても似つかない結果になります。で、実際に crypt の処理を調べたことがあります。

調べてみると、結構複雑 - JULYの日記

実は MD5 を使った crypt というのは、1,000 回のストレッチングを行った処理でした。ちなみに SHA-256 や SHA-512 の場合も、同様のストレッチングをしています。

で、改めて OpenLDAP のドキュメントを読むと、slapd.conf の設定に password-crypt-salt-format*6 という項目がありました。

OpenLDAP Faq-O-Matic: How do I specify the crypt(3) salt format to use?

password-crypt-salt-format に指定するのは printf の書式指定子の形式で記述します。上記ページでは、「password-crypt-salt-format "$1$%.8s"」という例が出ていますが、こうすれば、「$1$」で始まり、その後ろに 8 桁のソルト文字列が続くことになります。

つまり、

  • password-hash に {CRYPT} を指定し
  • password-crypt-salt-format に "$1$%.8s" と設定する

と、MD5 を 1,000 回繰り返すストレッチング処理をした結果が、userPassword のアトリビュートに書き込まれる事になります。MD5 の計算時間が SHA-1 の半分だっとしても、ブルートフォースで解くには、単純計算で {SSHA} の 500 倍の時間がかかる事になります。仮に、MD5 と MD4 の計算時間が同程度、と控えめに見積もっても、先の 5.5 時間の装置で 2,750 時間、4 ヶ月近い時間がかかる事になります。もし SHA-512 の crypt を使うようにすれば、先に紹介したベンチマーク結果を見ると、さらに 2.5 倍程度の時間を要するので 10 ヶ月の期間が必要、という事になります。

制限事項

slapd を動かす OS 上の crypt(3) の機能

OpenLDAP の {CRYPT} は、その OS 上の crypt 関数の実装に依存します。なので、複数の slapd で同期をしているような場合、それぞれの OS 上の crypt の実装で揃っている必要があります*7MD5 を使った形式であれば、よほどの事が無い限り、対応していない事は考えられませんが、SHA-256、SHA-512 を使うのであれば要注意です。

ちなみに、RHEL / CentOS の場合、pam_unix で SHA-256、SHA-512 対応となったのは Ver. 5.2 です*8ので、少なくともこのバージョン以降であれば大丈夫なはずです。

LDAP を使うプログラムの実装

ユーザ認証を行うプログラムが、そのバックエンドとして LDAP を使う場合、大きく分けて 2 つの実装方法があります。

  • 入力されたアカウント名、パスワードを使って、LDAP サーバへのバインドを試みる。
  • userPassword アトリビュートを直接参照・比較する。

前者の場合は、slapd がどんなパスワード・スキームを使ってるかは全く関係ありませんが、後者の場合はプログラム側が {CRYPT} で DES 以外の形式が扱えるか、という問題になります。

例えば、Dovecot でユーザ認証に LDAP を使う場合、

の二通りの方法があり、auth_bind を yes にすれば前者、no にすれば後者になります。

もし、POP3APOPIMAP で DIGEST-MD5 や CRAM-MD5 を使いたければ後者しか選択の余地がありませんが、そうでなければ、前者の方式が使えます。

前者の方式が使えるのであれば、パスワード・スキームの問題は生じませんが、後者の場合は、Dovecot がうまく扱えるかどうか、確認する必要があります*9

RFC 3062 非対応

パスワードを変更する際、RFC 3062 の「LDAP Password Modify Extended Operation」に対応しているプログラムからであれば、slapd が userPassword を設定したパスワード・スキームで保存してくれますが、これに非対応の場合、userPassword に保存する内容を直接書き込む物があります。コマンドラインの ldappasswd は RFC 3062 対応なので問題ないのですが、例えば Apache Directory Studio*10 は対応していません*11

これは、password-crypt-salt-format を指定してるか否かにかかわらず、クライアント側で勝手にパスワード・スキームを変更できる事になるのでうれしくないのですが、もし、これらのツールを使うのであれば、slappasswd で -c オプションに password-crypt-salt-format に指定したのと同じ物を指定し、-h オプションに {CRYPT} を指定すれば、userPassword アトリビュートに保存される値が計算できます。

$ slappasswd -h {CRYPT} -c '$1$%.8s'
New password:
Re-enter new password:
{CRYPT}$1$t6PXjyr8$R9LHggt9sf2ietomynfRo0

ただ、slappasswd が使えるなら、ldappasswd で変えた方が早いですが...。

パフォーマンス

そもそも、1度の SHA-1 の計算処理で綱渡り状態にあるようなサーバの場合、そのままパスワード・スキームを変更すれば破綻します。そもそも、認証処理でそこまで重い状態な時点で、システム増強などを検討すべきですが...。

まとめ

ということで、もし、システム全体で問題が無いのであれば、OpenLDAP でのパスワードスキームは、

password-crypt-salt-format を指定した上で、{CRYPT} を使う。

が、今のところ正解、という事になります。ブルートフォース耐性は、"$1$%.8s" で {SSHA} のおよそ 500 倍に上がります。パスワード長を1文字増やしたより高い効果が得られる事になります。

ただし、短いパスワードや単語を使ったようなパスワードなどを設定したら、ほとんど効果はありません。十分に長く、複雑なパスワードで、使い回しをしない、という鉄則は、何ら変わることはありません。

*1:8文字の全パスワードを5時間半で解析するコンピュータクラスタが登場 - CNET Japan

*2:こんなに早く、この日が来るとは... - JULYの日記

*3:エフセキュアブログ : 「SHA-1+salt」はパスワードに十分だと思いますか?

*4:指数表現は実感しにくい - JULYの日記

*5:crypt (C) - Wikipedia Traditional DES-based scheme 参照

*6:今時の cn=config からオンラインで設定変更をする場合だと olcPasswordCryptSaltFormat に該当します。

*7:試してはいませんが、同期自体は正常に行われるかもしれません。ただ、userPassword アトリビュート自体が正しく同期できても、バインド時に正しく認証できない、という事態になる事が想像されます。

*8:Bug 435804 – RHEL5.2 Release Notes: SHA-256 and SHA-512 support in password hashing

*9:未確認。Dovecot が {CRYPT} だった時にそのまま crypt 関数を呼び出していれば、大丈夫なはず。

*10:Welcome to Apache Directory Studio — Apache Directory

*11:Ver. 1.5 系の場合。Ver. 2 系は不明ですが、試した感じでは対応している気配が無かったです。サーバ側の設定の関係とか、あるのかなぁ。

LDD13is

LDD13is(LOCAL DEVELOPER DAY'13/Infra & Security)に行ってきました。

IT エンジニアの将来 - 吉田 パクえ

基調講演として、co-meeting の吉田パクえさん(本名で紹介されなかった)から、インフラ・エンジニアのクラウドとのつきあい方に関してお話がありました。

クラウドのメリットは、スピードとリスク対策で、コストに関してはケースバイケース、というのは、私も思っていたところなのですが、逆に、そこが力の発揮どころ、というのは、その通りだと思いました。

クラウドをどう使うか、という事をきちんと考えられるかどうか、がポイントで、目的次第でクラウドの使い方も変わるし、既存のホスティングで充分で安上がりだったり、全体としてのセキュリティ・ポリシーによっては、オンプレミスの方が良い場合もあるし。

結局、個々の目的、環境によってどうするのが適切かを判断する必要がある、ということに関しては、クラウドの有無に関係ないわけで、単に選択肢が増えた、ということかな、と。ただ、この選択肢を無視する事はありえないので、サービス全体から見たクラウドの使いどころ、というのを意識していく事が大切なのではないか、と思いました。

ライブコーディングとデモで理解する Web セキュリティの基礎 - 岸谷 隆久

SQL インジェクション、コマンド・インジェクション、XSS といった脆弱性を、実際のデモを交えた解説でした。個人的には、一応、知っている話だったのですが、具体的なコードと、実際の動作によるデモ、というのは、ありそうで無かったような気がします。

特に XSS は、「alert() が動く」というのが定番で、これだと、「何か大変な事が起きている」というのが実感しずらいのですが、セッション ID を保持している Cookie の値を盗む、というデモだったので、問題を実感できた人が多かったのでは、と思います。

個々の問題に対して、コードを修正して、実際に脆弱性が無くなる、というところもデモをしていましたが、具体的な対策は、このセッションの最後でも紹介されていましたが、まずは「徳丸本」ですね。

VPS はじめての一歩 - 鷲北 賢

VPS サーバを使う上で、やるべきセキュリティ対策に関するお話でした。

と言っても、基本的には普通のサーバでの対策と同じです。SSH で、PermitRootLogin を no にしたり、sshブルートフォースを避けるためにポート番号を変更*1したり、公開鍵認証を使ったり、といった ssh 周りの対策や、sudo のすすめや iptables の話など、VPS に限らず、一般的な UNIX サーバでも推奨されるお話でした。

一つ、VPS ならではなのは「まずは、root のパスワードの変える」。さくらの VPS では契約直後は停止状態だそうすが、それでも、いきなりインターネット上にさらされる訳ですから、なにはともかく、パスワードの変更ですね。

エンジニアのお仕事 実際の話

3名の方の、お仕事の様子のお話です。

東京の会社で札幌での在宅勤務されている方、元花屋のインフラエンジニア、ソーシャルゲームの開発者、といった三者三様のエンジニア・ライフのお話がありました。

最後の質問タイムで飛び出した、「手 JOIN」*2は、目 grep の次にくるエンジニア必須のテクニックに(^^?

狙われる日本 - Boris Sharov

なんと、Dr.Web の CEO である Boris Sharov さんの講演です。タイトルは「狙われる日本」でしたが、日本が特に何か、というよりも、世界を見渡せば酷い国・地域があり、日本も無関係ではいられない、といった事が印象に残りました。

とにかく、「安全と思い込む」のが一番危険、ということで、Mac で大規模なマルウェアの感染が見つかった時は、特に米国では大きな騒ぎだったようです。

後半、クラウドのセキュリティに関して話されて、その中で印象に残ったのは、クラウド自体は安全でも、所詮、アカウントとパスワードで認証しているだけだから、アカウント情報が漏れたらいくらでも成り済ます事ができる、という、当たり前だけど忘れがちな点について話されていたことです。故に Boris さんは「クラウドが嫌い」と言っていましたが、クラウドセキュリティの肝は認証、という事を強く思いました。

Free Software Way - 小岩 秀和

WCIT-12 の話から始まって、電子書式で購買履歴が管理されてしまう、といった話をマクラに、Free Software の話を小岩さんが熱く語ってました。個人的には、この辺の話は割と知っていて、とかく宗教論争になりやすいんだよなぁ、などと思いながら聞いていました。

どっちかというと「Stallman よりは Raymond」の自分としては、「ちょっと苦手」な感じもあるんですが、質疑の時に GPL と MIT や BSD ライセンスとの比較の話で、小岩さんが「GPL はきつい」と言われていたのが、ちょっと意外、というか、個人的にはホッとした感じがありました。

LT が 6 本

そういえば、せきゅぽろでは、このところ LT やってないですね。LT は毎度、楽しませてもらう側で、いつかは挑戦して見たいんだけど、笑い取れないしなぁ。

ということで次回は

せきゅぽろ #14 は 3/9 で、内容は...、と思ってせきゅぽろのページを見たら、まだ書かれてなかったですね。
ちょうど1年前のこの時期のせきゅぽろは、入院していて出られなかったんだよなぁ、今年は大丈夫かな。

*1:10022 番への変更例が多いために、すでに 10022 番ポートは、準 Well Known ポート状態だそうです。

*2:DB サーバを並列で増やした時に、上物のプログラムで複数の DB を横断するクエリーを実現する方法