概要
2021年版のOWASP Top 10では、最も深刻な脆弱性として「アクセス制御の不備」がランキング1位となっています。
【補足】
OWASP Top 10とは、Webアプリケーションのセキュリティに関する重大な脅威のうち、深刻度が高いものから順に選ばれた10種類の脆弱性のランキングです。これは「OWASP」というWebセキュリティ関連の非営利組織が選定するもので、数年おきの頻度で公表されています。
ランキングの決め方は、多数の企業や団体から提供されたデータをもとにして、脆弱性の発生確率や「悪用されやすさ」、「ダメージの大きさ」などを評価して決められているそうです。
概要
アクセス制御の不備だけを診断すれば大丈夫というわけではありません。他にも発生確率や危険性が高い種類の脆弱性がランクインしています。特に3位の「インジェクション」は致命的な侵害に直結する強烈な脆弱性です。また5位の「セキュリティの設定ミス」も発生確率はやや高く、OWASPの統計では最大発生率が19.84%となっています。ほか2021年版で初登場10位となった「SSRF」は、本来は到達できないはずの領域にもリーチし得る危険性を持っており、今後は増加する可能性もあるとのとこで注目されています。
このように複数の種類の脆弱性があるなかで、今回ご紹介する「アクセス制御の不備」の診断だけで十分だとは言えません。しかしインジェクション攻撃の脆弱性診断を素人がやるのは危険ですし(ミスるとデータ破壊が起こり得ます)、その他のものは個別の環境毎に診断内容は大きく異なりますし、いずれもスーパー簡易的に脆弱性診断するのが難しいです。そのため当記事では、ランキング1位の「アクセス制御の不備」だけに絞ることとしました。これだけで十分ではないとしても、1位の脆弱性なのですから、これを検出するだけでもWebサイトの安全確保には相当に寄与できるはずです。
【予備知識①】アクセス制御の不備とは
大まかに言うと、
『特定のユーザーだけにアクセスを許可しているページやデータに関して、そのユーザー以外の者がアクセスできるようになってしまう脆弱性』
です。
例えば、とあるユーザーの個人情報が含まれるページを別のユーザーが閲覧できてしまうとか、Webサイトの管理者だけがアクセスできるページに攻撃者がアクセスできてしまう、というような脆弱性です。
【予備知識②】アクセス制御の不備が引き起こす問題
この脆弱性は、例えば下に挙げるような問題を引き起こします。
- Webサイトの管理機能を攻撃者が利用できてしまい、情報漏洩する、Webページが改竄される、Webサイトを乗っ取られるなど。
- 通販サイトや予約サイトなどといった会員制のWebサイトの場合、ユーザー情報や購入履歴・利用履歴などのページに他人がアクセスできてしまい、個人情報やプライバシーが情報漏洩する。
- データベース関連の箇所でこの脆弱性がある場合、顧客情報などの営業秘密データに攻撃者がアクセスできてしまい、情報漏洩する、データを削除されるなど。
上記は極めて危険な例です。その他にも、例えば「数量限定の特売品を無限に購入できてしまう」とか、「虚偽の予約や注文により業務妨害される」というようなリスクもあります。
【予備知識③】アクセス制御の不備が生じる箇所
この脆弱性は、アクセスの許可・拒否などを制御する箇所において、「Webブラウザから送信される値」を未検証のまま使用している場合に発生します。ここで言うWebブラウザから送信される値とは下記のようなものです。
- URLのクエリストリング
- フォームからPOSTされたパラメータ
- Cookieに保存された値
上記の例の①番は、例えば「sample.php?
user_id=1001」というようにクエリストリングでuser_idの値を受け取り、その値に基づいて表示内容を切り替える、というような仕組みになっているプログラムにおいて発生し得ます。この
user_id=1001を
user_id=1002に書き換えてリクエストしたとき、別のユーザーの情報が表示されてしまうのがこの脆弱性です。
ほか、次のようなプログラムの場合でもこの脆弱性は発生し得ます。
- 「sample.php?bool=false」というように、True/Falseの値でアクセス制御しているとき。
- 「sample.php?role=2」というように、数値などで権限を分けて制御しているとき。(role=0は管理者、1は編集者、2は一般ユーザー、など。)
falseをtrueに書き換えるとか、2を1または0に書き換えるなどすれば、アクセス権限を詐称できてしまいます。(正確に言うと権限を「制御するための値」を詐称できてしまいます)
続いて②番(フォームからPOST)の場合。
このようにPOSTのパラメータの値を受け取ってアクセスを制御する、というような仕組みになっているプログラムにおいて脆弱性が発生し得ます。
最後、③番(Cookie)の場合も①②と同様で、Cookieに保存されている値に基づいてアクセス制御をおこなっているプログラムで脆弱性が発生し得ます。
要するに、クエリストリングやPOSTパラメータなど、「ユーザー側で書き換えることができる箇所の値」に基づいてアクセス制御をおこなってはダメということです。もしどうしてもそのような値を使用しなければならない場合には、受け取った値を検証してセッション状態や権限に矛盾がないか判定するようにプログラミングする必要があります。
スーパー簡易的な診断方法
ソースコードを確認するのが一番簡単で手っ取り早いです。
具体的な手順は後述しますが、簡単に言うと次のような流れになります。
- 診断対象のソースコードをキーワード検索する。
- インクルードがある場合はそのソースコードもキーワード検索する。
- 検索で見つかった部分の処理内容を読み、アクセス権限を検証する処理がおこなわれているか否かを確認する。
通常、診断会社がおこなう脆弱性診断ではこのような検査はおこないません。診断会社の場合は「診断ツールを使用して、リクエスト&レスポンスの内容を解析する」という検査方法を用います。診断ツールの使い方は単純ではなく、しかも原理をきちんと理解したうえで作業しないとWebサイトのデータを破壊してしまうリスクがありますので、それは「スーパー簡易的」とは言えません。そのため当記事ではツールを使用せず、ソースコードを確認する方法を説明することとしました。脆弱性診断の専門知識がなくてもプログラマーなら誰でも簡単にできる方法ですので、ぜひお試し下さい。
Step1. ソースコードの内容を検索する
ここでは、Webアプリケーションにおいて断トツでシェアが多いプログラミング言語である「PHP」を例にして説明します。
これらのようなWebブラウザから送信された値が入る変数のことを、以下では「スーパーグローバル変数等」と言います。このスーパーグローバル変数等をキーワードにして、ソースコードを検索して見て下さい。
【参考例】
find . -name "sample.php" | xargs grep '\$_GET'
上記の参考例は、カレントディレクトリにある sample.php に対し $_GET という文字列で正規表現検索するコマンドです。LinuxのWebサーバーにおいてソースコードの内容を検索する場合は、このコマンドを参考にしてスーパーグローバル変数等が含まれているか否か検索してみて下さい。
サーバーにアップされているソースコードではなく、ローカルPCに保存しているソースコードを確認する場合には、普段からご使用されているエディターソフトに備わっている検索機能でスーパーグローバル変数等を検索して下さい。
そしてもし検索にヒットする箇所が有った場合は、その値がどのように使用されているかを次のStep.2以降で確認します。
もし検索にヒットする箇所が無い場合は、次のStep.2と3を飛ばして、Step.4へ進んで下さい。
Step2. 検証の有無のチェック
プログラムがスーパーグローバル変数等の値を受け取った後、その内容を検証してから使用しているのか、あるいは未検証のまま使用しているのかを確認して下さい。
【例1】
SELECT * FROM テーブル名 WHERE ID = '" . $_GET["user_id"] . "'
この例のようにスーパーグローバル変数等を未検証でSQL文に直接放り込んでいるような場合は、かなり高い確率でアクセス制御の脆弱性がありそうです。しかもそれだけでなく、より凶悪なSQLインジェクションの脆弱性もありそうです。
【例2】
if ( $_GET["role"] == "1" ) {
この例のようにスーパーグローバル変数等を未検証で条件分岐に使用している場合は、かなり高い確率でアクセス制御の脆弱性がありそうです。
【例3】
$argument = $_GET["role"];
この例のように一旦変数に代入していても、その変数が例1・2のように使用されている場合は未検証ですので、この場合も脆弱性がある可能性はかなり高いです。
Step3. 検証内容のチェック
function validation($arg){
//検証内容の処理
return $arg;
}
$argument = validation( $_GET["role"] );
このような形で、プログラムに渡されたスーパーグローバル変数等の内容が検証されている場合には、その検証内容をご確認下さい。
下記のようにアクセス権限の正当性がきちんと検証されていれば問題ありません。
- 渡されたユーザーIDが、アクセス元のユーザーのIDと合致するか否かをきちんと検証している。
- 渡されたBooleanやroleの値が、アクセス元のユーザーに設定されている権限と合致しているか否かをきちんと検証している。
もしこのような検証ではない場合。例えば数値型/文字列型の判定やデータサイズの判定などといった単純なバリデーションだった場合には、アクセス権限の面では未検証のままですので、脆弱性がある可能性が高いと考えられます。
Step4. インクルードされているファイル等も確認
診断対象のphpファイルを検索&確認した後は、そのphpファイルにインクルードされている他のphpファイルがあるか確認してください。
include("assing.php");
上の例のようにインクルードがある場合には、そのphpに対してもStep.1から3までのチェックをおこなって下さい。
【言葉の定義】
- インクルードする側のphpを、以下では「インクルード元php」と言います。
- インクルードされる側のphpを、以下では「被インクルードphp」と言います。
Step5. インクルード元phpのソースコード検索
Step.4では被インクルードphpをチェックしました。もしそこでスーパーグローバル変数等の値を代入した変数があり、かつそれを検証する仕組みになっていない場合には、その変数がインクルード元phpで使用されているかどうか確認して下さい。
例えば被インクルードphpにおいて、「$argument」という変数に未検証の値が代入されている場合は、インクルード元phpにおいて、SQL文やif文の中で「$argument」が使用されているか否かをご確認下さい。
SELECT * FROM テーブル名 WHERE ID = '" . $argument . "
if ( $argument == "1" ) {
このように、被インクルードphpでもインクルード元phpでも未検証のまま「$argument」が使用されている場合は、脆弱性がある可能性が高いと判断できます。
なお、インクルード元のphpは複数あることも多いかと思います(一つの被インクルードphpを複数のphpで共用するなど)。その場合は該当する全てのphpのソースコードを同様に確認して下さい。
難しそうに感じるかも知れませんが、実際にはとても簡単です。
Step.1~5までを文章で読むと難しそう&面倒くさそうと感じてしまうかも知れませんが、実際にやっていることは「ただのテキスト検索」ですので、とても簡単です。
- $_GETなどのキーワードがphpに含まれているかを検索する。
- インクルードしているphpも同様に検索する。
- キーワードが含まれている場合は、その箇所の処理内容を読む。
ただこれだけのことですので、プログラマーならば誰でもサクッとできるはずです。
要注意事項
Step.2の説明において赤文字で強調しましたが、SQLに未検証の値が使用される場合は、アクセス制御の不備の問題だけでなく、より危険なSQLインジェクションの脆弱性がある可能性が高いです。
また、exec()など外部プログラムを使用する箇所で未検証の値が使用される場合は、これも非常に危険なOSコマンドインジェクションの脆弱性がある可能性が考えられます。
もしそういう安全性の低いプログラムになっている場合、セキュリティをあまり意識されずに作られたことが明白ですので、当該Webサイトには他の種類の脆弱性も沢山あるだろうと予測できます。ですので、なるべく早く当社のような専門会社による脆弱性診断サービスをご依頼頂いたほうが良いです。
また、既に不正アクセスや情報漏洩等があるかもしれないという場合には、被害確認等のためのデジタル・フォレンジック調査もご検討下さい。