防御プログラミング

ウィキペディアから、無料の百科事典
ナビゲーションにジャンプ 検索にジャンプ

防御プログラミングは、予期しない状況下でソフトウェアの一部の継続的な機能を保証することを目的とした防御設計の形式です。高可用性安全性、またはセキュリティが必要な場合は、防御的なプログラミング手法がよく使用されます。

防御プログラミングは、次の点で ソフトウェアとソースコードを改善するためのアプローチです。

  • 一般的な品質–ソフトウェアのバグや問題の数を減らします。
  • ソースコードをわかりやすくする–ソースコードは、コード監査で承認されるように、読みやすく理解しやすいものにする必要があります。
  • 予期しない入力やユーザーの操作にもかかわらず、ソフトウェアを予測可能な方法で動作させる。

ただし、過度に防御的なプログラミングは、発生することのないエラーから保護する可能性があるため、実行時間とメンテナンスのコストが発生します。また、コードトラップによって多くの例外が防止され、見過ごされて誤った結果が生じる可能 性があるというリスクもあります。

安全なプログラミング

安全なプログラミングは、コンピュータのセキュリティに関係する防御的なプログラミングのサブセットですセキュリティが懸念事項であり、必ずしも安全性や可用性ではありません(ソフトウェアが特定の方法で失敗する可能性があります)。あらゆる種類の防御プログラミングと同様に、バグを回避することが主な目的です。ただし、その動機は、通常の操作で失敗する可能性を減らすことではなく(安全性が懸念されるかのように)、攻撃対象領域を減らすことです。プログラマーは、ソフトウェアが積極的に悪用されてバグを明らかにする可能性があると想定する必要があります。バグは悪意を持って悪用される可能性があります。

int Risky_programming char * input {   
  char str [ 1000 ]; // ... strcpy str input ); //入力をコピーします。//... }  
  
  
  
     
  
  

入力が1000文字を超えると、この関数は未定義の動作になります。一部のプログラマーは、これほど長い入力をユーザーが入力しないと仮定すると、これが問題であるとは感じないかもしれません。この特定のバグは、バッファオーバーフローの 悪用を可能にする脆弱性を示しています。この例の解決策は次のとおりです。

int secure_programming char * input {   
  char str [ 1000 + 1 ]; //ヌル文字用にもう1つ。   

  //..。

  //宛先の長さを超えずに入力をコピーします。
strncpy str input sizeof str ));    

  // strlen(input)> = sizeof(str)の場合、strncpyはnullで終了しません。
//バッファの最後の文字を常にNULに設定することでこれに対抗し、//文字列を処理できる最大長に効果的にトリミングします。// strlen(input)が長すぎる場合は、//プログラムを明示的に中止することもできます。str [ sizeof str -1 ] = ' \ 0' ;  
  
  
  
      

  //... 
}

攻撃的なプログラミング

攻撃的なプログラミングは防御的なプログラミングのカテゴリであり、特定のエラーは防御的に処理されるべきではないという強調が加えられています。この方法では、プログラムの制御外からのエラー(ユーザー入力など)のみが処理されます。この方法論では、ソフトウェア自体、およびプログラムの防御線内のデータが信頼されます

内部データの有効性を信頼する

