2012-03-05

github の mass assignment 脆弱性が突かれた件

dev

気になって調べたのでメモ。自分も気をつけないとなー。

github に脆弱性があってそれが突かれたらしい。 Rails アプリにありがちな脆弱性の一つ、Mass assignment とかいうタイプの脆弱性である。

mass assignment 脆弱性とは

mass assignment 脆弱性とは何か、というのは以下の記事が詳しい:

Rails 3.1 の新機能解説の記事だが、機能拡張の解説であって attr_accessible などは 3.1 より前からある。 要するに、モデルのメソッド update_attributesnewHash でデータを渡した時 attr_accessible (attr_protected) で指定した カラムについては無視されるようにするという機能である。

update_attributes とは: ActiveRecord のモデルで、カラム名がキーとなった Hash を渡す事でデータを更新できるメソッド。foo.update_attributes(:title => "New Title") のように使います。 scaffold で生成されたコントローラの update アクションなどで使われていて、scaffold では update_attributes(params[:foo]) のようにパラメータが直接渡されています。

そして、update_attributes に HTTP のパラメータ params (Hash) を特にチェックせず直接渡して、 その params に本来更新されるべきではないカラムのパラメータが含まれていても更新されないようにするために attr_accessible, attr_protected をモデルで定義しておく事によって、update_attributes 等のメソッドにパラメータを渡しても、attr_accessible (attr_protected) で保護指定したカラムについては渡した Hash で指定されていても無視されるようになります。

上記のこの記事での例を引用すると、

attr_accessible :name とした事によって, ホワイトリスト方式で :name カラム以外は無視されるようになるため、 User.new:group_id を指定していてもそれは無視されている事がわかるかと思います。

さて、この機能を使っておらず保護されていないカラムがあると何故脆弱性になるかはもう分かると思いますが、

たとえば実際にこのモデルを用いた Web アプリケーションがある時に、Web のインターフェースでは更新時に update_attributes を特にパラメータをチェックせず直接 params を渡していて、 ユーザー (Web インターフェース) からは group_id を変更できないという事にします。

すると、 もし attr_accessible :name が無い場合 、Web インターフェースの update_attributes を呼んでいる所が、 Web インターフェースでは更新できるべきではない group_id を含んだパラメータを受け取ると 更新できるべきではない group_id が更新できてしまいます。

しかし attr_accessible :name がある事によって、update_attributes:group_id を含んだ Hash (パラメータ) が来ても無視されるので変更される事は無いのです。

そのため、attr_accessible で明示的に「変更可能なカラム」を指定しておくのは重要で、これを指定していない事によって 更新されるべきではないカラムも更新することができる 脆弱性が mass assignment 脆弱性です。

しっかりホワイトリスト方式の attr_accessible で指定する事が一番安全でしょう。

update_attributes はいちいち user.name = params[:user][:name] 等としなくても Hash のキー・値でデータ (レコード)を更新できる 機能で便利なため、

update_attributes 以外にも new, create でもその保護は働くという事もあり、attr_accessible, attr_protected で保護するのが安全だと思います。

これは ActiveRecord を使ったアプリケーション (大半の Rails アプリケーション) は多く存在する可能性がありますが、 Mongoid でも同様の脆弱性が発生することがある そうです。

重要: これは Rails の脆弱性 ではなく Rails の問題 である。mass assignment 脆弱性に関しては Rails アプリケーション (もしくは ActiveRecord を使ったアプリケーション) において開発者が作りやすい脆弱性であるから。すぐ後述する Issue #5228 についたコメント (2段落目) にも書いてある。__Rails の問題__ というのは、現在の scaffold generator や ActiveRecord がこの問題を発生させやすいため、Issue 5228 では発生しにくくなるような対策を検討している。

今回の発端

さて、そこでこの github/rails/rails に登録された issue を見てみよう。今回の問題の発端である。

この issue で問題に上げているのは、現在の Rails は、開発者が mass assignment 脆弱性を発生させやすい (attr_accessible 等の存在とこのような脆弱性を知らないと) ということ。

そのため、attr_accessible 等の指定を開発者に強制したりする等して、発生しにくくする案を探している。

(その後、いくつかの案が複数人によって挙げられているが今の議論、何が提案されているかまではこの記事では取り扱わない為、 issue ページを参照してください (それを見て、コメントするのも良いでしょう))

