【翻訳】Firefox における MIME Confusion Attack の防止
この記事は、2016 年 8 月 26 日付で Mozilla Security Blog に投稿された Mitigating MIME Confusion Attacks in Firefox(筆者: Christoph Kerschbaumer)の翻訳です。この翻訳は公式なものではありません。詳しくはこちらをご覧ください。
web サーバが Content-Type を指定しなくとも、web ブラウザはファイルの内容をスキャンしてファイル形式を判別することができます。例えば、スクリプトを受信するリクエストを Firefox から web サーバに投げた結果、web サーバが "image/jpg" の Content-Type でスクリプトを返した場合でも、Firefox は本来のファイル形式を判別できるのでスクリプトが実行されます。この技術は俗に「MIME スニッフィング」と呼ばれており、コンテンツのメタデータが間違っていたり、もしくは完全に欠落していたりしても、コンテンツの解釈に必要な情報を補うことができます。Firefox は正しいファイル形式を判別する際、文脈となる情報(該当する通信のきっかけとなった HTML 要素)を利用したり、ファイルの先頭バイトに書かれたメディアタイプを確認していました。MIME スニッフィングは多くのユーザの web 体験を向上させている一方、MIME confusion attack という攻撃の原因にもなっています。
ユーザから画像をアップロードできる web アプリケーションを例に考えてみましょう。ただし、ユーザが正しい画像を実際にアップロードしたかどうかは確認していないものとします(ファイルの拡張子のみを検査している場合など)。このとき攻撃者は、スクリプトを含むように細工した画像をアップロードできてしまうため、確認作業は十分ではありません。。ブラウザは細工されたファイルを HTML として表示してしまうため、クロスサイトスクリプティング(XSS)攻撃の起きる可能性があります。しかし残念ながら、ファイルが polyglots(2 通りのファイル形式で解釈できるもの)であるかもしれません。例えば、GIF ファイルを細工することにより、画像としても JavaScript としても正しいファイルにすることができます。すなわち、ファイル形式の正しい解釈はコンテキストに依存することになります。
Firefox 50 以降からは、サーバがレスポンスヘッダで "X-Content-Type-Options: nosniff" を送信した場合(仕様)、読み込まれた時のコンテキストと MIME タイプが一致しないスタイルシート、画像、スクリプトを破棄するようになります。より正確に言うと、Content-Type がコンテキストに一致しないファイルが Firefox によってブロックされます(ファイル形式と許可される Content-Type の一覧は下を参照してください)。これにより、先程のような MIME confusion attacks を防ぐことになり、コンソールには次のようなメッセージが表示されます。
スタイルシートの正しい Content-Type
- "text/css"
画像の正しい Content-Type
- "image/" から始まるもの
スクリプトの正しい Content-Type
- "application/javascript"
- "application/x-javascript"
- "application/ecmascript"
- "application/json"
- "text/ecmascript"
- "text/javascript"
- "text/json"
【翻訳】MWoS 2015: Let’s Encrypt Automation Tooling の成果報告
この記事は、2016 年 8 月 8 日付で Mozilla Security Blog に投稿された MWoS 2015: Let’s Encrypt Automation Tooling(筆者: J.C. Jones)の翻訳です。この翻訳は公式なものではありません。詳しくはこちらをご覧ください。
Mozilla Winter of Security 2015 が終了し、参加チームの学生はプロジェクトを終えることができました。
Certificate Automation tooling for Let’s Encrypt project は今月終了し、ACME による証明書自動管理プロトコルをサーバ運用と密接に統合させるべく、Nginx web サーバ用の実験的な proof-of-concept のパッチを作成しました。
このプロジェクトにおいて多大なる研究成果を挙げてくださった Klaus Krapfenbauer さん、彼のアドバイザーである Martin Schmiedecker さん、そしてウィーン工科大学の皆さんに対し、MWoS チームとメンターの Richard Barnes、そして同じくメンターの私からお礼を申し上げます。
以下の AirMozilla による動画は、Klaus さんがプロジェクトのまとめとして発表したプレゼンテーションで、このプロジェクトの詳細について紹介しています。
MWoS Let’s Encrypt Certificate Automation のプレゼンテーション(AirMozilla)
Nginx 用 ACME モジュールの開発
筆者: Klaus Krapfenbauer
補足: このモジュールは不完全な proof-of-concept ですが、https://github.com/mozilla/mwos-letsencrypt-2015 から参照できます
2015-2016 Mozilla Winter of Security では、著名な web サーバに ACME クライアントを実装するプロジェクトが採用されました。このプロジェクトの目標は、Let's Encrypt と併用した HTTPS 設定の自動化に対する価値を示すことです。Caddy Server のようなプロジェクトは、多くの使いやすい機能をユーザから利用できるようにしたものですが、今回のプロジェクトでは主要な web サーバの Nginx において、それらの自動化する機能を組み込むことを目指しました。
Nginx のモジュールシステムでは、それぞれが異なる目的を持つ様々なモジュールを利用可能になっています。モジュールとしては、トラフィックを複数のバックエンドサーバに振り分けるロードバランサモジュール、web サイトのデータ変換を行うフィルタモジュール(例えば SSL/TLS モジュールのような暗号化など)、web リクエストに対応するコンテンツを生成するハンドラモジュール(例えば HTML ファイルをディスクから読み出して送り返す HTTP ハンドラなど)が挙げられます。モジュールの目的のみならず、サーバのコア部分へフックをかける方法でもモジュールの種類が異なりますが、この選択は Nginx モジュールを実装し始める際に重要となります。しかし、今回のプロジェクトに適したモジュールの種類はデフォルトで用意されておらず、後述するような困難がいくつか生じました。
ACME モジュール
今回の Nginx モジュールは、ACME Certbot による既存のワークフローを置き換えることが目的です。そのため、このモジュールの機能は Certbot の機能に近いものとなります。その機能とは以下の通りです。
- 鍵対の生成と格納
- ACME サーバに対するアカウントの登録
- ドメインに対する認証情報の作成
- ドメインの認証における HTTP チャレンジの解決
- 他のチャレンジ方式は後日サポートします
- ACME サーバからの証明書取得
- 証明書の更新
- 取得した証明書を Nginx SSL/TLS モジュールに使用させる設定
ACME プロトコルの処理に必要な情報を提供するため、Nginx に以下のような新しい設定ディレクティブを導入することにしました。
他の情報はすべて、Nginx にデフォルトで組み込まれているディレクティブから集められます。例えば、証明書を発行したいドメイン名は "server_name" という Nginx の設定ディレクティブから取得できます。
今回の ACME モジュールは Nginx サーバ自身を拡張するため、モジュールは Nginx というソフトウェアの一部となります。従って、モジュールを設定するために Nginx の設定ファイルを利用し、証明書を Nginx の設定ファイルディレクトリに格納します。その証明書を取得する際、ACME モジュールは ACME サーバ(例えば Let's Encrypt が該当しますが、ACME プロトコルを話せる他のサーバでも構いません)と通信を行い、この証明書を使うよう SSL/TLS モジュールを設定します。そして、設定された SSL/TLS モジュールによtって、web サイトとユーザのブラウザ間における通信が暗号化されます。
ここで、安全な web サイトを立ち上げる際のワークフローを確認してみましょう。ACME を用いない場合、暗号化された web サイトを立ち上げるには以下の手順を踏む必要がありました。
- 必要な情報をすべて揃えて CSR(証明書署名要求)を作成する
- 作成した CSR を CA(認証局)に送る
- 署名付きの証明書を取得するために CA へ料金を支払う
- 証明書が返送されるまで待つ(場合によっては数時間)
- 証明書をダウンロードし、サーバの正しい場所に置く
- その証明書を使用するようにサーバを設定する
ACME プロトコルと Let's Encrypt CA を利用すれば、必要な手順は以下で済みます。
これでも大きな進歩ですが、Nginx 用 ACME モジュールを利用すればもっとシンプルになり、以下の手順だけで済むようになります。
- サーバの設定項目で ACME モジュールを有効にする
他のことはすべて ACME モジュールが処理してくれます。従って、Let's Encrypt クライアントが行っていた処理に加え、サーバ起動時に必要な設定もすべて ACME モジュールが自動的に処理します。このようにすれば、web サイトの管理者が自身のサイトをより安全にしやすくなるはずです。
ACME モジュールを動かすのに必要な最小限の設定は、動作させたい Nginx サーバの設定ファイルにおいて、server コンテキストに "acme" ディレクティブを加えることだけです。つまり、設定の仕方は以下のようになります。
… http { … server { listen 443 ssl; server_name example.com; acme; … <recommended SSL hardening config directives> … location / { … } } } …
立ちはだかった困難
ACME モジュールの設計と開発にはかなりの困難が伴いました。
上で述べたように、Nginx のモジュールには様々な種類があり、モジュールによってサーバのコアを拡張する箇所が異なります。デフォルトとなる Nginx モジュールの種類は、ハンドラモジュール(サーバ上にコンテンツを生成するもの)、フィルタモジュール(SSL/TLS モジュールのように web サイトのデータを変換するもの)、ロードバランサモジュール(リクエストをバックエンドサーバに振り分けるもの)となっています。しかし、これらの種類は ACME モジュールと隠蔽したいワークフローとには当てはまりません。今回のモジュールは、自分自身の設定ディレクティブを有することや、サーバのコアや他のモジュールへのフックを必要とする点において、先程の慣例から外れてしまいます。今回の要件を満たせるように Nginx のモジュールシステムは設計されていないため、ACME プロトコルの通信を行う「タイミング」について自由度はほとんどありませんでした。
ACME モジュールは既存の SSL/TLS モジュールに対して設定を行いますが、SSL/TLS モジュールは web サイトの暗号化を実際に行うものです。ACME で取得した(暗号化に必要となる)証明書を渡すには、ACME モジュールから SSL/TLS モジュールを必要限度でコントロールする必要があります。残念ながら、サーバの起動時に Nginx の設定ファイルがパースされる際、証明書の実在性と正当性が SSL/TLS モジュールによって確認されてしまいます。つまり、設定ファイルのパースが終わる前に ACME モジュールを実行しなければなりません。このような制約があるため、サーバの起動時に "acme" ディレクティブがパースされた段階で、証明書の取得作業をすべて行うように方針決定しました。証明書を取得した後は、メモリに格納されている SSL/TLS モジュールの設定項目を ACME モジュールから更新し、新しい証明書を利用するように設定します。
アーキテクチャに関しては、ACME HTTP チャレンジ・レスポンスを実装する際にもう 1 つ問題が生じました。ACME HTTP チャレンジを用いてドメインを認証させるには、そのドメイン上の well known な URL パスから、サーバが決められたトークンを返信する必要があります。通常このトークンの返信方法は、web サーバがサイトのコンテンツを配信するのと同じ方法でなければなりません。しかし、ACME モジュールが処理を行っている最中に Nginx はまだ起動しておらず、どこにも web サーバは立っていないのです。もし ACME モジュールの処理を中断させ、web サーバの起動に処理を譲ってしまうと(先に SSL/TLS モジュールにおける証明書の制約を解決しておくことに注意)、後から ACME の処理を再開させることは容易にできません。これはアーキテクチャ的に Nginx 側の理に適っていますが、今回のプロジェクトとしては不都合です。このジレンマに直面しつつも proof-of-concept の実現を目指した結果、Nginx 自身が正常に起動する前に ACME チャレンジに応答できる、独立した小規模の web サーバを立てるよう方針を決めました。
まとめ
ここまで議論してきたように、Nginx モジュールの制約を受けたことで、アーキテクチャ設計に関して次善的な意思決定を余儀なくされました。多くのソフトウェアプロジェクトと同じく、利用するフレームワークが設計された際の想定範囲から超えた時に困難は生じます。現時点における ACME モジュールのアーキテクチャ設計は、proof-of-concept と捉えるべきでしょう。
このモジュールのアーキテクチャや、Nginx のコア部分 - SSL/TLS モジュール - ACME モジュール間の通信を改善する余地はまだ残っています。こうした変更案による長所・短所を以下で検討してみましょう。
変更案の 1 つに、証明書を受信するタイミングを、設定ファイルがパースされた後に延期させる方法があります。これを実現するには、新しく受信する証明書の準備が整うまでの間、一時的な証明書で SSL/TLS モジュールをごまかす必要があります。しかしコーナーケースとして、その時点で取得済みの証明書が格納されていない場合に問題が生じ、ちょうどサーバの初回起動時が相当します。
もう 1 つはチャレンジ・レスポンスに変更を加える案です。これは、web サーバの中に web サーバを立てるもので(サードパーティ製ライブラリであるかは関係なく)、あまり綺麗な方法ではありません。こうすることで、ACME プロトコルで採用されている TLS-SNI や他のチャレンジ方式をより組み込みやすくなるかもしれませんし、ACME モジュールの処理中に Nginx を起動させる方法が他にあるかもしれません。
最後にひとつ。SSL/TLS モジュールとのやり取りは非常に hacky です。
プロジェクトの現状と展望
今回開発したモジュールは現状、開発段階の終盤にあたる proof-of-concept とほぼ考えられます。現時点のモジュールでは、一時的な鍵対の生成、ACME サーバへの登録、ドメインに対する認証チャレンジの発行、チャレンジに対する応答の開始までが行えます。proof of concept はまだ実現できていないため、引き続きプロジェクトに取り組んでいく考えです。
多くの方々に感謝を
今回のプロジェクトは、web 全体を安全にしたいという将来像を形にするきっかけとなり、非常に楽しい機会でした。私事になりますが、このプロジェクトにおいて私をサポートしてくださった Mozilla Security Engineering Team の J.C. Jones さんと Richard Barnes さんに特別な感謝を申し上げたいと思います。そして、私の教授でもありメンターであった、オーストリアのウィーン工科大学にある SBA Research の Martin Schmiedecker 氏にも特別な感謝を申し上げます。もちろんながら、Mozilla Winter of Security を開催し、世界中の学生に素晴らしい IT プロジェクトに参加させてくださった Mozilla organization の皆様にもお礼申し上げます。最後となりましたが、一部分ではありながら素晴らしいセキュリティプロジェクトに参加させていただいた Let's Encrypt プロジェクトの皆様にお礼を申し上げます。
【翻訳】2016 年度 Mozilla Winter of Security のお知らせ
この記事は、2016 年 8 月 1 日付で Mozilla Security Blog に投稿された Announcing the 2016 edition of Mozilla Winter of Security(筆者: Francois Marier)の翻訳です。この翻訳は公式なものではありません。詳しくはこちらをご覧ください。
Mozilla のセキュリティエンジニアがする仕事は、単に Firefox ユーザのみならず、Web 全体にとって重要な仕事です。もし今までに OWASP Zed Attack Proxy を使ったことがあれば、SSH と TLS に関する私たちのガイドラインを読んだり、自分の web サイトを HTTP Observatory で検証してみてください。そうすれば、Mozilla セキュリティチームの成果から利益を得ることができることと思います。Web セキュリティに真価のある影響を与えたいと考え、かつこの分野において世界で最も才能のある方々を、私たちが必ず採用するようにしているのはこのためです。
Mozilla Winter of Security (MWoS) とはまさにそのための機会であり、学生に我々のエンジニアとタッグを組んでもらい、Mozilla のセキュリティプロジェクトに貢献してもらうものです。今日は、今年で第 3 回を数える MWoS の応募受付が始まったことことをお知らせします。
私たちは毎年、セキュリティに関して意義深い課題を含んだプロジェクトを選定しています。メンターの立場から見ると、MWoS とはプロジェクトを Mozilla のエコシステムから外部のコントリビュータへ公開し、まとまった時間をなかなか割けない箇所を手伝っていただける機会です。対して学生の立場から見ると、MWoS とはセキュリティにおけるオープンソースの世界への入口であり、現実世界の問題を解決できる機会でもあります。この相互に利益を得られる仕組みによって、この 2 年間で 33 人の学生に 16 のセキュリティプロジェクトでコードを書いていただけました。これらのプロジェクトの中には、Mozilla とインターネットを安全にするものとして完全に採用されているものもあります。例えばギリシャの Dimitris Bachtis (MWoS 2014) が開発した TLS Observatory は、サイトの適切な HTTPS 設定を支援するプラットフォームです。他の例として MIG Sandbox がありますが、これは Mozilla Investigator を安全にするべく Linux seccomp を実装した Go パッケージであり、ルーマニアの Teodora Băluță と Vladimir Diaconescu、Constantin-Alexandru Tudorică (MWoS 2015) が開発したものです。
今年の MWoS では Mozilla の Crypto チームにも範囲を拡大し、Firefox のネットワークセキュリティライブラリである NSS のうち 5 つのプロジェクトも対象となりました。暗号技術の他にも web とインフラのセキュリティなど、2016 年度の MWoS では様々な領域に渡る 12 個のプロジェクトを取り上げます。今回のプロジェクトは以下の通りです。
- MIG: A web interface for Mozilla Investigator
- ZAP: Field Enumeration
- ZAP: Form Handling
- ZAP: Automated authentication detection and configuration
- Plug'n'hack / ringleader: Support for e10s (and more)
- NSS: Demos
- NSS: Server integration
- NSS: SHA-3 Implementation
- NSS: Formal Verification
- NSS: TLS Interoperability
- ssh_scan: Improving Scalability and Feature Set
- Security Testing Workflow and Toolchain for Python Websites and Services
全プロジェクトの一覧と詳細は https://wiki.mozilla.org/Security/Automation/Winter_Of_Security_2016 から確認できます。
応募に際しては、チームとして大学の講義に必ず登録し、MWoS のプロジェクトによってチームに単位が与えられることを担当教員が必ず承認していることが必要です。これまでの経験から、この要件があることで学生の時間とプロジェクトへのモチベーションを確保することができ、参加者全員により良いメンタリングの機会を提供できると考えています。
応募受付は今日から始まり、9 月 15 日に締め切られます。あなたが教員であるのなら、ぜひ学生の方々に MWoS のことを伝えてあげてください。あなたが Web セキュリティに真価のある影響を与えたいと考えている学生ならば、メンバー集めを始めて 9 月 15 日までに応募フォームを記入してください。選考の結果は締切後 2 週間以内にチームへご連絡します。
MWoS プログラムやプロジェクトについて何か質問があれば、メールまたは Mozilla の #security IRC チャンネル でメンターに直接聞いてください。あなたの参加を待っています!