セキュリティ対策を行うべき部分 – 自分が作っている部分

(更新日: 2013/12/03)

アプリケーション開発者がセキュリティ対策を行うべき部分とはどこか?当たり前ですがアプリケーションです。アプリケーションとは広い意味でのアプリケーションです。Webアプリの場合もあれば、ライブラリやモジュールであったり、フレームワークであったり、言語やサーバの場合もあります。

すべてのアプリケーション開発者が同じような意識を持ち、アプリケーションが安全に動作するようの作る責任はアプリケーションにあると責任感を持って開発すべき、と言いたいところですが実際には難しいです。

例えば、開発を始めたばかりの初心者であれば無理があります。どう作れば安全か、危険か、判断する基準がないからです。経験を積んだ開発者でも自分が作った事もない様なプラットフォーム上でどのように作れば安全か判断できません。

何故、セキュリティが分かり辛いのか?その一つ理由が「セキュリティ対策を行うべき部分 – 自分が作っている部分」と言う意識が足りないからだと考えています。

Djangoの例

本来はWebアプリケーションのセキュリティ問題ではない例を紹介します。

DjangoというPythonのフレームワークにはX-FORWARDED-FORの内容がREMOTE_ADDRに上書きされる、という設計上のセキュリティホールがあります。比較的最近CVEが登録されいます。Djangoの開発チームは新しいバージョンではこの問題が修正しましたが1.0系は修正しない方針です。

私もこのような脆弱性があると知らなかったら、REMOTE_ADDRはTCP/IPレベルで設定された値なので信頼できると判断して「内部ネットワーク」という設定を用意し、特定のネットワークからは管理用の操作ができるようなアプリケーションを作ってしまうかも知れません。

この例の場合、Django側にセキュリティホールがあるのは明らかだと思います。普通はTCP/IPレベルでのIPアドレスは信用できるからです。(TCPプロトコルの場合、アドレスを偽証していたら接続は確立できません。Webアプリまで接続されている=”普通”はリモートIPは信頼できます。詳しくはTCP/IPを解説した書籍で接続を確立ハンドシェイクやソースルーティングを防ぐ方法などを参照してください。あまり”普通”では無い状況で信頼できない場合もあります。IPv6などの書籍を参考してください)

アプリケーション側の問題でなくても、この例のようにフレームワークやライブラリ側で対処されない場合も割と見かけます。フレームワーク/プラットフォームの問題なのに対応しない、というような場合は仕方がないので、アプリケーション側で対処するしかありません。PHPでもあります。誰もが無効にするmagic_quotes_gpcも一例です。

Http Response Splitting

Webアプリケーションの脆弱性である例を紹介します。

Http Response Splittingと呼ばれる脆弱性があります。JavaScriptインジェクション、キャッシュ汚染によるページ改ざん等が可能になる危険な脆弱性です。これの場合、非常に多くのフレームワーク、プロキシ、ブラウザ、Webアプリケーションが影響を受けました。

この攻撃の原理は非常に単純でHTTPヘッダを送信する際に、不正な改行を送信させ、不正なデータでリバースプロキシを含むプロキシやブラウザのキャッシュを汚染し半恒久的なページ改ざんを可能にする危険な問題でした。

RFCではHTTPヘッダは複数行にまたがっても構わない仕様となっており、フレームワークやライブラリはヘッダ送信関数などで「改行」文字を含んだ文字列を送信する事は仕様通りの動作でした。つまり、「不必要な改行」をチェックする責任はアプリケーション側にありました。

私もHttp Response Splittingと呼ばれる攻撃方法は研究者が発表するまで問題自体を認識していませんでした。しかし、全ての入力は「ホワイトリスト型」のバリデーション処理によりチェックされ、不正な入力はすべて排除(プログラムを停止)すべき、という方針に基づきアプリケーションを作っていました。結果的には私が作ったアプリは全くこの攻撃の影響を受けませんでした。

フレームワークやプロキシ開発者にとっては、Http Response Splitting問題の責任はいい加減なレスポンスを返すWebアプリ側に責任がある、と言いたいところですし、実際Webアプリの問題です。この問題の根本的な責任はアプリケーション側にある事は明らかですが、フレームワークやライブラリ側で対処されています。