過度に防御的なプログラミング
const char * trafficlight_colorname 列挙型traffic_light_color c {     
    スイッチc {  
        case TRAFFICLIGHT_RED return "red" ;      
        case TRAFFICLIGHT_YELLOW 「黄色」を返します;   
        ケースTRAFFICLIGHT_GREEN 「緑」を返す;    
    }
    「黒」を返す; //死んだ信号機として扱われます。//警告:この最後の'return'ステートメントは、'traffic_light_color'のすべての可能な値が//前の'switch'ステートメントにリストされている場合、//最適化コンパイラによって削除されます... }  
    
    
    

攻撃的なプログラミング
const char * trafficlight_colorname 列挙型traffic_light_color c {     
    スイッチc {  
        case TRAFFICLIGHT_RED return "red" ;      
        case TRAFFICLIGHT_YELLOW 「黄色」を返します;   
        ケースTRAFFICLIGHT_GREEN 「緑」を返す;    
    }
    アサート0 ); //このセクションに到達できないことを表明します。//警告:この'assert'関数呼び出しは、'traffic_light_color'のすべての可能な値が//前の'switch'ステートメントにリストされている場合、//最適化コンパイラによってドロップされます... } 
    
    
    

ソフトウェアコンポーネントの信頼

過度に防御的なプログラミング
if is_legacy_compatible user_config )){  
    
//戦略:新しいコードが同じold_code user_config );で動作することを信頼しないでください。    
} else {  
    //フォールバック:新しいコードが同じケースを処理することを信頼しない
if new_code user_config != OK {        
        old_code user_config );
    }
}
攻撃的なプログラミング
//新しいコードに新しいバグがないことを期待します
if new_code user_config != OK {    
    //大声で報告し、プログラムを突然終了して適切な注意を引きます
report_error "何かが非常にうまくいかなかった" );    
    終了-1 );
}

テクニック

防御的なプログラミング手法は次のとおりです。

インテリジェントなソースコードの再利用

既存のコードがテストされ、機能することがわかっている場合は、それを再利用することで、バグが発生する可能性を減らすことができます。

ただし、コードを再利用することは必ずしも良い習慣ではありません。特に広く配布されている場合、既存のコードを再利用すると、他の方法で可能であるよりも幅広い対象者を対象とするエクスプロイトを作成し、再利用されたコードのすべてのセキュリティと脆弱性をもたらすことができます。

既存のソースコードの使用を検討する場合、モジュール(クラスや関数などのサブセクション)を簡単に確認することで、開発者に潜在的な脆弱性を排除または認識させ、プロジェクトでの使用に適していることを確認できます。[要出典]

レガシー問題

古いソースコード、ライブラリ、API、構成などを再利用する前に、古い作業が再利用に有効であるかどうか、またはレガシーの問題 が発生しやすいかどうかを検討する必要があります。

レガシーの問題は、古い設計が今日の要件で機能すると予想される場合、特に古い設計がそれらの要件を念頭に置いて開発またはテストされていない場合に固有の問題です。

多くのソフトウェア製品は、古いレガシーソースコードで問題を経験しています。例えば:

  • レガシーコードは、防御的なプログラミングイニシアチブの下で設計されていない可能性があるため、新しく設計されたソースコードよりもはるかに低品質である可能性があります。
  • レガシーコードは、適用されなくなった条件下で作成およびテストされた可能性があります。古い品質保証テストは、もはや有効性がない可能性があります。
    • 例1:レガシーコードはASCII入力用に設計されている可能性がありますが、現在、入力はUTF-8です。
    • 例2:レガシーコードは32ビットアーキテクチャでコンパイルおよびテストされている可能性がありますが、64ビットアーキテクチャでコンパイルされると、新しい算術問題が発生する可能性があります(たとえば、無効な符号テスト、無効な型キャストなど)。
    • 例3:レガシーコードはオフラインマシンをターゲットにしている可能性がありますが、ネットワーク接続が追加されると脆弱になります。
  • レガシーコードは、新しい問題を念頭に置いて作成されていません。たとえば、1990年に作成されたソースコードは、当時広く理解されていなかったため、多くのコードインジェクションの脆弱性が発生する可能性があります。

レガシー問題の注目すべき例:

正規化

悪意のあるユーザーは、誤ったデータの新しい種類の表現を発明する可能性があります。たとえば、プログラムがファイル「/ etc / passwd」へのアクセスを拒否しようとすると、クラッカーは「/etc/./passwd」など、このファイル名の別のバリアントを渡す可能性があります。非正規入力 によるバグを回避するために、正規化ライブラリを使用できます。

