構造化設計とセキュアコーディング設計の世界観は二者択一なのか?

(Last Updated On: )

プログラミングの「世界観」

で構造化プログラミング/オブジェクト指向プログラミングの世界観(パラダイム)では、抽象化を行い問題を関数やオブジェクトの中に閉じ込める。つまり、プログラムの内部奥深くに”問題”を閉じ込めようとする。

セキュアコーディングの世界観では、”正しくないデータはどう処理しても正しく処理不可能である”プログラム原理と”失敗する物はできる限り早く失敗させる”Fail Fast原則に従い、できる限り問題となる”データ”を早い段階で廃除する、つまり問題を中に入れずに入り口で対策する、と紹介しました。1

一見すると相反するように見えますが、これら2つの世界観を持つ概念は二者択一ではありません。

抽象化とFail Fast

構造化プログラミング/オブジェクト指向プログラミングの場合、抽象化するのは”処理”です。処理の複雑性を関数やオブジェクト内部に抽象化します。構造化プログラミング/オブジェクト指向プログラミングでもFail Fast原則を適用し、入力エラーは関数やメソッドのできる限り早い段階でエラーにしていると思います。例えば、ある機能を実装したモジュールなら、そのモジュールの入力処理の段階で入力バリデーションを行っていると思います。

これはソフトウェア部品の機能単位で正しく動作することを保証するために必要な事です。セキュアコーディングでもこれが無用になることはありません。

構造化プログラミングもオブジェクト指向プログラミングもソフトウェアの機能を設計する為の概念です。ソフトウェアの部品レベルでの考え方として、それぞれの部品が正しく動作するように設計するのは当然です。

構造化プログラミング/オブジェクト指向プログラミングは抽象化はプログラムをどう設計するのか?という方法論であり、これらの必要が無くなることはありません。

構造化設計におけるセキュリティ対策の抽象化

多くのソフトウェアは”機能”を設計する為の構造化設計を、セキュリティ対策にも適用して設計されています。構造化設計をセキュリティ設計に適用することは間違いではありません。間違いではない、というより寧ろ推奨されています。

しかし、構造化設計を適用したセキュリティ設計”だけ”では、満足するセキュリティ設計になりません。その原因は構造化設計はアプリケーションの”機能”を設計する為の利用されていることにあります。

構造化設計で”機能”のセキュリティ設計/対策はできていても、アプリケーション全体のセキュリティ設計が丸ごと欠落していたり、不十分であることがとても多いです。

セキュアコーディングの粒度

セキュアコーディングの概念はソフトウェア全体としてをどう作ればより安全になるか?という考え方からソフトウェアのセキュリティを考えています。アプリケーション全体からコードの一行に至るまで、大きな粒度から最小の粒度まで、全てをカバーします。セキュリティを考える場合、全体対策も個別対策も両方とも無くてはならないモノなのでこうならざるを得ないのです。

セキュアコーディングを実装する場合、全体対策の概念と個別対策のコーディング標準(セキュアコーディング標準)の両方をソフトウェア開発に適用します。ここでは構造化設計で不足になりがちな全体対策の概念だけを考慮します。

CERTはセキュアコーディングの10原則を提唱しています。これはアプリケーションレベルのソフトウェアセキュリティ設計の概念/指針と言えます。話を簡単にする為にセキュアコーディング原則の第1番目の入力検証だけを取り上げます。

2017年版OWASP TOP 10 A10「不十分なモニタリングと記録」の策定段階では、ほぼ全てのWebアプリがモニタリングと記録以前に、これらに必要な入力検証さえほとんど無いか著しく不足している、としていました。これが第1原則だけを取り上げる理由です。

ソフトウェアの信頼境界線

話を進める前に誤解の多いソフトウェアの信頼境界を紹介します。

ソフトウェアの信頼境界は1つのプロセス上で動作するアプリケーションソフトウェア境界までが最大限です。1つのアプリケーション」としてパッケージングされているアプリケーションであってもプロセスが異なる場合、無条件に他のプロセス上で動作するソフトウェアを信頼できません。

1つのプロセス上までがソフトウェア信頼境界の最大限、これはプログラムがどんなに頑張ってもプログラム自身が排他的に管理するメモリ領域と異り、他のプログラムとの通信やデータのやり取りを行う場合、必要な保護や対策をしないと他のプログラムなどによって盗聴、偽造、改ざん、破壊のリスクが発生するからです。

