ユーザーを忘れる
ユーザーがメソッドを呼び出すのではなく、他のメソッドを呼び出します。 ユーザーはボタンを押す生きている人であり、あなたの方法については何も知りません。 本当の誤解は、メソッド呼び出しをユーザーにマップすることです。
非常に多くの場合、プログラマーは視覚環境で作業するときにユーザーについての考えを吹き込まれます。 DelphiやVisual Studioなどの環境では、ユーザーが操作しているコントロールのイベント処理を簡単に定義できます。 誘惑に負けやすく、ボタンのフォームエディターをダブルクリックして、ユーザーアクションの処理を決定するアクションを設定することは簡単です。 正式には、これは正しいです。 しかし例を考えてみましょう:
protected void Button1_Click( オブジェクト送信者、 EventArgs e)
{
(ボタンとして送信).Text = "Hello" ;
}
プライベート ボイド MyMethod()
{
Button1_Click( null 、 new EventArgs ());
}
*このソースコードは、 ソースコードハイライターで強調表示されました。
この例は、神話上のユーザーがイベントを制御していることが確実な場合にのみ機能します。 しかし、コードがユーザーによってではなく、別のコードによって制御されている場合、実際の状況の前には無力のままです。
コンテキストはなく、セキュリティ要件のみがあります
Webアプリケーションを扱うときは、どこかで何かが起こったときにのみいくつかの機能を呼び出したり、コントロールを押したりすることを忘れてください。 ユーザーがログインしたこと、今日が月曜日であること、ボタンがPetyaではなくBoryaによって押されたこと。 これらはすべて、コードではなくユーザーを扱っているという考えによってもたらされる幻想です。
たとえば、ログイン後、コントロールパネルにいくつかの機能が表示されるページがあります。 最大の間違いは、このコントロールパネルは許可されていないユーザーが使用できないというあなたの考えかもしれません。 これは非常に単純な誤解であり、多くの人は考えさえしません。
私のプロジェクトにはパネルのあるこのようなページがあり、ページでのキャッシュは禁止されています。緊急の場合はデータベースに登録されます。 また、ページをキャッシュできなかったという事実を考慮しても、権限のないユーザーがアクセスできないと思われるパネルを使用する試みを記録します。
これには非常に簡単な説明があります。ユーザーBoryaは、数日間ページを閉じず、サーバーでのセッションが長時間完了したときに再びページを表示する場合があります。 そして、多分、彼の代わりにペティアがそれをするでしょう、そして、ここで結果はすでに異なっているかもしれません:エラーと不快な沈殿物がある単純なウィンドウから、悪人ペティアによるデータの誘ductionまたは妥協まで。
これはどういう意味ですか? 簡単です。コンテキストを忘れて、安全規則に従ってください。
コードは常に「邪悪な」コードによって呼び出されます
それは妄想のように聞こえますが、そうです。 どのコードとメソッドがどのように呼び出すかは誰にもわかりません。 確実なことは1つだけです。コードは揮発性環境で動作し、すべての必須パラメーター(メソッド引数、グローバル変数、構成ファイルデータ、クエリ文字列など)の必須検証が必要です。
したがって、前の例に値するものをやり直します。
protected void Button1_Click( オブジェクト送信者、 EventArgs e)
{
Button senderButton =(ボタンとして送信);
if (senderButton!= null )
senderButton.Text = "Hello" ;
}
プライベート ボイド MyMethod()
{
Button1_Click( null 、 new EventArgs ());
} *このソースコードは、 ソースコードハイライターで強調表示されています。
例外的な状況は例外的な措置に値する
一度覚えておく価値があります:
1.例外をスローする代わりに、エラーコードメソッドで戻ります-これは悪です。
2.例外はエラーと同義ではありません。
ここでは、エラーコードを実際に考慮するものをすぐに決定する価値があります。 コードがシチュエーションの説明を返す場合、これはシチュエーションの説明ですが、動作を継続できなかったシチュエーションのイベントでコードが値を返す場合、これはエラーコードであり、その呼び出しは例外に置き換える必要があります。
例:
•コードは必要なファイルの存在を確認し、ブール値を返します。falseはファイルが存在しないことを示します。
•コードはファイルの内容を読み取りますが、ある時点でブロックを読み取って終了できず、ブール値または列挙値を返します。
•コードはイメージファイルの存在を確認し、見つからない場合は、値を返さずに例外を発生させずに実行を完了します。
前者の場合、ブール値を返すことはメソッドのタスクであり、後者の場合、例外の説明を返します。 最初のメソッドを変更する必要はありません。2番目のメソッドを変更して例外をスローし、値を返すことを拒否する必要があります。 3番目のケースは、実行された作業の一般的なコンテキストでエラー状況が重要でない一般的なケースです。 この場所で例外を生成すると、些細な瞬間のために重要なコードの実行が停止しますが、これは受け入れられません。
エラーの排他性の程度を判断することは、必ずしも簡単なことではありません。 次のルールをお勧めします。
•エラーコードを返すことは、エラーの状況をテストするメソッドでのみ許可されます。
•エラーが原因でコードを完全に実行できない場合、例外をスローする必要があります。
•解決しようとしている問題のコンテキスト内でコードが以前に知られている可能性のある問題に遭遇した場合、状況の説明を返してコードを完了するか、問題を無視するのが理にかなっています。
すべての答えは否定的です
次のコードを見てください。
列挙型アクセス
{
付与された
制限あり
}
プライベートアクセスCheckLogin( 文字列パスワード)
{
アクセス結果= Access.Granted;
試してみる
{
if (password!= GetValidPassword())
結果= Access.Restricted;
}
つかまえる
{
}
結果を返す ;
} *このソースコードは、 ソースコードハイライターで強調表示されています。
コードは明らかに愚かですが、これは単純化であり、実際にはより複雑な構造を見ることができ、その本質はこのコードに由来します。 ここで何が悪いのですか? はい、GetValidPasswordメソッドで例外が発生した場合、任意のパスワードを持つユーザーがアクセスできます。
結果を返すために、いくつかのルールを定義しました。
•問題に対して例外をスローしないマイナーメソッドでは、ブール値以外のnull不可の型を返すことを避けます。
•値を返すすべてのメソッドはまず、最も負または安全なオプションでこの値を初期化する必要があります(null許容型の場合はnull、boolean型の場合はfalse、列挙型の場合はAccess.Restrictedなどの最も負の値)。
•値を返すには、すべてのメソッドに1つのポイントが必要です。
その結果、次のパターンを区別できます。
プライベートアクセスMyMethod()
{
アクセス結果= Access.Restricted;
//ここにコードを配置します。コードにはreturn呼び出しはなく、resultの値を変更するだけです
結果を返す ;
}
*このソースコードは、 ソースコードハイライターで強調表示されました。
おわりに
この記事では、安全なコードを作成する際の問題に対処しているため、次のルールを区別できます。
•悪意のある環境でコードが機能し、各方法のすべてのセキュリティ要件を満たしている。
•コードが動作する環境が有効かどうか、どのパラメーターが呼び出されたかを確認します。これはユーザーが行うのではなく、別のコードが行うことを忘れないでください。
•デフォルトでは常にコンテキストセーフな値を返します。
•すべてのメソッドには1つの出口点が必要です。
•例外的な状況では例外を使用して、コードの実行が中断されるようにします。
•重要なタスクを完了するために、軽微な問題を無視または処理します。