はじめに
この記事は、Exam Ref 70-483『C#でのプログラミング』の試験対策書籍の私的まとめ その2の続編となります。
Ch.3 Debug applications and implement security
学べるスキル
- アプリケーションへの入力の検証(Validation)
- 対称および非対称暗号化の実行
- アセンブリの管理
- アプリケーションのデバッグ
- アプリケーション診断の実装
要約
- データ検証(バリデーション)は、安全なアプリケーションの重要な要素である。 これはアプリケーション起動時の段階で必ず組み込まなけらばならない。
- JavaScript Object Notation(JSON)は、C#クラス構造を、クラス内の要素に一致する一連の名前と値のペアを含むドキュメント文字列に変換する方法を提供する。型のプライベート要素は自動的に保存されることはないが、保存することもできる。
- Newtonsoft JSONライブラリを使用して、クラスとJSON文字列を相互に変換できる。不正なJSON文字列デコードが指定されると、例外がスローされる。 例外には、エラーのソーステキスト内の位置を説明する情報が含まれている。
- XML(eXtensible Markup Language)は、クラスをテキストドキュメントに変換できるもう1つの手段である。 例外には、エラーのソーステキスト内の位置を説明する情報が含まれている。
- プログラムは、プログラムの実行時に例外を発生させるのではなく、型の使用に関するエラーがコンパイル時に検出されるように、型付きコレクションクラスを使用する必要がある。
- アプリケーションが複数のスレッドを使用する可能性がある場合、コンカレントコレクションクラスを使用する必要がある。
- 正しい形式のコレクション(キュー、スタック、インデックスストレージ、リンクリスト、または辞書)を選択すると、パフォーマンスが向上し、コーディングが容易になる。
- ASP.NET(Active Server Pages)アプリケーションは、Model View Controller(MVC)パターンのModel要素を提供するEntity Frameworkデータストア上に構築できる。このマッピングでは、データのビューはHTML Webページによって提供され、コントローラー(ビューからの入力に応答し、データモデルを更新する)はC#クラスとして作成される。
- オブジェクトの整合性を保持するためにどれだけの労力をかけるかを決定するときは、整合性障害のリスクと、そのような障害がもたらす影響を考慮することが重要である。リスクを特定し、その影響を評価したら、プロジェクトの開始時にリスクを軽減するための労力を割り当てる必要がある。
- 正規表現を使用してデータを編集したり、特定のデータ要素と照合してその構造と内容を検証することもできる。
- C#は、データを文字列値から変換先の型に変換するために
Parse
およびTryParse
動作のビルドを利用できる。変換が失敗する場合、parse
メソッドは例外をスローする。かなり一般的な問題とみなされるべきものに対処するために作成した例外ハンドラの管理が容易となるTryParse
メソッドは、True
またはFalse
を返す。 - C#は、データ変換を実行する多くのメソッドを含むConvertクラスを提供している。
- Entity Frameworkアプリケーションのデータクラスには、バリデーションアクションを示す追加の属性を指定できる。
- 暗号化は、盗聴者が読み取れないメッセージを送信している。 暗号解析は、あなたたちが読むことができないはずのメッセージを読み込んでいる。暗号化とは、プレーンテキスト(メッセージ)を暗号化されたデータに変換するプロセスであり、暗号化されたデータを読み取るには解読する必要がある。 復号化は暗号化の逆である。
- キーは、暗号化および復号化プロセスで使用されるアイテムである。 キーの使用を伴わない暗号化は、言語のパターンおよび会話する当事者の慣習を通じて暗号化のテクニックを明らかにする統計的手法に対して脆弱となる。
- 対称暗号化では、暗号化された会話の両端で同じキーが使用される。 これにより、高レベルのセキュリティが提供され、コンピューターの実行が容易になります。 ただし、会話の両側にキーのコピーが必要である。
- 対称暗号化を実行する.NETライブラリが存在する。 暗号化アルゴリズムは、
SymmetricAlgorithm
抽象クラスの子クラスの形式で公開されているため、暗号化アルゴリズムを簡単に変更できる。暗号化プロセス自体はストリームとして提供されるため、暗号化をデータ転送に簡単に統合できる。 推奨される暗号化メカニズムは、AES(Advanced Encryption Standard)である。 - 非対称暗号化では、送信者と受信者に異なるキーが使用される。 一方のキーで暗号化されたデータは、もう一方のキーで読み取ることができる。 キーを生成するために使用される数学的手法により、一方のキーを他方から推測すること、または暗号化されたデータからいずれかのキーを決定することは非常に計算上困難となる。
- 非対称暗号化を実行するには、より多くのコンピューター処理能力が必要であり、比較的小さなデータパケットにのみ適している。 対称キー値を転送し、デジタル文書に署名してそれらを検証し、その起源を証明するために使用される。
- パブリック/プライベート暗号化では、パーティ(ここではアリスと呼ぶ)が1つの非対称キーを公開し、もう1つのキーをプライベートにする。他の関係者は、この公開鍵を使用して、アリスのみが読み取れるメッセージを暗号化できる。 これは、アリスに暗号化された会話を行うために使用できる対称キーをアリスに送信する方法です。
-
RSACryptoServiceProvider
クラスは、バイトブロックのRSA暗号化を提供します。但し、 ストリームを暗号化するものではない。 キー値(パブリックまたはプライベート)を記述するXMLを生成できる。ユーザーまたはマシンごとに、コンピューターのキーストアにキー値を保存することもできる。 - パブリック/プライベートメカニズムは、安全な通信を確立する便利な方法ですが、身元確認の形式を提供しません。誰でも公開鍵を作成して、アリスであると主張できます。 証明機関は、特定の関係者の身元を検証できる信頼できる関係者です。 パーティー(ここではボブと呼ぶ)は、証明機関によってホストされている証明書によって署名された公開キーをアリスに送信できる。
-
markcert
プログラムを使用して、開発中に使用するテスト証明書を生成できる。 これらはファイルに保存することも、証明機関がホストすることもできる。 - 文書に署名することにより、受信者は文書の送信者、および内容が変更されていないことを判別できる。これを実現するには、プログラムはドキュメントの「ハッシュ」を計算する必要がある。 ハッシュ関数はデータのブロックに適用され、そのブロックに固有のはるかに小さな値(数十バイト)を生成する。 これは「ブロックマニフェスト」と呼ばれる。
- ハッシュ関数は攻撃に対して脆弱である可能性がある。ハッシュ関数を変更せずにドキュメントの内容を変更できる可能性があり、検出できない焼き戻しの可能性が高まる。ブロックマニフェストが長いほど、優れている。 SHA1(Secure Hash Algorithm 1)は危険にさらされているため、使用を推奨しません。 SHA2の方が優れていますが、SHA3は将来標準になる。 実装はGitHubを介して利用可能であるが、SHA3は現在.NETライブラリでサポートされていない。
- アセンブリは、.NETアプリケーションの基本的な構成要素である。 エントリポイントを持つことができ、アプリケーションの開始点として機能する。その場合、拡張子
.exe
を持つか、アセンブリにクラスのライブラリを含めることができる。クラスのライブラリは、必要に応じて動的にロードされ、その場合、アセンブリファイルの拡張子は.dll
となる。 - アセンブリファイルには、アセンブリの内容を記述し、そのアセンブリ内のコードで使用される他のアセンブリを識別するマニフェストが含まれている。
- アセンブリ内のプログラムコードは、Microsoft Intermediate Language(MSIL)で記述されている。これは、.NET互換言語で記述できる元のプログラムソースコードをコンパイルすることによって生成される。
- アセンブリにはバージョン情報が含まれている。 厳密な名前を持つアセンブリは、各アセンブリが対応する公開キーを介して一意に識別できるようにする秘密キーを使用して署名される。 これにより、アセンブリファイルの内容の変更も防止される。
- アセンブリは、グローバルアセンブリキャッシュ(GAC)に保存できる。 これにより、マシン上のアプリケーション間でアセンブリを共有できる。 同じアセンブリの複数のバージョンをGACに「平行」的に保存でき、それぞれが数学上の異なるアプリケーションによって適切に使用される。
- WInRTは、コンパイルされたC ++コードに基づくランタイムシステムである。 .NETアセンブリと同じメタデータの基本を使用して、オブジェクトの動作を表現することができる。動作は、WinMD(Windows MetaData)型のファイルで表現される。これは、既存のC ++のラッパー(Windows APIの場合)にすることも、WinMDファイルにコードを含めることもできる。Windowsランタイムコンポーネント(コードを表す要素。Windowsランタイムコンポーネント(WinMDファイルで動作を表す要素)をC#クラスから作成することは可能だが、WinRTで使用できるC#オブジェクトの動作には制限がある。
- C#コンパイラは、プロセッサディレクティブを理解する。 ディレクティブは、
#
文字が前に付いたコマンドである。#if
ディレクティブを使用して、プログラムのどのコード要素を実際にコードにコンパイルするかを制御できる。 このディレクティブは与えられたシンボルが#define
ディレクティブを使用して定義されているかどうかをテストする。#if
ディレクティブを使用して、プログラムの診断要素のオンとオフを切り替えたり、プログラムのカスタムバージョンを作成できる。 ただし、コードを混乱させる可能性があるため、使いすぎないようにすべし。 -
DEBUG
シンボルは、プログラムがデバッグオプションでコンパイルされている場合に定義される。これは、プログラムのデバッグ時に実行されるコードをアクティブにするために使用できる。 -
#waning
ディレクティブは、プログラムのビルド時に警告メッセージを生成する。 -
#error
ディレクティブは、プログラムのビルド時に指定されたメッセージでコンパイルエラーを生成する。 条件オプションの互換性のない選択が含まれている場合、プログラムがコンパイルされないようにするために使用することができる。 -
#progma
ディレクティブを使用すると、プログラマーは、ソースコードのブロックを識別でき、識別した場合、コンパイラーの警告は無視される。 -
#line
ディレクティブを使用すると、開発者はソースファイルのコンパイルおよびトレース中にVisual Studioによって報告される行番号を設定できる。ソースコードファイルがビルドプロセスの間に自動的に挿入するコードを生成した場合に有用である。#line
ディレクティブを使用して、デバッグプロセスからソースコード行を非表示にすることができる。#line
ディレクティブを使用して、診断メッセージによって拒否されるソースファイルの名前を設定することもできる。 - Visual Studioプロジェクトには、デバッグオプションとターゲットプラットフォームを指定する多数のビルド構成を含めることができる。 新しく作成されたプロジェクトには、デバッグ構成とリリースビルド構成が含まれる。 Visual Studioの構成マネージャーを使用して、ビルド構成を設定し、新しい構成を作成できる。
- デバッグビルドによって生成されるアセンブリには、呼び出されない未使用の変数とメソッドを実装するコードが含まれる。 リリースビルドは未使用の要素を破棄し、プログラムが実行される。 このため、リリースビルドではデバッグブレークポイントを設定できない。
- プログラムがビルドされると、Visual Studioはプログラムデバッグデータベースファイル(PDBファイル)を作成する。このファイルには、プログラムで使用されるシンボルの名前と、それらの値が保存される場所が含まれる。このファイルには、ソースコードステートメントとそれらを実装するMSILへのマッピングも含まれている。 特定のデータベースファイルは、両方のファイルに格納されているGUID(グローバル一意識別子)を使用して特定のソースコードファイルにマップされる。 プログラムデータベースファイルがある場合、プログラムは実行されるが、それがないとデバッグできない。
- プログラムデータベースファイルには、パブリック要素とプライベート要素を含めることができる。パブリック要素とは、パブリックメソッドなど、アセンブリ自体に表示される要素である。プライベート要素には、ローカル変数などが含まれます。 プライベート要素を含むデータベースにアクセスすると、コードがどのように機能するかについての洞察が得られる可能性があり、これは潜在的なセキュリティ問題になる可能性がある。 Debugging Tools for Windowsの一部であるpdbcopyプログラムを使用して、データベースファイルをコピーし、パブリック要素を削除することができる。
-
System.Diagnostics
ライブラリのDebug
クラスとTrace
クラスを使用して、プログラムの実行時にメッセージを生成できる。 アサーションテストにも使用できる。 - デバッグオプションを使用してプログラムをビルドすると、プログラム実行時にデバッグコードが実行される。 デバッグまたはリリースオプションを使用してプログラムをビルドすると、トレースコードが実行される。
-
Trace
オブジェクトは、出力の情報、警告、およびエラーレベルを提供する。 - リスナーは、
Debug
クラスとTrace
クラスにバインドすることができる。 出力の表示、出力のコンマ区切りリスト、およびXML形式のデータとしてのログ出力に使用できるさまざまな形式のリスナーが存在する。 -
TraceSource
クラスは、トレースイベントの生成を管理する。 通常の操作中に生成される情報イベントから、警告、エラー、および重大なイベントまで、いくつかのタイプのイベントが存在する。1つ以上のTraceListener
インスタンスをTraceSource
インスタンスにバインドして、イベントの通知を受け取ることができる。 -
TraceSwitch
クラスを使用して、プログラムによって実行されるトレースのレベルを決定できる。プログラムコードは、TraceSwitch
インスタンスの値をテストして、生成するトレース出力のレベルを決定できる。 -
SourceSwitch
クラスは、TraceSource
インスタンスによって生成されるトレースメッセージを制御するために使用される。SourceSwitch
クラスのインスタンスをTraceSource
に関連付けて、生成するトレースイベントを決定できる。 - トレース出力のレベルは、アプリケーションの構成ファイルに
SourceSwitch
値を作成することでも定義できる。 これにより、アプリケーションの実際のプログラムコードを変更することなく、プログラムのトレース動作を変更できる。 - アプリケーションのプロファイリングは、プログラムの実行時にプロセッサー時間を最も消費している要素を特定するために使用される。これらの要素は、必要に応じてパフォーマンスを改善するために特に最適化できる。 プロファイリングの最も単純な形式は、
Stopwatch
クラスを使用して、プログラムの実行時に経過時間を測定することである。 - Visual Studioには、さまざまなプロファイリングツールが用意されています。 デフォルトのプロファイラーでは、多くのプロファイリングオプションを利用できる。 通常、プログラムがほとんどの時間を費やしている場所を特定するには、最も単純なCPUサンプリングで十分である。このオプションは、コンピューターへの読み込みのプロファイルを作成し、「ホットパス」(実行頻度の高い箇所や実行時間の長い箇所)を表示する。これにより、プロセッサ時間のほとんどを消費するメソッドが特定される。
- パフォーマンスカウンターはオペレーティングシステムによって維持され、メモリやプロセッサの使用など、ホストコンピューターに関するさまざまな情報を表示するために使用できる。
- アプリケーションは、独自のパフォーマンスカウンターを作成および更新できる。 それらの値はオペレーティングシステムによって保持される。値をカウントするだけでなく、1秒あたりのイベント数を評価するものなど、さまざまな種類のカウンターが存在する。プログラムが独自のパフォーマンスカウンターを作成するには、管理者権限が必要となる。
- パフォーマンスカウンターの値は、パフォーマンスモニター
perfmon
プログラムを使用して表示できる。プログラムは、パフォーマンスカウンターを読み取って独自のダッシュボード表示を作成することも可能である。 - オペレーティングシステムは、イベントログも管理する。 プログラムは、独自のイベントカテゴリとイベントタイプを作成し、イベントをログに追加できる。 プログラムがイベントを読み取り、リスナーメソッドを特定のイベントにバインドして、そのイベントが記録されたときに通知を受け取ることも可能である。
関連記事
参考書籍
『Exam Ref 70-483 Programming in C#, 2nd Edition』 By Rob Miles