(Last Updated On: 2018年10月8日)

ソフトウェアにバグがあった場合、そのバグは”ただのバグ”で”単純に意図しない余計な動作をする箇所を直す”、で万事OK!でしょうか?

ここでは”ただのバグ”とは”問題が起きた時に問題が起きた箇所を直せばOK”なバグとして話を進めます。

よくある”ただのバグ”修正

インジェクション脆弱性もバグの一種です。多くの場合、インジェクション脆弱性は”ただのバグ”として修正されています。

以下はPHPのPostgreSQLモジュールを使った脆弱なSQLクエリ例です。クエリパラメーターの$_GET[‘id’]はそのまま渡されているとします。adminはシステム管理者フラグとします。

pg_query($db, ‘UPDATE myusers SET admin = true WHERE id = ‘, $_GET[‘id’]);

これは明らかにSQLインジェクションに脆弱なコードです。”ただのバグ”として以下のような修正をすることが多いでしょう。

pg_query_params($db, ‘UPDATE myusers SET admin = true WHERE id = $1’, [$_GET[‘id’]]);

または

pg_query($db, ‘UPDATE myusers SET admin = true WHERE id = ‘. pg_escape_literal($db, $_GET[‘id’));

アプリケーションによってはこれでも十分となるケースもあるでしょう。しかし、これで万全!万事OK!でしょうか?

この”ただのバグ”修正の問題点

例に挙げたSQLインジェクション脆弱性の修正はSQLインジェクションは防ぎます。しかし、この修正”だけ”では問題が残ります。

  • 不正な入力によるSQLエラーは防げない
  • 任意のユーザーをシステム管理者にしてしまうことを防げない

システム開発の基本的な原則に

  • 他のシステムに命令やデータを送る場合はそのシステムで誤作動したり、エラーとなるような命令やデータは送らない

があります。妥当な命令/データを送る責任は、命令/データを送る側にあります。この原則を一言で言い表せる単語は無いですが、CERTセキュアコーディング原則の7番目(出力を無害化する)がこれになります。

参考:

脆弱性があった、”ただのバグ”として修正、ではNG

プリペアードクエリ/エスケープだけでは、PostgreSQLがクエリを実行した際にエラーにならないようにするには明らかに不十分です。

  • IDが整数型の場合、整数以外の$_GET[‘id’]はSQL構文エラーになる

例のクエリは、コードによっては

  • IDが文字列型の場合、$_GET[‘id’]が出鱈目でも保存する

となってしまう事があります。

SQLiteのようにデータ型に関係なく文字列を保存できるデータベースも存在します。

“ただバグ”として修正してもOKな場合とは?

この例のクエリを”ただのバグ”として修正してOKな条件は

  • 入力データが妥当である場合
  • SQLクエリを送信するユーザーが修正権限を持っている場合

に限られます。つまり、この条件を満たしていない限り”ただのSQLインジェクション脆弱性バグ”として修正してもダメということです。条件を満たすには入力データの妥当性、ユーザー権限の検証が必須です。

データベースのレコードIDは整数であるとします。この場合、入力データが”整数として妥当”であることをバリデーションする必要があります。

このクエリを実行するユーザーがシステム管理者フラグを編集可能であることをバリデーションする必要もあります。

どのようにバリデーションすべきなのか?

余程単純なアプリケーションでなければ、開発者みんなが大好きな構造化、が必要になります。”ただのバグ”に見えるセキュリティ問題バグでも同じです。

アプリケーションのデータベースレコードIDは整数のみである場合が多いでしょう。この場合、整数以外のレコードIDをアプリケーションが受け入れる必要はありません。

Fail Fast原則に従い、エラーとなる出鱈目な入力はできるだけ早くエラーにします。MVCアーキテクチャーならコントローラーが最適でしょう。OWASP Source Code Review Guideでいうことろのアプリケーション入力データのバリデーションをコントローラーで行う構造が最適です。無条件にエラーにできる物はFail Fast原則でできるだけ早くエラーにしてしまう方がリスクが少なくなる、よい構造になるからです。

SQL文を実行するユーザーの権限、対象となるユーザーIDが管理者権限を持っても構わないのか、これらのバリデーションも必要になります。

これらはOWASP Source Code Review Guideでいうところのビジネスロジックバリデーションになります。MVCアーキテクチャーならモデルでバリデーションするのが最適です。

実行中のユーザーが編集権限を持っていない、編集対象のユーザーが管理者となることを許可されていない、といったビジネスロジックのエラーが発生した場合に対話的なUIが必要、つまり無条件にエラーとなるリクエストとして拒否できない場合もあります。ビジネスロジック処理、対話的UIが必要な処理はモデルで行うのが良いMVC構造になります。

良い構造にすると自然とセキュアコーディングの構造になる

セキュアコーディングの構造は単純かつプログラムの動作原理に則っています。この為、原理や原則に従い論理的にプログラムを構造化すると、バリデーション構造はセキュアコーディングのプログラム構造に自然となってしまいます。

”ただのバグ”として修正して構わない条件

アプリケーションの出力時のセキュリティ問題を”ただのバグ”として修正して構わない条件は出揃いました。

プログラムが”セキュアな構造”を持ち、必要なバリデーション処理が全て行われていること。

これが、セキュリティ問題を”ただのバグ”としても修正しても構わない条件となります。

この条件を満たしていない場合、遅すぎるセキュリティ対策(=フェイルセーフ対策)に頼る構造的に脆弱なアプリケーションのままになってしまいます。

OWASP TOP 10 A10:2017は攻撃者やセキュリティ検査ツールからの攻撃を検出/記録/対応できないアプリケーションは脆弱なアプリケーションである、としています。適切なデータバリデーションを構造的に適した形で行っていないと、体系的な対策は難しいです。

出力時のセキュリティ問題を”ただのバグ”として修正しても不十分なアプリケーションが大半です。構造的な問題はさっさと直してしまうのが得策です。

PHPの場合、入力処理/ロジック処理/出力処理、全てに使えるバリデーションフレームワークを公開しています。セキュアなアプリケーション構造にすることはアドホック(=アプリケーション機能の構造化と無関係)に行えます。

アプリケーション構造をセキュアにするのは、体質改善と同じような物です。体質を改善すると、セキュアな状態を維持することが容易になります。

投稿者: yohgaki