開発者の自由を許容するセキュリティ、自由を束縛するセキュリティ

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

アプリケーション開発におけるセキュリティ対策は大きく別けて、自由を制限するセキュリティ対策と自由を許容するセキュリティ対策の2種類に分けられると思います。

「セキュリティ対策の為に自由を制限する対策”だけ”でなければならない」とする意見を時々見かけます。しかし、これでは必要な仕様を満すソフトウェアが作れなかったり、不必要なコストが要るソフトウェアになったりします。

開発者の自由の許容しないセキュリティ対策

一般論として、仕組みとして安全性を保証できる制約(セキュリティ対策)、を原則としてセキュリティ対策を行う方が良いです。デフォルトでセキュアにする、という考え方の方が安全です。

開発者の自由を許容しないセキュリティ対策には色々あります。SQLインジェクション対策だけ取り上げます。

SQLインジェクション対策の代表例は

  • ORM(オブジェクトリレーションマッパー)だけを使う
  • プリペアードクエリだけを使い、プリペア文への変数埋め込みを禁止する

体系的なデータを管理するにはリレーショナルデータベース(RDB)が欠かせません。効率的にRDBを利用するにはSQLが欠かせません。

RDBをORMだけで使っていても、RDBをキーバリューストア(KVS)のように使っている分には全く問題ありません。しかし、KVS的な使い方を超える場合、例えば集計クエリを実行する場合はORMだけでは厳しい場合も少くありません。

SQLを理解しているなら、ORMを使わずに集計クエリを書いた方が何倍も早く書け、メンテナンスも容易になる場合は少くありません。特に大きなクエリ文にならざるを得ないようなクエリの場合、ORMだけで処理しようとすると何をやっているのか解らない、そのORMのスペシャリストでないと解らない、といったコードになってしまう事も少くありません。要するに非効率になります。

  • プリペアードクエリだけを使い、プリペア文への変数埋め込みを禁止する

これはもっと問題が大きく、プリペア文に変数を使えないと

  • ソートカラムを指定できない
  • 抽出カラムを指定できない

状態になります。 実質的に普通のRDBアプリケーションが作れなくなります。

「SQLデータベースを使う場合、プリペアードクエリだけ使えばOK!」と主張している方は、RDBをKVSの様に使っているだけから問題がないのではないでしょうか?

RDBをKVSのとしてだけの用途で使っているので、KVSをRDBのように使える、といった勘違いも発生している(していた?)のかも知れません。RDBの機能と用途を理解していれば、KVSを本格的にRDBのように使うには無理が多すぎる、と解ります。

RDBに限らず、特定のライブラリやフレームワークの機能だけを使う、とすると色々な制約が生まれます。しかし、”制約”があるから”制約による安全性”が保証されます。

開発者の自由を許容するセキュリティ対策

システム開発をする場合、使用するライブラリやフレームワークの機能だけを利用する、と制限すると要求仕様に合った機能の実装ができなかったり、困難になったりします。どうしても”ある程度は開発者の自由を許容するセキュリティ対策”も必要になる場合があります。

このような場合は”例外”を認める方が得策です。基本的にORMを使うシステムであっても、

  • 例外としてSQL文を直接記述する
  • 例外としてプリペア文への変数埋め込みを許可する

とします。

例外であっても、普通にRDBアプリケーションを作る場合に「SQL文の直接記述」「プリペア文への変数埋め込み」は割と普通に発生します。

例外であっても割と普通に例外が発生する、はSQL文に限らず”制約”によるセキュリティ対策で起こります。数は少なくても、アプリケーションの中に”例外”が普通にあります。

こういった場合、”例外”であっても安全なコードが書けるよう自分のアプリケーション用の”セキュアコーディング標準1を作ります。SQL文であれば

  • SQL文を直接(動的に)組み立てる場合のセキュリティ対策

としてコーディング規約としてのセキュアコーディング標準を作ります。

SQL文を直接(動的に)組み立てる際のセキュアコーディング標準作りのみでなく、プリペアードクエリだけ、ORMだけ、を使っている場合にも役立つ完全なSQLインジェクション対策とはどういう物かブログに書いています。

完全なSQLインジェクション対策

これを参考にセキュアコーディング標準を作ると問題ない標準(コーディング規約)を作れます。

自由を許容する/しないの二者択一ではない

一般的には、アプリケーション開発時に開発者の自由を許容する/しない、は二者択一ではありません。実用的なシステム構築で原則があるのは当然ですが、例外があるのも当然です。

ITシステムのセキュリティ対策の目的は

  • ITシステムを許容可能な範囲内のリスクに管理してITシステムを利用可能にする

です。

セキュリティ対策の為に、使えないシステムやコード記述とメンテナンスが困難なソフトウェア、を作るようでは本末転倒です。

原則は重要で守られるべきです。だからと言って、原則だけ、では使えるシステムが作れなくなります。バランスが重要です。

  • メンテナンスが難しいORMのコード

  • メンテナンスが難しいSQLのコード

と同じように不味い作り方と言えます。

まとめ

結局、使えるシステムを作るには原則と例外の両方が必要になります。

原則に従ったセキュリティ対策、例外用のセキュリティ対策、両方がないと十分に安全なシステム開発が困難になります。

ソースコード検査でよく見つかるセキュリティ問題の原因に

  • 例外用のセキュリティ対策

が定義されていない、理解されていない、があります。

  • 例外だから例外用のセキュリティ対策は必要ない

は本当に一切の例外がない場合のみ適用可能です。実用的なアプリケーションには、普通に例外的なコードが含まれます。基本的には

  • 例外用のセキュリティ対策とその知識は必須

と考えてシステム構築をしないと、致命的なセキュリティ問題を生む原因になります。実際、あるセキュリティ専門家は

  • SQLクエリで識別子が変数になるケースは例外的だから、プリペアードクエリ/プレイスホルダだけ知り、エスケープを知る必要はない

としていました。しかし、例外的だから知る必要も、使う必要もない、は実用的なアプリ開発ではあり得ません。

現在、ソースコード検査で見つかるSQLインジェクション脆弱性の8〜9割くらいが”SQL識別子のエスケープ漏れ”です。「プリペアードクエリ/プレイスホルダだけ知っていればよい。エスケープを知る必要はない」は明らかにアンチプラクティスで脆弱性を量産しています。


  1. セキュアコーディングの10番目のベストプラクティスである「セキュアコーディング標準を採用する」とはCERTが言語用に作ったセキュアコーディング標準を使う、という意味ではありません。自分のアプリケーション環境にあったセキュアコーディング標準を自分で作ることを意味します。 

投稿者: yohgaki