7PKとは「Seven pernicious kingdoms: a taxonomy of software security errors」の略でソフトウェアセキュリティ領域の分類の一つです。CWEのビューのCWE-700としても利用されています。CWE-700となっているので、ISO 27000などのセキュリティ標準で要求される「セキュアコーディング」の基礎知識として知っておくべき分類方法/概念です。
- 1 Input validation and representation (入力バリデーションと表現)
- 2 API abuse (APIの乱用/誤用)
- 3 Security features (セキュリティ機能)
- 4 Time and state (時間と状態)
- 5 Errors (エラー)
- 6 Code quality (コード品質)
- 7 Encapsulation (カプセル化)
- 追加 – Environment (環境)
入力バリデーションの次に重要な領域である「APIの乱用/誤用」を紹介します。
※ 入力バリデーションが第一番目である理由は、入力データの妥当性が保証されていなとプログラムは絶対に正しく動作しないからです。不正な入力で動作しているように見えても、誤った出鱈目な結果を返しているだけです。プログラムが脆弱性なく正しく動作する為には入力バリデーションが欠かせません。
APIの乱用/誤用
7PKは「APIは契約(仕様)に基づいて正しく利用されなければならない」としています。「何を今更、当たり前の事を?!」と思うかも知れません。しかし、現実にこの当たり前ができていない現状があります。
APIの契約(仕様)に基づいて正しく利用できていない例
- 32bit整数に50億の値を設定する → 符号なしでも約40億までしか表現できない
- 英数字の商品番号に英数字以外の文字を渡す → 正しく処理できるハズがない
APIを正しく使うには全てのパラメーターが妥当でなければなりません。APIが正しく動作できない妥当でない値を渡しても、絶対に正しく動作しません。1プログラムが受け入れるデータには「決まり」(≒制約)があり、その決まりに従ったデータしか正しく処理できない。基本的な事だがよく忘れられており「APIが何とかしてくれるだろう」と出鱈目な値を渡すコードは多い。
「出鱈目な値を渡しても、エラー/例外になるから、サニタイズしてくれるから大丈夫!」ではありません。
遅すぎるエラー/例外はプログラムの複雑性を増すだけで、悪さしかしません。iPhoneなどで頻繁に起きる「特定/壊れた文字」によるDoS脆弱性はその良い(悪い)例です。文字エンコーディングをバリデーションしていないアプリは簡単にDoS攻撃に脆弱になります。
一見するとサニタイズなら大丈夫に見えるかも知れません。しかし、サニタイズに頼ったプログラムの場合、エラー/例外が無用な複雑性を生み脆弱性の原因になる事、と同じです。サニタイズに頼るプログラム構造はダメな設計です。サニタイズに頼るアプリだとOWASPから脆弱なアプリ認定されます。
よくある間違い – ◯◯APIを使えばセキュリティ対策は完璧!
「◯◯APIを使えばセキュリティ対策は完璧!」、これは非常によく見られる間違いです。その代表例はSQLインジェクション対策でしょう。
- プリペアードクエリ/プレイスホルダさえ使っていればSQLインジェクション対策は完璧!
「プリペアードクエリ/プレイスホルダだけ」使っても全然完璧ではありません。既に紹介した通り、APIには妥当なデータを渡さなければ正しく動作しないので「プリペアードクエリ/プレイスホルダだけ」使ってもダメである事は明らかです。”事前”に入力データのバリデーションが”必須”です。
他にも色々と「プリペアードクエリ/プレイスホルダだけ」使ってもセキュリティ対策としてはお粗末すぎる対策にしかならい理由があります。詳しくは以下のブログを参照してください。
プリペアードクエリ/プレイスホルダの契約(仕様)
プリペアードクエリ/プレイスホルダが利用者(開発者)に保証(契約)してくれるのは
- プリペア文とパラメーターを分離してSQLを実行すること
だけです。これ以外のSQL文を経由した様々な攻撃に対して何の契約(仕様)もありません。SQL文経由で
- JSON/XMLインジェクション攻撃を行う(JSON/XMLは今時のRDBMSの標準機能)
- ReDoS攻撃、正規表現インジェクション攻撃を行う(正規表現は今時のRDBMSの標準機能)
- LIKEクエリにインジェクション攻撃を行う(SQL標準機能)
- SQL識別子やSQL語句を利用したSQLインジェクション攻撃を行う(SQL標準機能)
- SQLクエリエラーを発生させ、DoS攻撃を行う(SQL標準機能)
- 大量のSQLクエリ結果を返され、DoS攻撃を行う(SQL標準機能)
- 不正な整数で整数オーバーフロー攻撃を行う
- 長大なデータでDoS攻撃、インジェクション攻撃を行う
- 不正な文字列/データでシステム上のどこかに存在する脆弱性に攻撃を行う
など、ありとあらゆる攻撃を行われる可能性があります。
SQLインジェクションだけ見ても、プリペアードクエリ/プレイスホルダだけ、では「SQL識別子やSQL語句を利用したSQLインジェクション攻撃」が可能である為、SQLインジェクション対策だけとしても不十分です。
- プリペアードクエリ/プレイスホルダ”さえ”使っていればSQLインジェクション対策は完璧!
としてプリペアードクエリ/プレイスホルダを使うのは、明らかに「APIの乱用/誤用」である、と解ると思います。
基礎的間違い/勘違いの原因と対策は?
こういった基本的な部分での間違い/勘違いは
- ソフトウェアセキュリティはセキュリティ機能を使う事である
と考えている事に原因があるのかも知れません。
ソフトウェアセキュリティは何かのセキュリティ機能/APIを使えばOK、といったモノではありません。この問題は「APIの乱用/誤用」と関連する7PKの「セキュリティ機能」でも指摘しています。
- セキュリティソフトウェア(機能/API)はソフトウェアセキュリティではない
単純にセキュリティ機能/APIを利用する”だけ”、では全く不十分なソフトウェアセキュリティしか達成できません。これはプログラムの動作原理(プログラムは妥当な入力/正しいプログラムロジックでしか正しく動作できない)に基づくので、どんな天才が頑張っても変わりません。
- ソフトウェアセキュリティはセキュリティ機能を使う事である
ではなく(プリペアードクエリ機能を使えばソフトウェアセキュリティが作れる、ではなく)
- ソフトウェアセキュリティはプログラムを記述している開発者が作るモノである
と意識を変える必要があるように見えます。プ
基本的にはどんなプログラムでも 、入力 → 処理 → 出力、の構造を持っています。
この構造は変えられないので、ソフトウェア開発者はこの構造に合わせたセキュアなコードを”自分で作る”必要があります。
アプリケーションソフトウェア開発者が先ず第一にしなければならないのは、CWE-20が要求する完全な入力データバリデーションです。プログラムは出鱈目なデータでは絶対に正しく動作しません。アプリケーションにとって「どのようなデータが妥当なのか?」を定義/検証するのは、そのアプリケーションソフトウェア開発者の責任だからです。
まとめ
体系的/科学的なソフトウェアセキュリティ対策を実施しようとすると、何をどうしようと、入力バリデーションから始ないとソフトウェアセキュリティは始まりません。
「入力データバリデーションはしている!」としていても、セキュリティ標準(≒法律)が要求する入力データバリデーションになっているでしょうか?セキュリティ標準ではCWE-20が要求する入力データバリデーションが必要です。
全ての入力に対して標準的な入力バリデーションを使わなければならない。
・ 長さ
・ 入力種別(訳注: 期待される形式)
・ 少すぎる又は多すぎる入力
・ 関連するフィールドとの整合性
・ ビジネスルール
ビジネスルールロジックの例として、”boat”は構文的には正しいかもしれない。しかし、開発者が”red”や”blue”などの色の名前を期待している場合、”boat”は妥当ではない。
可能な限り、リクエストのパラメーターに期待する値に基き、利用する文字セットを制限するホワイトリストを使わなければならない。これは製品の何処かに存在するかも知れない脆弱性を削減または排除する間接的なメリットがある。
これらのルールを破るどのような入力も受け入れてはいけない。安全な値に変換してもいけない。
あなたのソフトウェアに対する全ての信頼できない入力が入り込む可能性がある箇所を全て理解しなければならない。例: パラメーターまたは引数、クッキー、ネットワークから読み込み全てのデータ、環境変数、DNSの逆引き、クエリ結果、リクエストヘッダー、URLやその一部、Eメール、ファイル、データベース、アプリケーションにデータを提供するあらゆる外部システム。 これらの入力はAPI呼び出しによって間接的に取得されることがあることを忘れてはならない。(訳注: 要するに「全ての外部入力データはバリデーションし、全ての入力データの妥当性を保証しなければならない)
入力バリデーションを実施する前に、適切に入力のデータコード/アプリケーション内部データ形式への変換するよう、注意しなければならない。
少なくとも私自身は、上記の要求事項を満たすOSS Webアプリを見た事がありません。(プロプライエタリならあります)
「APIの乱用」防止には契約プログラミング/契約による設計が役立ちます。
- 1プログラムが受け入れるデータには「決まり」(≒制約)があり、その決まりに従ったデータしか正しく処理できない。基本的な事だがよく忘れられており「APIが何とかしてくれるだろう」と出鱈目な値を渡すコードは多い。