ヘッダ送信関数で「改行」を認めなければ攻撃は行えません。アプリケーションの中には仕様通りの動作を期待していて、このような変更を行うと正常に動作しないアプリケーションもあるかも知れません。しかし、アプリケーションの問題であっても現実的な対策としてフレームワークやライブラリ側で改行文字をサニタイズして対処しています。

全く同じような例はメールのヘッダを設定する関数などでも行われています。現在のフレームワークやライブラリの多くは、Subject等を設定するパラメータの改行文字をサニタイズします。(開発者は「多くは」と言う部分で安心するのではなく、不安を感じなければなりません)

mod_securityの例

Webアプリケーション以外の例です。アプリケーション(mod_security)のセキュリティ問題ではない例を紹介します。現在では、この例の問題の原因の多くはWebアプリケーションではなく、もう少し下のフレームワークやライブラリのレベルの問題です。

Apache Web Serverで追加のセキュリティ対策や様々な制限を加える事ができるmod_securityというジュールに「設定された制限を回避できる」脆弱性がCVE登録されたことがあります。分かり易く書くと「守っているつもりが、守れていなかった」事が問題となった事例です。

この問題の原因はJava, Perl, Python, Ruby等で作成されたWebアプリケーションが、仕様ではC言語の文字列を送信すべきところをNull文字を含んだ文字列を使っていた事が原因です。(PHP4は仕様通り、PHP5もPHP5.2までは仕様通りにC言語の文字列を送信していました)

mod_securityの開発者からすれば仕様外のデータを送信してくるWebアプリ(フレームワークやライブラリ、言語を含む「全体」としてのWebアプリ)に脆弱性の原因があると考えるのは当然です。本来の原因はWebアプリ側にあることは明らかです。しかし、mod_securityはWebアプリから送られてきた「仕様外」のデータを受け入れるように変更することでこのセキュリティ問題に対処しました。

セキュリティ対策を行うべき部分 – 自分が作っている部分

これらの例を見ていくと混乱しませんか?

こう例を挙げていくと、「自分のコード(アプリ)を変えなくても、他のコンポーネントの責任にできるなら自分のコードには責任はない」と主張できるものは主張してしまって当然、と考える人もでてきます。本当は「自分のコードにも問題はあったが、とりあえず他の部分で対処されたのでセキュリティホールではなくなった」と考えるべきです。

例えば、mod_securityの脆弱性として報告されたCVEですが、本来はJava, Perl, Python, Ruby, PHP等で作られたWebアプリケーション(やそのフレームワーク、ライブラリ)側が問題に対処する方が好ましいです。mod_securityと似たような機能を持つ”セキュリティ”アプリケーションが”仕様”通りに作られて、また同じように「守っているつもりが守れてなかった」等という事態になる可能性があるからです。

Http Response Splittingの脆弱性も同様です。次々に作られいく新しいプロキシの中には”仕様通り”に実装され対策がとられていない物が出てくるかもしれません。次々に生まれてくるフレームワークやライブラリの中には現在広く使われてる物のように”サニタイズ”しない物もでてくるかも知れません。組み合わせによって、またHttp Response Splittingで攻撃できるWebシステムが出来上がる可能性があります。

外部のシステムがどうしようも無い脆弱性を持っているなら、その脆弱性が悪いと非難するだけでも十分です。例えば、初期のSafariのXHRにはSame Origin Policyが実装されていませんでした。クッキーやXHRのSame Origin Policyは外部システムであるブラウザですが、セキュリティを維持するための根幹となる機能です。このような部分に問題があったら、Webアプリ開発者は「自分の責任ではない」と言い切っても構わないでしょう。

しかし、すべての開発者が持つべき”基本的な心得”は「セキュリティ対策を行う部分=自分が作っている部分」であるべきです。

このブログを読んでいる方の多くはWebアプリの開発者だと思うのでWebアプリ限定しますが、Webシステムの中心にいるWebアプリの開発者が「セキュリティ問題の責任はフレームワークやDBMSなどにある」と考えていては安全なWebアプリの開発が難しくなるばかりです。

すべての開発者が「セキュリティ対策を行う部分=自分が作っている部分」を”基本的な心得”として実践してれば、今よりもっと安全なシステム作れると思いませんか?

これが私のバリデーションやセキュリティに対する基本的な考えです。
理解頂けるでしょうか?

Comments

comments

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です