2013年08月30日

ロリポップでWordPressの改竄が拡がった理由

ロリポップでの大規模なWordPressサイトの改竄について
http://lolipop.jp/info/news/4149/

ロリポップからのリリースでは、管理パスワードとログインへのアクセス制限の強化を推奨して、パーミッションの変更と全体のウイルスチェックを行うとしている。WordPressそのもののアップデートはマニュアルに方法が記載されているものの、リリースでは触れられていない。
このことから、被害が大きくなったのは、ロリポップの提供していたWordPressのインストール手順に問題があり、wp-config.phpなどのファイルのパーミッションが不適切だったためではないかと推察出来る。


いくつかのアカウントだけWordPressの管理パスワードが突破される、というのであれば、世界中でほぼいつでも起こっている。
もし、あるユーザーの管理パスワードが脆弱で推測することが出来てしまうと、そのWordPress管理画面から自由にプラグインを導入できる。古い脆弱なWordPressやプラグインを使っている場合も同様で、この場合、そのユーザーアカウントで攻撃者は任意のスクリプトを実行でき、ファイルやDB上のデータ全てを自由に改竄可能になる。
ここまでは、ロリポップに限らずどこのホスティングサービスでも起こりうる、脆弱なパスワードあるいは古いバージョンを使っているユーザーの自己責任と言える。

安価な共用サーバーでのウェブホスティングでは、数多くのユーザーが一つのサーバーを利用している。一つのアカウントに侵入されても、同一サーバーの他のユーザーのデータを読まれたり、変更されたりしないように、CGIは各ユーザーの権限で動作させ、ファイル・ディレクトリの所有者がパーミッションでアクセスを制限することで、他のユーザーの秘密のデータを保護している。そのため、(脆弱な)あるユーザーの権限でCGIが実行できても、影響範囲はそのユーザー1人にとどまる。
(ユーザー毎のchroot/jail/LXCなどを利用ことで、パーミッションに依存せず、各ユーザのデータを保護しているところも有るだろうが、少なくともロリポップはそうでは無かったことになる)

しかし、wp-config.phpに不適切なパーミッション(たとえば444、サーバー上の全てのユーザーが読み込み可能)が設定されていて、そのファイルの場所が分かっていれば、他のユーザーがスクリプトの内容を読めてしまう。wp-configにはデータベースに接続するためのパスワードが記載されているので、DBに接続して管理パスワードを変更してしまえば、管理者としてログインしてウェブサイトを改ざんできる。

つまり、WordPressをインストールしたユーザーのうち、たった1人が脆弱なパスワードを利用していたり脆弱な古いバージョンを使っていて、ファイルのパーミッションが不適切であれば、同じサーバーのユーザーが芋づる式に二次被害を受けることになる。
対策として、真っ先にアナウンスされた内容はWordPressのアップデートを推奨するもの(WordPress自体の脆弱性対策)ではなく、強い管理パスワードとパーミッションの再設定を求めるものだったことから、この推測が補強される。

ロリポップにWordPressをインストールしたユーザーの多くが、誤ったパーミッションを設定していた理由は幾つか想像できる。単にユーザーの不注意かも知れないし、ロリポップへのWordPressインストール方法を紹介したサイトが、間違ったパーミッション設定を多数のユーザーに伝授してしまったのかもしれない。

しかし最もありえそうなのは、ロリポップの「WordPress簡単インストール」機能に問題があり、ユーザーのwp-config.phpに不適切なパーミッション(たとえば644)を設定してしまった場合。
ロリポップのWordPressインストール手順にはインストール後のパーミッションの変更が記載されていなかったので、ユーザーはそうと気付かずに、インストーラが設定した不適切なパーミッションのまま運用していた、と考えられる。

WordPressの簡単インストール機能がどのように動作するのか、現在その機能が無効化されていて確かめることが出来ないが、ほぼ同様の動作をするだろうMovableTypeの簡単インストール機能は有効で、自動的にDBアカウントとパスワードが記入される mt-config.cgi のパーミッションは644のままだった。ユーザー権限でCGIを動作させている共用サーバでは通常、400(所有者のみ読み出し可能)に変更するはずだ。
wp-config.php のパーミッションを400にする必要があるのに、同じ方法でDBに接続するMovableTypeは変更する必要が無いというのが不思議なところだ。二次被害を引き起こした可能性がある以上、WordPressにかぎらず全てのインストール機能は無効化して、全てのファイルのパーミッションの再確認をするべきだ。


