コードを書くとき、高いプログラム品質を確保し、バッファ オーバーフロー エクスプロイトやコード インジェクションなどによってコードが悪用される可能性を回避するために、意識的に防御的にプログラムしますか?
コードに常に適用する「最低」レベルの品質は?
コードを書くとき、高いプログラム品質を確保し、バッファ オーバーフロー エクスプロイトやコード インジェクションなどによってコードが悪用される可能性を回避するために、意識的に防御的にプログラムしますか?
コードに常に適用する「最低」レベルの品質は?
私の仕事では、コードは最高品質でなければなりません。
そのため、主に次の 2 つの点に焦点を当てています。
それらはお金を家に持ち帰ります。
abyx と同様に、私が所属している開発チームでは、常に単体テストとコード レビューを使用しています。それに加えて、人々が使用する可能性のあるコードを組み込んでいないことを確認することも目指しています。私は、手元のオブジェクトが仕様どおりに機能するために必要なメソッドの基本セットのみのコードを書く傾向があります。 . 使用されることはないかもしれないが機能を提供するメソッドを組み込むと、意図せずに「バックドア」または意図しない/予期しない使用がシステムに導入される可能性があることがわかりました。
後で戻ってメソッド、属性、およびプロパティを導入する方がはるかに簡単です。
「コンポーネント」またはフレームワークに入るデータに対して防御することをお勧めします。「コンポーネント」またはフレームワーク内では、データが「正しい」と考える必要があります。
このように考えています。正しいパラメーターを提供するのは呼び出し元次第です。それ以外の場合、すべての関数とメソッドはすべての着信パラメーターをチェックする必要があります。ただし、チェックが呼び出し元に対してのみ行われる場合、チェックは一度だけ必要です。したがって、パラメーターは「正しい」必要があり、下位レベルに渡すことができます。
バグがあり、呼び出しで間違った値が使用されている場合。本当に正しいtodoとは?プログラムが作業している「データ」が間違っているという兆候があるだけで、ASSERTS のようなものもあれば、高度なエラー報告と可能なエラー回復を使用したいものもあります。いずれにせよ、データに欠陥があることが判明し、ほとんどの場合、作業を続けた方がよい場合があります。(少なくともサーバーが死ななければ良いことに注意してください)
衛星から送信された画像は、エラー アイコンを表示するためにインターネットからダウンロードした画像で高度なエラー リカバリを試行する場合に使用できます...
開発環境ではファシストで、本番環境では慈悲深いコードを書くことをお勧めします。
開発中は、問題が見過ごされたり、根本原因を追跡するのが困難な後で問題が発生したりするのを防ぐために、不良なデータ/ロジック/コードをできるだけ早くキャッチする必要があります。
本番環境では、問題を可能な限り適切に処理します。何かが本当に回復不可能なエラーである場合は、それを処理し、その情報をユーザーに提示します。
例として、ベクトルを正規化するコードを次に示します。開発中に悪いデータを入力すると悲鳴が上がり、本番環境では安全値が返されます。
inline const Vector3 Normalize( Vector3arg vec )
{
const float len = Length(vec);
ASSERTMSG(len > 0.0f "Invalid Normalization");
return len == 0.0f ? vec : vec / len;
}
私の経験では、防御的なプログラミングを積極的に採用することは、必ずしもコードの品質を向上させることを意味するわけではありません。誤解しないでください。ユーザーが遭遇するような問題をキャッチするために防御的にプログラムする必要があります。ユーザーは、プログラムがクラッシュしたときにそれを気に入らないのですが、これによってコードの保守が容易になる可能性はほとんどありません。テストなど。
数年前、ソフトウェアのすべてのレベルでアサーションを使用することをポリシーにしました。これは、単体テスト、コードレビューなどに加えて、既存のアプリケーションテストスイートとともに、コードの品質に大きなプラスの効果をもたらしました。
インジェクション攻撃などを防ぐために常に取り組んでいます。ただし、内部イントラネット サイトで作業する場合、ほとんどのセキュリティ機能は無駄な労力のように感じられます。私はまだそれらをやっていますが、多分そうではありません。
セキュリティには、一定のベスト プラクティスがあります。少なくとも、データベース アプリケーションの場合は、SQL インジェクションに注意する必要があります。
パスワードのハッシュ化、接続文字列の暗号化などの他の機能も標準です。
ここから先は、実際のアプリケーションに依存します。
幸いなことに、.Net などのフレームワークを使用している場合は、多くのセキュリティ保護が組み込まれています。
内部アプリの場合でも、常に防御的にプログラミングする必要があります。ユーザーは運が良ければ、アプリを壊すようなものを書くことができるからです。確かに、お金を騙し取ろうとすることを心配する必要はないかもしれませんが、それでも. 常に防御的にプログラムし、アプリが失敗することを想定してください。
場合によります。
私が本当に自分で何かをハッキングしているのであれば、考える必要のない最高のコードを書きます。コンパイラを警告などの味方にしましょう。しかし、型を自動的に作成するつもりはまったくありません。
コードが使用される可能性が高いほど、場合によっては、チェックのレベルを上げます。
Josh Blochによる効果的な Javaで提唱されているものとして、防御的プログラミングの別の定義を使用します。この本の中で彼は、呼び出し元がコードに渡す可変オブジェクト (セッターなど) と、呼び出し元に渡す可変オブジェクト (ゲッターなど) の処理方法について語っています。
持ち帰り用のメッセージは、内部で使用する変更可能なオブジェクトへのエイリアスを外部コードが保持できないようにすることです。これにより、不変条件を維持できます。
Java、署名付き JAR、および JAAS。
Java を使用して、バッファ オーバーフローとポインタ/スタック ワッキング エクスプロイトを防止します。
JNI を使用しないでください。(Java Native Interface) DLL/共有ライブラリに公開します。
セキュリティ上の問題であるクラスのロードを停止するために JAR に署名しました。
JAAS を使用すると、アプリケーション自体を含め、誰も信頼しないようにすることができます。
J2EE には、ロール ベースのセキュリティのサポートが組み込まれています (確かに制限があります)。
これにはいくらかのオーバーヘッドがありますが、セキュリティ ホールはなくなります。
私は、正しいプログラミングによってこれらのリスクを防ぐことができると強く信じています。(少なくとも Microsoft C++ ライブラリでは) セキュリティの脆弱性のために一般的に非推奨になっている非推奨の関数を回避したり、外部境界を越えるすべてのものを検証したりするなどのことです。
コードからのみ呼び出される関数は、呼び出し元を制御するため、つまり、外部境界を越えないため、過度のパラメーター検証を必要としません。他の人のコードによって呼び出される関数は、受信パラメーターがある時点で無効および/または悪意のあるものになると想定する必要があります。
公開された関数を処理するための私のアプローチは、可能であれば役立つメッセージを表示して、単純にクラッシュすることです。呼び出し元がパラメーターを正しく取得できない場合、問題はコードにあり、あなたではなく、呼び出し元が修正する必要があります。(公開されているため、関数のドキュメントを提供したことは明らかです。)
コード インジェクションは、アプリケーションが現在のユーザーを昇格できる場合にのみ問題になります。プロセスがアプリケーションにコードを挿入できる場合、コードを簡単にメモリに書き込んで実行することができます。システムへのフル アクセスを取得できなければ、コード インジェクション攻撃は無意味です。(これが、管理者が使用するアプリケーションを下位ユーザーが書き込み可能にすべきではない理由です。)
テスト駆動開発を使用すると、確かに役立ちます。一度に 1 つのコンポーネントを作成し、コードを作成する前に (テストを介して) 入力の潜在的なケースをすべて列挙します。これにより、すべての基本をカバーし、誰も使用しないが壊れる可能性のあるクールなコードを作成していないことが保証されます。
私は正式なことは何もしませんが、通常、各クラスを調べて次のことを確認するのに時間を費やします。
簡単な答え:場合によります。防御的なコーディングが多すぎると、重大なパフォーマンスの問題が発生する可能性があります。