「潜在的な」バグに対する耐性が低い

問題が発生しやすい(既知の脆弱性などと同様)と思われるコード構造は、バグであり、潜在的なセキュリティ上の欠陥であると想定します。基本的な経験則は、「私はすべての種類のセキュリティエクスプロイトを認識しているわけではありません。知っているものから保護する必要があり、それから積極的に行動する必要があります!」です。

コードを保護するためのその他のヒント

  • 最も一般的な問題の1つは、プログラムへの入力などの動的サイズのデータ​​に一定サイズまたは事前に割り当てられた構造体を未チェックで使用することです(バッファオーバーフローの問題)。これは、 Cの文字列データで特に一般的です入力バッファの最大サイズが引数として渡されないため、のようなCライブラリ関数は使用しないでください。のようなCライブラリ関数は安全に使用できますが、プログラマーは、使用する前にサニタイズすることにより、安全な形式の文字列の選択に注意する必要があります。getsscanf
  • ネットワークを介して送信されるすべての重要なデータを暗号化/認証します。独自の暗号化スキームを実装しようとしないでください。代わりに、実績のあるものを使用してください。CRCまたは同様のテクノロジーを使用したメッセージチェックも、ネットワーク経由で送信されるデータを保護するのに役立ちます。

データセキュリティの3つのルール

*他の方法で証明されるまで、すべてのデータは重要です。
 *他の方法で証明されるまで、すべてのデータは汚染されています。
 *他の方法で証明されるまで、すべてのコードは安全ではありません。
    • ユーザーランド、またはより一般的には「クライアントを信頼しない」として知られているコードのセキュリティを証明することはできません

データセキュリティに関する次の3つのルールは、内部または外部からのデータを処理する方法を説明しています。

他の方法で証明されるまで、すべてのデータは重要です。つまり、すべてのデータは、破棄する前にガベージとして検証する必要があります。

すべてのデータは、他の方法で証明されるまで汚染されます 。つまり、すべてのデータは、整合性を検証せずに残りのランタイム環境を公開しない方法で処理する必要があります。

他の方法で証明されるまで、すべてのコードは安全ではありません -少し誤称がありますが、バグや未定義動作がプロジェクトやシステムを一般的なSQLインジェクション攻撃などの攻撃にさらす可能性があるため、コードが安全であると決して想定しないように注意してください

詳細情報

  • データが正しいかどうかをチェックする場合は、データが正しくないことを確認してください。正しくないことを確認してください。
  • 契約による設計
  • アサーション(アサーションプログラミングとも呼ばれます
  • リターンコードより も例外を優先する
    • 一般的に言えば、例外が発生した場所やプログラムスタックがどのように見えたかを示さないエラーコード値を返すのではなく、API コントラクトの一部を強制し、開発者をガイドする例外メッセージをスローすることをお勧めします。開発者のストレスを最小限に抑えながら、ソフトウェアの堅牢性とセキュリティを向上させます。

も参照してください

参照

  1. ^ 「fogoアーカイブ:GeraldOskoboiny<[email protected]>によるBINDv9およびインターネットセキュリティに関するPaulVixieおよびDavidConrad」印象的な.net 2018年10月27日取得
  2. ^ 「WMFの問題を見て、どうやってそこにたどり着いたのですか?」MSRC2006年3月24日にオリジナルからアーカイブされました2018年10月27日取得
  3. ^ リッチフィールド、デビッド。「Bugtraq:Oracle、パッチはどこにありますか?」seclists.org 2018年10月27日取得
  4. ^ アレクサンダー、コーンブラスト。「Bugtraq:RE:Oracle、パッチはどこにありますか?」seclists.org 2018年10月27日取得
  5. ^ Cerrudo、Cesar。「Bugtraq:Re:[完全開示] RE:Oracle、パッチはどこにありますか?」seclists.org 2018年10月27日取得

外部リンク