はじめは速攻で reject された。既にデフォルトで有効にする pull request があり (Pull Request #4062) それが reject されているからだ。

もちろん homakov さんは反論している。「ホワイトリストを必須にするのではなく、たとえばデフォルトで foreign_key, primary_key をブラックリスト入りさせておくのはどうか」 と。

(メモ: 一度は reject されましたが、現在は議論が再開されています)

脆弱性の問題を例示

そして、reject が繰り返されるとこのような issue が open される:

what?

作成日時を示す部分を見て欲しい。"in 1001 years" とある。未来ですね。おそらく github が抱えている mass assignment 脆弱性をつついたのだろう。GitHub を使って例示してしまった。

たぶん created_at 等をパラメータに含ませて自分の指定した値に created_at を変更したのだろう。

そして彼はさらに別の所にある脆弱性もつつく:

hacked

一番最初に上げた github の blog の記事でメインに言及されている脆弱性がこれである。

At 8:49am Pacific Time this morning a GitHub user exploited a security vulnerability in the public key update form in order to add his public key to the rails organization. He was then able to push a new file to the project as a demonstration of this vulnerability.

(日本語訳: 8:49am (Pacific Time) に GitHub ユーザーは SSH 公開鍵の更新フォームに存在する脆弱性を攻撃し、彼の公開鍵は rails organization に登録された。そして彼は rails/rails プロジェクトに新しいファイルをコミットする事ができた、この脆弱性のデモとして。)

organization account も実は SSH 公開鍵を登録する事ができるので、たぶん SSH 公開鍵の更新のフォームで SSH 公開鍵のモデルにある user_id といったカラムを推測してパラメータに含ませ、pubkey を update したのだろう。どうやって account 側の primary key を取得したんだろう?

このように GitHub 等もうっかり mass assignment 脆弱性を抱えてしまう事から、デフォルトでいくつかの key をブラックリスト入りさせようと提案した訳である。まだこの issue は議論が続けられている: Issue #5228: Mass assignment vulnerability - how to force dev. define attr_accesible? · rails/rails

どのようにしてこの脆弱性の発生を防ぐか。現状だとユーザーが attr_accessible 等を手動で定義しないと、ユーザーがこの脆弱性の存在を知らない限り容易に発生させてしまうからね。rails だと。

GitHub のアクション

ちなみに今は解除されたが 彼の github アカウント は一時的に suspend された様である。何をしたかの調査、その間は害を及ぼした疑いがあるための suspend と見える。最初のアナウンス では単に suspend したとしか書いてないから誤解が多かったんだなぁ。Github, もちろん当初から疑いが晴れたら解除するつもりだったんだよね?

ちなみに誤解が多いと思われるのは そのアナウンス についたコメントでは「suspend を解除してやるべき」との声が多く上がっていた。

その suspend は実際に解除されたが、まぁ、解除すべきだよね。何か重大な損害を起こすような事はしてないものね。ただ、素直に報告せずに rails の所で実例を示してしまうというのはどうかと思うがw

まとめ

これだから rails は(キリッ, はやくなんとかしろ(キリッ

今後の動向が注目されますね。

追記 8: コントローラでみえる params に保護機能 ($SAFE な時の taint 的な感じで) をつける方向というのが DHH の考える一応の対応策? 別記事に詳細を書いた: rails/strong_parameters

あわせてよみたい: GitHub and Rails: You have let us all down. - Code Space

ところで、PHP は?

"register_globals?そんなのデフォルトでオフですよ" という記事より。

何年も前に指摘されていた脆弱性に今頃慌てふためいている愚かでコンピュータサイエンスを学ぶには無能すぎてRailsくらいしか使えないくせにPHPerだなんだと他人の尻馬に乗って調子こいてたボケナス共は、土下座してmodelの修正に取りかかるがよい。わっはっは。

だそうです。

PHP: グローバル変数の登録機能の使用法 - Manual」… これはひどい。

あと、PHP の Web フレームワークの一つ Symfony にも似たような問題があるっぽい: Security must be taken seriously - Symfony (はてブコメントより)

はてブコメントを見て思ったこと

  • attr_accessible はバリデータの一種なのかなぁ。
  • 自動生成で中身を把握してないというのも問題だが、これは自動生成じゃなくても update_attributes とか普通に使うメソッドだし自動生成関係無くないかなあ。自分は今回この記事で自動生成 (=scaffold) を取り上げたけど。

追記メモ

追記: suspend は解除されていたようだ (実害を及ぼしたかどうかの疑惑が解けたから?) https://github.com/blog/1069-responsible-disclosure-policy ので、文章を一部修正

追記2: これは Rails の脆弱性と言うよりは Rails の問題点である事を追記。 (重要: 〜 の段落を追加)

追記3: セクションごとに見出しをつけました

追記4: register_globals の事を言及

追記5: 前提知識が必要だとの言葉を受けて若干追記。まだ分からない部分があれば twitter 等で指摘ください。

追記6: mass assignment 脆弱性の説明を大幅に書き換え。わかりやすくなったと思う。

追記7: PHP の Symfony にあった似たような脆弱性のつくりを紹介

追記8: strong_parameters の事を追記

Published at 2012-03-05 09:35:58 +0900 | Permalink