セキュリティに詳しい方でも、ソフトウェアの信頼境界が最大限でも1つのプロセス上で動作するソフトウェア境界であることを誤解している場合も少なくありません。この制限はコンピュータプログラムの動作原理から発生する制約で変えることができない原則です。注意して下さい。

とは言っても「1つのプロセスで動作するソフトウェア」が信頼境界として書かれている図はあまり見ないではないか?と思うかも知れません。これはソフトウェアの最大信頼境界は自明なので書く必要がないこと、信頼境界図の多くは「システムの信頼境界図」だからです。

「システムの信頼境界」と「ソフトウェアの信頼境界」は異なるモノであることに注意してください。よく勘違いされています。

システム信頼境界図の例

ソフトウェア信頼境界図の例

 

さらに信頼済みのモノ(他のアプリケーションや自身のプログラムが利用するライブラリ)であっても、それには制限や守るべきルールがあり何をやっても大丈夫というモノではない事にも注意が必要です。これもよく勘違いされています。

アプリケーションソフトウェアの信頼境界

CERTはセキュアコーディングの10原則をよく読むとアプリケーション(≒ソフトウェア)の信頼境界は1つのプロセスで動作するソフトウェアまでであると理解ります。

セキュアコーディングの第1原則「入力をバリデーションする」は効果を最大化させるため、Fail Fast原則に従いできる限り早い段階で入力データをバリデーションする、とすることは論理的に導き出せる妥当なセキュリティ設計です。

ソフトウェア信頼境界の限界点が「できる限り早い段階」となります。先ずここで対策しないと「ソフトウェアセキュリティ」の「ソ」でつまづく事になります。

問題を抽象化し「できる限り内部」に閉じ込める構造化設計を利用したセキュリティ設計とは正反対とも言える設計になります。

構造化設計とセキュアコーディングの融合

構造化設計とセキュアコーディング設計のセキュリティ対策は水と油、二律背反のように感じたかも知れません。実際はそうではありません。

構造化設計”だけ”のセキュリティ設計は時代遅れと言えますが、構造化設計が悪いのではありません。構造化設計が”機能”の為の設計(個別設計)であることが、構造化設計”だけ”のセキュリティ設計をダメな設計にしてしまう原因です。

セキュリティ対策には全体設計/対策と個別設計/対策の両方が欠かせない、と既に紹介しました。これはソフトウェアに限らない一般的なセキュリティ対策原則で、個別だけ、でセキュリティ設計をしてしまうと脆弱なセキュリティ設計の原因になります。どのようなセキュリティ設計でも同じです。

構造化設計で個別設計ができます。セキュリティ設計も同じく構造化設計で個別設計できます。足りていないのは全体設計です。全体設計の基本セキュリティアーキテクチャーを導入し、それに合わせて個別設計を調整すれば満足できるソフトウェアセキュリティのアーキテクチャーを作れます。

既に紹介した通り、セキュアコーディングの第1原則をアプリケーションソフトウェアの信頼境界で適用することが(これだけではないですが)が全体設計の第一歩です。

この図のような考え方は、構造化設計に捉われすぎて全体設計/全体対策の重要性を丸ごと見落している考え方です。(因みに、セキュアコーディングでは入力を無害化しません。入力は検証/バリデーションします。無害化するのは出力(第7原則)です。)

残念ながらOWASPのセキュリティ専門家も指摘しているように、入力検証が全く無い、ほぼ無い、遅すぎる、著しく不十分なソフトウェアが大半を占めています。

重要なので繰り返しますが、構造化設計は”機能”に重点を置いた設計です。構造化設計によるセキュリティ設計の有効性は無くなりませんが、構造化設計”だけ”に頼ったセキュリティ設計は時代遅れで危険です。

セキュアコーディングが求める”データ”に重点を置いた設計概念2も取り入れる必要があります。これには「契約プログラミング(契約による設計)」の概念が役立ちます。

参考:エンジニア必須の概念 – 契約による設計と信頼境界線


  1. 実際にはセキュアコーディングは”全体”対策です。早い段階で不正なデータの廃除は要素の一部に過ぎません。 
  2. セキュアコーディングの概念は全体対策からコード一行までカバーします。データにだけ重点を置いているのではありません。 

投稿者: yohgaki