上記の推測があたっているとすると、ユーザーが強固なパスワードを使っていて、手順通りに最新バージョンで運用していても、脆弱なユーザーの二次被害を受けることになる。
(追記)
各サーバーで最初に侵入されたアカウントへが侵入経路がWordPressの脆弱性であろうと、それ以外であろうとも関係は無い。
(/追記
thx:名無しさん

ユーザー側でとれる対応は、
・wp-config.phpやmt-config.cgiなど、同一サーバーの他のユーザーに見られては困るファイル(管理パスワードやDBパスワードを記述したファイル)のパーミッションを400に制限する(脆弱なユーザーからの二次被害対策)
・手元のバックアップと現状のファイル・DB内データを比較し、改竄があればバックアップから復元する(バックドアや不正なリンク設置への対策)
・DB接続用パスワードも強固なものに変更する(対応するwp-config.phpの記述も変更する)


現状のロリポップの記載内容では、改ざんされたウェブサイトの所有者全員が脆弱なWordPressプラグイン・テーマを使っていたかのように書かれている。WordPress以外のCGIスクリプトにも同じ問題が起きていないかのチェックがなされていない、というのは問題だと思うのだが。
posted by ko-zu at 00:30| Comment(2) | TrackBack(0) | セキュリティ | このブログの読者になる | 更新情報をチェックする

2013年08月22日

OpenIDの仕組み・安全性と危険性

少し思う所があってメモ

OpenIDが出来る事

ユーザーが「あるOpenIDプロバイダにアカウントを持っていること」をウェブアプリに証明する

基本的にはたったこれだけ。OAuthとの違いウェブアプリに何らかの権限や、ランダム生成された識別子以上の情報を渡すことはない。

OpenIDログインを利用するウェブアプリ(リライングパーティー)が知ることができるのは
・ユーザーがどのプロバイダのIDを持っているか
・ユーザーの所有する識別子(乱数)

OpenIDを発行する側(OpenIDプロバイダと呼ばれる)が知ることが出来るのは、
・ユーザーがどのウェブアプリ(リライングパーティーと呼ばれる)にアクセスしたか

だけになる。正しく実装されたOpenIDでは、OpenIDプロバイダにどのような情報が登録されているか(メールアドレスやパスワードなど)は、リライングパーティにはわたらない


仕組み
OpenIDではおおよそ次のような認証手順をふむ。

ユーザーがリライングパーティのウェブサイトにアクセスする。

ユーザーが「OpenIDでログイン」を選択
= ユーザー→リライングパーティ「私はとあるプロバイダが発行したOpenIDを持っています」

リライングパーティはブラウザをOpenIDプロバイダのページへリダイレクトする
=リライングパーティ→ブラウザ「問い合わせメッセージを渡すので、それに署名してもらってきてください」

ここからブラウザはOpenIDプロバイダのページを表示する

ブラウザはリライングパーティが発行したメッセージへの署名要求を送る
=ブラウザ→プロバイダ「このメッセージに、アカウントを持っていることを証明する署名をください」

OpenIDプロバイダはOpenIDプロバイダ自身のログイン画面を表示する
=OpenIDプロバイダ→ユーザー「あなたは誰ですか?」

ユーザ―はOpenIDプロバイダでのIDとパスワードなどを入力する
=ユーザー→OpenIDプロバイダ「ユーザーID foo、パスワードbarです。」

OpenIDプロバイダはユーザーへの確認画面を表示する
=プロバイダ「このウェブアプリ(リライングパーティ)に対してあなたの識別子を証明していいですか?」

ユーザーがOKをクリック

OpenIDプロバイダはメッセージへの署名と識別子をブラウザに渡す
=プロバイダ→ブラウザ「この署名と識別子を持ってリライングパーティのページに行ってください」

ここからブラウザはリライングパーティのウェブページにもどる

ブラウザは署名済みメッセージをリライングパーティに送る
=ブラウザ→リライングパーティ「このOpenID識別子をもっている事を証明します」

リライングパーティはサードパーティの署名を検証して、識別子とユーザーを紐つけて保存する。

これでリライングパーティは、「ユーザーがOpenIDプロバイダにアカウントを持っていること」と「ユーザーの(ランダム生成された)識別子」を保証できる。

OpenIDプロバイダに保存されている情報は、ユーザーの識別子以外、なにも漏れていない。例えば、Google発行ののOpenIDを使っても、GmailアドレスやGoogle+アカウントの個人情報が漏れることは無い。

具体的方法は
http://openid-foundation-japan.github.io/openid-authentication.html
に日訳があった。


OpenIDの問題点
現在普及していないことから分かるように欠点もある。

2つのウェブアプリの間での紐付け
古いOpenID実装では、ユーザーは一つのOpenIDプロバイダにたった一つだけ固有の識別子をもつ。つまり、2つのウェブアプリが提携すると、それぞれにログインしたユーザーが同一人物であることをOpenID識別子が一致することから知られてしまう。(もっとも、サードパーティクッキーやIPアドレスによる追跡の方がずっと強力だが)

OpenIDプロバイダはこの問題に、リライングパーティ毎に個別の識別子を生成することで対処できる。つまり、あるウェブアプリAにユーザーfoobarがログインする時にはOpenID識別子として123456を返し、ウェブアプリNには7890123、というふうにしてしまえば、識別子から紐付けされることはない。OpenID2.0では、ユーザーはOpenIDプロバイダの名前さえ覚えておけば、識別子はOpenIDプロバイダが自動生成してくれる。


ユーザーの誤認・フィッシング

OpenIDを実装すると、異なるウェブサイト間をリダイレクトで自動的に移動することになる。これはユーザーを混乱させる元になる。

悪意あるリライングパーティは、OpenIDプロバイダにリダイレクトしたと見せかけて、プロバイダのログイン画面を模倣したフィッシングサイトにユーザーをリダイレクト出来る。
直接的な対処法がなく、ユーザーにフィッシング対策の知識が一定以上有ることを期待するしかない。OpenIDプロバイダになる=フィッシングリスクを高める事になり、一般向けに開放することが難しい。

逆向き(OpenIDプロバイダからリライングパーティ)も同様で、信頼出来ないOpenIDプロバイダが、リライングパーティを模倣したフィッシングサイトを作ることで、ユーザーがリライングパーティにポストしようとした内容を詐取する可能性がある。

OpenIDを導入するにあたっては、リダイレクト前後に特徴的なページ(例えば、ユーザ専用のアイコン画像や背景色など)を挿入するなど、ウェブサイトの識別性を高めるフィッシング対策をとる必要がある。
例えば、Yahooはログイン画面に好きな画像を登録できる。


OpenIDプロバイダの信頼性
OpenIDプロバイダが侵入されるなどで、認証システムが乗っ取られると、そのOpenIDを利用してログインしている全てのウェブアプリが同時に脅威にさらされる。
OpenIDの原理上、OpenIDプロバイダにはどのリライングパーティにアクセスしたかの履歴が残るので、侵入に成功した攻撃者は入手したOpenIDでどのウェブサイトにログイン出来るか瞬時に分かってしまう。

通常のパスワード漏洩では、他のサイトはログイン失敗したパスワードのパターンを調査することで、漏洩リストによる攻撃の徴候を検出することが可能だが、OpenIDプロバイダ自体の脆弱性ではそもそもログインに失敗することが無いので、不正ログイン検出が難しくなる。

対処法としては、プロバイダの脆弱性が発覚した時点でリライングパーティ側は該当するOpenIDプロバイダのユーザー全員をログアウトさせ、OpenIDプロバイダの信頼性が復旧した後にログインし直す事を要求する。


OpenID認証の代替手段
OpenIDプロバイダがクラックされた場合、上記のように一時的とはいえリライングパーティ側は、そのOpenIDプロバイダを利用した認証を無効化する必要に迫られる。(念の為、OpenIDプロバイダ側に総パスワードリセットなどの復旧手段があれば、アカウントが完全に失われることは避けられる) ユーザー認証を完全にOpenIDに頼っている場合、その間ユーザーが安全にログインする手段がなくなってしまう。

リアルタイムのアクティブアユーザー数が直接利益に関わるウェブアプリでは、アカウントを失うリスクを減らすために、リライングパーティ側でも、ユーザーのメールアドレスなど、ユーザーへの信頼出来る到達手段を用意しておく必要があり、これはOpenIDの利点を相殺する。


サードパーティ認証との識別性
OpenIDそのものの認知度が低く、単なるサードパーティ認証やOAuthとの違いがユーザーに理解されていない。
そのため、メールアドレス漏洩やアカウント機能の不正利用についての懸念がOpenIDの利用を阻害する。
ラベル:OpenID
posted by ko-zu at 00:41| Comment(0) | TrackBack(0) | セキュリティ | このブログの読者になる | 更新情報をチェックする

2013年08月11日

TLS1.0クライアントライブラリでCBCを使えるか考えてみるメモ(訂正版

TLS1.0のクライアントを何とかBEAST対策させる方法として。
# なんでこんな事を検討してるんだとかはあまり考えたくないのでやめておく
# ブラウザではないのだけど

そのままランダムバイトシフトによる方法は効率が悪い。というのを昨日気づいていなかったので訂正を兼ねて。

CBCでは
平文ブロックの列 ..., Pn-1, Pn , Pn+1, ...
暗号ブロックの列 ..., Cn-1, Cn , Cn+1, ...
に対して、
E( Cn-1 ^ Pn) = Cn
がなりたつ。

BEASTでは
(1) 攻撃者はブロック境界を制御できる
(2) ある平文ブロックPxに秘密情報が1バイト含まれ残りの部分は知っている
(3) かつある暗号ブロックCn-1に対して、次の平文Pnを制御できる
(4) 次の平文Pnを攻撃者が決定する前に、Cn-1とそれ以前の暗号文ブロックを傍受済み
を組み合わせる。

攻撃者はPxブロックの暗号文Cxを傍受できるが、直接残りの1バイトを計算することはできない。そこで攻撃者はセッションを再利用して平文Pnで始まるリクエストを発行する。
このとき、次の平文Pnとしてブラウザに送らせるべき内容は、想定している256種のPxの一つ Pxi (i= 0...255)について、Cn == Cxを仮定して、Pn ^ Cn-1 == Pxi ^ Cx-1 から、Pn = Pxi ^ Cx-1 ^ Cn-1 と計算できる。(4)からCn-1を傍受できるので、Pnを計算するための不確定要素はPxiの256通りのみになる。

Cn が予想通り Cxと一致すれば、 Pxiが正解だったことが分かる。失敗であれば、盗聴した最後の暗号ブロックを新たにCn-1として、次のPxiを調べていく。つまり平均128*トークン文字数程度の連続リクエストができればPxiから衝突を発見できる。トークンが事前にhexとわかっていれば、平均8リクエスト*トークン文字数ですむ。


TLS1.1以降で導入されるIVの強制的な更新では、暗号鍵・セッションを再利用する場合、新しいリクエストでは以前の暗号ブロックCn-1を使わず新しいIVにすることで、バイトごとの総当りを不可能にする。つまり(4)を防ぐ。攻撃者は新しいIVを事前に知ることが出来ないので、適切なPnを生成できない(Cn-1が足りない)。

TLS実装側から言えば、CBCモードの暗号器を使うなら、平文入力をバッファして次の平文ブロックPnが確定するまで直前の暗号ブロックCn-1の出力をブロックし、平文バッファをフラッシュしてMACを送った後はIVを変更することで、(4)が成立しないことを保証する。


TLS1.1に対応したクライアント・サーバーならこれでいいが、CBCがデフォルトのままのサーバーと、TLS1.0クライアントライブラリを使わなければならない場合を考える。

まずTLSセッションを毎回破棄してしまう方法があるが、keep-alive必須とされているし、お互いにあまりにも効率がわるい。
openssl実装は設定によってはパディングを送信できるようだが、少なくとも(TLS1.0しかない)1.0.0でがデフォルトにはなっていないようだ。

クライアントだけで出来る一つは、冗長なリクエストを送ることで、IVの更新に替える。たとえば、全てのリクエストの前に、/へのHEADリクエストを送るなど。続くjavascriptで生成されたリクエストはHEADリクエストの最後の暗号ブロックをIVとして使うので、攻撃者はPnを生成できない。なおN回に1回HEADを送るのでは、攻撃を'(N-1)/N倍に遅くすることしか出来ないのでほぼ意味が無い。

これらはいずれも(4)を防ぐことでBEASTから守る。


一方、追加ヘッダで可変長の乱数列を追加する方法は、攻撃者がPxの状態を知ることが出来るという前提を崩す方向を考える。つまり(2)のPxの特定を難しくする。これははっきり行って効率が良くない。

乱数列の長さが不明なので、攻撃者はPx候補の前の暗号化ブロックCx-1を複数のブロックから見つけ出す必要がある。
これが成功する確率は、乱数列のバイト数をkとし、秘密が1バイトだけで左15バイトが既知なら、1/kになる。よさそうだが、2バイト目への攻撃もまた1/kで推定できてしまう。つまり困難性はk/2倍程度しか上がらない。

200バイト可変シフトさせて、突然クライアントからのリクエスト数の桁が100倍も増えれば、流石にレートリミットが効くだろうけれど、全体平均してk/2倍にしかならないので暗号としては余裕が無い。もっとも、Cookieに保存するトークンの長さを(k/2)倍にするのと同じだけの効果がある、という意味では大きい。

バイトシフトによる対処では足りないなら、秘密情報の位置をシフト「させない」必要が出てくる。同一ブロックに3〜4バイトも秘密情報が含まれれば、総当りは急激に難しくなる。つまり(2)の不確定要素を2バイト以上にする。
だがこれはjavascriptがcookieをセットできるのでうまく行かない。javascriptで重要なトークンより前に別のキーをセットしたり、長さを変更できてしまう。


結局のストリーム暗号としてのCBCモードの限界として、クライアント側で使えそうな防御手段はあまりない。
弱い暗号やCBCを強制するサイトからは都度ログアウトする、くらいか。
posted by ko-zu at 10:17| Comment(0) | TrackBack(0) | 日記 | このブログの読者になる | 更新情報をチェックする

2013年08月10日

サーバー側・クライアント側でのBEAST/CRIME系攻撃への処方メモ

今更過ぎるけれど、centos6.xのopensslがまだ1.0.0でTLS1.1非対応という現実に直面したので回避方法を考えてみるメモ。

(追記:ブラウザ側でのハックの困難性があまりに甘かったので困難性を追記。)


BEASTやCRIME攻撃として提案された手法の本質は、同じ秘密情報を含むHTTPSリクエストをたくさん発生させることで、SSL圧縮ブロックや暗号ブロック境界の選択平文攻撃によって、秘密情報を1バイト単位で少しずつ盗むというものだ。
http://j-net21.smrj.go.jp/develop/digital/entry/001-20120229-01.html
CRIMEなら例えば、リクエストに適当な文字列を1バイト追加して、SSL圧縮が起きればそのバイトが秘密情報に含まれる事が分かる。これを繰り返して、秘密情報全体を決定していく。
http://www.scutum.jp/information/waf_tech_blog/2012/09/waf-blog-014.html

攻撃に必要なたくさんのHTTPSリクエストを発生させるには、別個にブラウザやそのプラグインの脆弱性などを必要とする。(追記:原理的にはscriptタグなどで外部ドメインから直接叩く、というのはアリそうだけど、正しく外部呼び出しがコントロールされたHTTPSサーバーなら回避できるはず)つまり、javascriptやRefreshなどの悪意あるリクエストを生成するコードをブラウザに注入できるものの、クッキーのhttpsonlyなどによって、スクリプトだけでは秘密情報を取得できない場合を対象にしている。
また、囮無線LANアクセスポイントなど、パケットキャプチャ(少なくともパケットのサイズやタイミングの推定)が容易にできることも前提になる。

提案されている攻撃では、バイトシフトや圧縮を利用して最大256通り・平均128通りのリクエストを試すことで、1バイトの秘密情報を奪うことが出来る。実際にはCookieなどの秘密情報はBase64やhexで書かれている事が多いので、最悪だと平均8回で4bitの情報が漏れることになる。
秘密情報がSHA-1 160bitのhexなら、わずか320クエリ程度で完全に特定できるので、単純にリクエストの頻度によってサーバーサイドでフィルタする方法では、ブロックする閾値が低すぎて通常利用に差し支えるだろう。


サーバー側HTTPSプロトコルでの対応
対処法としては、HTTPSサーバーの設定で、CBCモード暗号を使わず、SSL圧縮を無効にすれば、今知られている手法に対しては一応対応できる。ただし、圧縮やタイミングをサイドチャネル攻撃は様々なレイヤー・状況下で発生するので、完全に防ぐのは無理かもしれない。対症療法的に、暗号にCBCを使わないRC4を使うというものもあるが、それは暗号強度の面で問題が有る。
http://tetsutalow.hateblo.jp/entry/2013/04/02/053927


サーバー側アプリケーションでの対応
一方、アプリケーションレベルでCRIMEを含む圧縮率やタイミングによるサイドチャネル攻撃の排除方法としては、秘密情報を毎回変化させてしまう、という方法が挙げられる。
これらの攻撃手法は、秘密情報が少しずつ漏れるという特徴があるので、クライアントに保存するログイン情報を、毎回サーバー側で自動生成してしまう。
ただし、Cookie送信自体はクライアント側だけでパイプラインして複数回行えるので、リクエストとレスポンス到達の時間差によっては、サーバーが攻撃を検知してクッキーを再設定する前に攻撃を終わらせられるような改良手法が出てくるかもしれない。


クライアント側HTTPSでの対応
CBCモードでTLS1.0がIVを使いまわす事を利用したBEAST攻撃は、接続の切断や無効なリクエストの付加でIVを定期的にリフレッシュすることで対処できる。また、SSL圧縮に対応させないことで、既知のCRIMEに対処できる。

SSL/TLS実装が改修されていない、あるいは密結合していないブラウザの場合、HTTPクライアント側で、ゴミデータをリクエストに追加するという方法も考えられる。

一つは、GETやPOSTに先行して /favicon.ico (ドキュメントルート)など へのHEADリクエストを挿入してしまう方法。
HEADリクエストは副作用が無いので、404でも200でも構わない。これでIVを挿入したリクエストの末尾の暗号ブロックにリフレッシュ出来る。

もう一つはランダムな内容とある長さの独自HTTPヘッダを秘密情報の前後に挿入すれば、バイト境界を利用するタイプの攻撃は排除できる 難しくなる。たとえば
X-NONCE-1: ランダム長さの乱数列
Cookie: xxxxx;
X-NONCE-2: ランダム長さの乱数列
というように、ブラウザがランダム長の乱数で秘密情報の位置をシフトしたり、圧縮辞書を変化させてやれば、攻撃したいバイト境界がリクエストの度に変化するので、攻撃を著しくある程度困難に出来る。(追記、ただバイトシフトするのではBEASTは1/可変長にしかならない。圧縮系には意味があるが)

ブラウザはどれが秘匿すべき情報なのかアプリケーションの詳細を知らないし、独自ヘッダではクエリ文字列にセッション情報を保持するようなアプリケーションには対処できない(ただjavascriptを注入された時点でクエリ文字列は取得されているはず)、といった問題はあるけれど、この手法はSSL実装をOSに依存した軽量なブラウザや、ブラウザの追加アドオンなどでできるので、BEAST等に脆弱だが改修できない古いHTTPSサーバーやクライアントライブラリに対して、ユーザーやブラウザアプリ開発者の対抗手段時間稼ぎとして利用できる。



サーバー側のopensslバージョンによる制限
クライアント側が完全に実装されるまで、現時点ではサーバー側で、TLS1.1以降やGCMモードなどのバイトシフトによる攻撃が難しいモードを使い、SSL圧縮を無効にするといった方法で対処することになる。
ところが、そのために必要なopensslは1.0.1以降で、まだ数の多いRHEL6.xではいまだ1.0.0のため、互換性を捨てて1.0.1以降にするか、TLS1.0のRC4しか回避する手段がない。そしてRC4にもまた脆弱性が見つかっている。

1.0.1以降が入っているなら、TLS1.1以降を有効にしているクライアントに対しては、RC4のような古い暗号を優先せず、AES-GCMなどを用いるべき。


秘密情報のないサービス
これらの攻撃は秘密通信をリークするだけなので、秘密情報を扱わないアプリケーションには影響しない。
フリーソフトウェアの静的な配布サイトのように、誰でも匿名でダウンロード出来る情報しかないウェブサイトなら、漏れて困る情報はない。
HTTPSでダウンロードした内容やHTTPSのウェブサイトに記載されたソフトウェアの証明書フィンガープリントが改ざんされている、ということは上記の手法では考えにくい。

結局自分のアプリ配布用サーバーはRC4ということで妥協しておく。

nginx設定メモ
    ssl_prefer_server_ciphers on;
    ssl_protocols       SSLv3 TLSv1 TLSv1.1 TLSv1.2;  #実際にはTLSv1.1以降使えていない
    ssl_ciphers  AESGCM:RC4:HIGH:!MD5:!aNULL; #RC4以降しか使えていない
    # AESGCMと省略出来る事に気づいたので変更

SSLチェック https://sslcheck.globalsign.com/ja/sslcheck?host=app.usb0.net
ラベル:Beast crime CentOS
posted by ko-zu at 11:05| Comment(0) | TrackBack(0) | セキュリティ | このブログの読者になる | 更新情報をチェックする

2013年08月08日

オンラインサービスパスワードとストレージのパスワードと端末ログインパスワードの違い

徳丸氏による徳丸氏への取材ブログ「パスワードの定期的変更について徳丸さんに聞いてみた」
(1) http://blog.tokumaru.org/2013/08/1.html
(2) http://blog.tokumaru.org/2013/08/2.html
前後の反応を見ていて、オンラインサービスのパスワードの話と、ストレージのパスワードや端末のログインパスワードの話が混同されていることが多いように思われた。
どれもパスワードと呼ばれることがあるが、必要な強度や性質の違いに留意していれば、/etc/passwdやNTログインキャッシュと、オンラインサービスのパスワードの話が同列に語られるはずがない。


オンラインサービスのパスワード
=短期間総当りされない程度に強い鍵を使う

・サービス側が攻撃を検知できるので、攻撃者がサービスへの侵入なしに総当りするのは事実上不可能
・通信経路はずっと強い鍵で暗号化されているので、盗聴は考えなくていい(HTTPSでないウェブサービスは、あなたの安全のためではなく、最も簡単な個人識別方法としてパスワードを用いているだけ)
・サービス側からの漏洩が起きる確率は、ユーザーがパスワードを変えても変化しない
・生のパスワードが漏れた場合、実際の攻撃に利用されていないなどあり得ないので、パスワードを後から変えても意味が無い
・パスワードのセキュアなハッシュが漏れても、少なくとも数日〜数ヶ月はパスワードが逆算されることはない
・ハッシュが漏れたことに直ちに気づかないサービスが、保護するべき情報が漏れていないことを保証できると考えるべきではない

→ 12〜20文字程度(だいたい70~120bitくらい)のパスワードをランダム生成して、ブラウザなどに保存する。もしハッシュが漏れたとニュースがあれば、即座に変更する
→ 端末の紛失、フィッシングや、野良アクセスポイントの利用など、ユーザー側責任での漏洩に注意する


通信・ストレージの暗号化パスワード
=盗聴されることを前提にした、長期間総当り不能なとても強い鍵を使う

・攻撃者は盗んだ暗号文を保存して秘密裏に総当りできるので、十分な強度が必要
・「鍵と暗号方式の耐久年数」- 「情報が価値を持つ期間」 = 「同じ鍵を使っていい期間」 なので、新しいデータのための鍵を定期的に変えることには意味がある
・古い鍵で暗号化したストレージを、そのまま新しい鍵で暗号化し直すことは意味が無く、しばしばより脆弱になる(古い暗号文が絶対に漏れていないことを保証できるなら別だが、それなら暗号化の必要がない)
・通信や大容量データ暗号化ならAES-GCMの128bit以上が推奨 http://www.cryptrec.go.jp/images/cryptrec_ciphers_list_2013.pdf

→ 最新のブラウザを利用する。ただし紛らわしいドメイン名でのフィッシングには注意が必要
→ TrueCryptなどのデータ暗号化ソフトは短すぎる鍵を警告してくれる(警告がでない暗号化ソフトは見せかけだけで、正しく暗号化してない可能性が高い)


ブラウザのマスターパスワード、PCのログインパスワード、スマートフォン端末のPINコード
=弱い鍵と物理的にアクセスさせないことの組み合わせ

・パスワードと呼ばれるが、実体はログインユーザーの秘密情報を暗号化するための鍵
・通常入力できるパスワード・PINだけでは鍵として弱すぎるので、物理的にアクセス出来ない状況という前提を組み合わせて擬似的に強度を高めている
・暗号文=端末そのものが盗まれれば簡単に総当りできるので、盗まれない対策が必要
・保護したいデータはほどんど変化せず、IDや個人情報のように後から変更できないものが多いので、端末を紛失したら暗号文が漏れないように、リモート削除する
・暗号文は漏れていない(端末は盗まれていない)ことがわかっているが、盗み見などでパスワードだけ漏れた場合がありうるので、パスワードを定期的に変えることは意味がある

→ 最新のOSとブラウザとセキュリティソフトを利用し、端末のストレージから暗号文が盗まれないよう注意する
→ リモート削除機能を用意して、紛失に気づいたら即座に削除する(=バックアップする)
→ リモート削除できない携帯用のメディアやノートPCは、TrueCryptなどでストレージを暗号化して、強いパスワード(20文字で約120bit)を利用する


漏洩に気づかない場合
ユーザーの不注意などでパスワードが漏れたのに、そのユーザーが気づかないかもしれない、だから、パスワードは変えたほうがいい、ということは有りうる。しかし、漏れる頻度よりずっと高い頻度でパスワードを変えないと意味がない
端末のパスワードでは端末そのものを入手できないとパスワードを悪用できないが、オンラインサービスへは誰でも匿名でアクセス出来てしまう。オンラインサービスへの攻撃は自動化されているので、ほとんど一瞬にしてパスワードで保護されていた全情報が漏洩してしまう。

高頻度のパスワード変更を人力でやるのは不可能なので、トークンによって自動生成されるワンタイムパスワードなどが利用されている。トークンの中には電子証明書が入っていて、人間が入力できるパスワードよりずっと強度が高い。それがたった6桁の数字に見えたとしても。


結局、
・オンラインサービスでは、安全な暗号通信で利用しているなら定期的にパスワードを変える利点は無い(ワンタイムパスワードは例外)
・物理的なストレージや端末のパスワード・PINコードは、可能な限り強くし、定期的にパスワードを変えることには意味がある
・利便性のために弱いパスワードしか使えない端末は、紛失時のためのリモート削除機能を利用する
ラベル:暗号論
posted by ko-zu at 21:38| Comment(0) | TrackBack(0) | セキュリティ | このブログの読者になる | 更新情報をチェックする

2013年08月05日

Android OSでの主な通信ブロックアプリの動作方式

Androidスマートフォンでのアプリの通信をブロックするアプリの動作原理分類

プロセスID/iptables方式
低負荷・アプリ別・root必須
・DroidWall https://play.google.com/store/apps/details?id=com.googlecode.droidwall.free&hl=ja

アプリごとにiptables(AndroidOSのベースのLinuxに組み込まれているファイアーウォール)でフィルタする。
iptableを制御するためにroot化が必要で、アプリのIDからフィルタルールを動的生成するために、常駐して実行中アプリを監視する必要がある。原理的に起動直後の通信を取りこぼす場合がある。

フィルタリング自体はAndroid自体アプリではなく、OS側が行なってくれるので、CPU負荷は少ない。
接続先や内容でフィルタすることも不可能ではないが、iptablesのルール数・ルールの表現力的に面倒。
最近の機種はiptablesへのアクセスをSelinuxで(rootでも)禁止しているものがあるため、単なるroot化でなくブートローダーアンロック・カーネルパッチなどが必要なことがある。


HTTPフィルタプロキシー方式
高負荷・URL別・一部はroot要求
・FilterProxy https://play.google.com/store/apps/details?id=com.googlecode.droidwall.free&hl=ja
・AdBlock Plus (android 3.0以前) https://adblockplus.org/en/android-about

端末内にHTTPプロキシを作成・設定してブロックする。機種によっては全アプリに対してAPNの共通プロキシ設定ができるものがあるが、それ以外ではroot化が必要。HTTPを通さない他のプロトコルの通信に効果はない。
HTTPのレイヤで動くので接続先ホスト名やURLのパス、ファイル内容でもフィルタすることが可能。(ただしHTTPSはホスト別でしかできない。)プロキシサーバーとして動く常駐アプリが必要。HTTPを解釈する必要があるので他よりも高負荷。
原理的には、アプリの通信をデフォルトでブロックしたり、アプリ別ルールも作れるはずだが、今のところそのような実装はなさそう。


hostsファイル方式
負荷なし・ホスト別・root必須
・AdAway  https://f-droid.org/repository/browse/?fdid=org.adaway

ブロックしたいホスト名のIPアドレスを127.0.0.1などに上書きするhostsファイルを利用する。
事前にホスト名さえわかっていればプロトコルやアプリによらず、そのホスト名での全ての通信を遮断できる。
逆に、AdAway対策にホスト名を使わず、IPアドレスがハードコードされたアプリやホスト名が変化するような場合には効果がない。アプリ別のルールを設定することは出来ず、未知の新しいアプリをデフォルトで遮断することは出来ない。

OS側が行なっているドメイン名解決を上書きするだけなので、アプリが常駐して負荷が増加することもなく、実際の通信にアプリが関与することはない。


カスタムVPN方式
中負荷・アプリ別・root不要
https://play.google.com/store/apps/details?id=com.netspark.firewall&hl=ja
https://play.google.com/store/apps/details?id=app.greyshirts.firewall&hl=ja

Android4.0で導入されたカスタムVPN実装用APIを利用して、全てのアプリの通信を中継する。
ソケット単位で制御できるので、アプリ別・IPアドレス・ポート別でフィルタ出来る。ただしホスト名でフィルタは出来ない。
なお、ホスト名でフィルタできるというNoRootファイアウォールはIPアドレスからホスト名を逆引きしているため、正引き(見かけのドメイン名)ではフィルタ出来ない。また接続の度に逆引きするため接続開始時の遅延が大きい。

サービスとして常駐が必要だが、ソケットを開く時点で切断できるため取りこぼしがない。送受信の全てがAndroidアプリを経由するため、HTTPプロキシ程ではないにせよ、通信量に応じて負荷は増える。
原理的には通信の中身を読めば、(CPU負荷が大きいが)URLでもフィルタ出来るだろうが、そのような実装はまだないようだ。
(なおVPN利用中はテザリングができなくなる現象をAndroid4.3+norootファイアーウォールで確認)



ブラウザ拡張・userscripts方式

低負荷・一部のブラウザ
FirefoxやOpera、Sleipnirなどのブロック拡張
javascriptでHTMLの要素単位でブロックする。ブラウザに表示されるものであればなんでも自由に制御できる。
当然だが他のアプリに対しては機能しない。
当然そのブラウザ内でしか機能しないので、他アプリの通信を制御することは出来ない。


カスタム外部プロキシ
負荷なし・一部機種でroot化必須
自宅サーバーなどにフィルタを組み込んだHTTPプロキシを立てるなどして、スマートフォンの外でフィルタする
HTTPプロキシを外に置くためCPU負荷は無いが、HTTPにしか効かない。
副次的に圧縮機能(Operaの高速化機能など)を付けることが出来る。


カスタムDNSサーバー
負荷なし・WiFiならroot化不要・3G/LTEなら必須
hostsファイルの代わりに、DNSサーバーでドメイン別にフィルタする。
自作のWiFi AdBlockerはこのタイプ。実際の通信を中継する必要がないため、負荷も増えない。


通信機能が不要なアプリをアプリ単位でブロックするならカスタムVPN方式(Android4.0以降)。root化可能ならhostsファイルを追加することで大抵の不要な通信をブロックできるだろう。 個人的には、hostsファイルだとリスト化が不十分なのでカスタムDNSサーバーを使っている。

念のため、いずれの方式も、利用している通信ブロックアプリ自体が通信を傍受することが原理的に可能なので、通信ブロックアプリを使用中は重要な通信にはHTTPSなどで暗号化しておく必要がある。
posted by ko-zu at 01:30| Comment(0) | TrackBack(0) | Android | このブログの読者になる | 更新情報をチェックする