背景
Hello Worldのような以下のシンプルなアプリケーション(コントローラ)を考えます。これに対するテンプレート hello/hello.html.erb は以下だとします。class HelloController < ApplicationController def index render 'hello/hello' end end
ご覧のように、上記テンプレートを指定した場合、Hello worldが表示されます。<div>Hello world</div>
次に、以下のテンプレート hello/bye.html.erb を用意します
これを呼び出すには、コントローラにてrender 'hello/bye'を実行すればよいわけですが、helloとbyeを切り分けられるように、コントローラを以下のように修正します。<div>Good bye world</div>
これを呼び出すには、以下のようにします。class HelloController < ApplicationController def index render params[:template] end end
しかし、renderメソッドの引数を外部から自由に指定できるようにするのは、危なっかしい感じです。
renderメソッドの inlineオプション
renderメソッドにはinlineオプションというものがあり、テンプレート文字列を指定することができます。実行結果を以下に示します。Time.nowメソッドの呼び出しにより、現在時刻が表示されています。render :inline => "<%= Time.now %>"
しかし、そんなことができるのでしょうか?hash = {:inline => "<%= Time.now %>"} render hash
JSONによりハッシュを外部から指定できる
公開されているCVE-2016-2098のPoCでは、JSONによりrenderメソッドにハッシュを指定する方法が示されています。その様子を以下に示します(少し変えています)。以下の攻撃例では、FileUtils.touchメソッドにより、rootedというファイルを作成することで攻撃の証拠を示しています。上記の攻撃で、ファイル rooted が作成された様子を下図に示します。
$ ls -l rooted -rw-rw-r-- 1 ockeghem ockeghem 0 6月 1 22:29 rooted
対策
Ruby on Railsの以下のバージョンで修正されています(今年の2月29日公開)。- Rails 3.2.22.2
- Rails 4.1.14.2
- Rails 4.2.5.2
- 可能な限りrenderメソッドの引数には外部由来の値を指定しない
- やむを得ずrenderメソッドの引数を外部から指定する場合は、ホワイトリスト(たとえば指定可能なテンプレートファイル名の一覧)による検証を行う
まとめ
Ruby on Railsの潜在的なリモートスクリプトインジェクションの脆弱性CVE-2016-2098について説明しました。renderメソッドには強力なオプション指定機能があるため、外部から自由な値を指定できると危険です。そもそも、renderメソッドのinlineオプションでrubyスクリプトが実行できることは、脆弱性ではなく仕様です。このため、この問題は本来Ruby on Railsの脆弱性というよりは、アプリケーション側の問題であと考えます。この問題が「潜在的な」脆弱性と表現されているのは、このような背景からだと思います。
【HASHコンサルティング広告】
HASHコンサルティング株式会社は、ウェブアプリケーションのセキュリティに関心のあるセキュリティエンジニアを募集しています。
興味のある方は、twitterやfacebookのメッセージ、あるいは問い合わせページからお問い合わせください。