エクスポート (0) 印刷
すべて展開
展開 最小化

How To: ASP.NET でインジェクション攻撃から保護する方法

Patterns and Practices ホーム

J.D. Meier, Alex Mackman, Blaine Wastell, Prashant Bansode, Andy Wigley

Microsoft Corporation

May 2005
日本語版最終更新日 2006 年 1 月 19 日

適用対象

  • ASP.NET version 1.1
  • ASP.NET version 2.0

概要

このガイドでは、インジェクション攻撃からアプリケーションを保護するために、入力を検証する方法を示します。 入力検証の実行が不可欠なのは、アプリケーション レベルの攻撃はほぼすべて、有害な入力を内包しているからです。

フォーム フィールド、クエリ文字列のパラメータ、および cookie も含めたすべての入力を検証して、有害なコマンド注入からアプリケーションを保護する必要があります。 Web アプリケーションへのすべての入力は有害であると想定し、すべての入力ソースに対してサーバー検証を必ず行ってください。 クライアント側検証を行って、サーバーへのラウンド トリップを削減し、ユーザー エクスペリエンスを改善します。ただし、これをう回するのは簡単なので、頼りすぎないようにします。

入力を検証するには、各アプリケーションの入力フィールドごとに受け入れ可能な入力を定義します。 確実な対策としては、長さ、範囲、フォーマット、およびタイプに関して入力を制約します。 「拒否」 アプローチではなく、「許可」 アプローチをとって、有効な入力を定義します。 「拒否」 アプローチは、非実用的です。好ましくないと思われる入力をすべて事前に想定するのは非常に困難だからです。

ある範囲の HTML 文字を受け入れる必要があるときは、そのデータをあらかじめ HTML エンコードして安全化してから、出力として表示します。

目次

このガイドの目的
はじめに
ステップの概要
ステップ 1 - ASP.NET の検証の要求の使用
ステップ 2 - 入力の制約
ステップ 3 - 安全でない出力のエンコード
ステップ 4 - SQL クエリでのコマンド パラメータの使用
ステップ 5 - ASP.NET エラーがクライアントに戻されないことの検証
関連資料

このガイドの目的

  • 長さ、範囲、フォーマット、およびタイプに関して入力を制約する。
  • 開発中に ASP.NET 検証の要求を適用し、インジェクション攻撃を識別する。
  • ASP.NET バリデータ コントロールを使用して、入力を制約する。
  • 安全でない出力をエンコードする。
  • コマンド パラメータを使用して、SQL 注入を防止する。
  • 詳細なエラー情報がクライアントに戻されないようにする。

はじめに

アプリケーションへの入力が信頼されないものである場合、それらをすべて検証する必要があります。 ユーザーからの入力はすべて有害であると想定しなければなりません。 Web アプリケーションへのユーザー入力には、フォーム フィールド、クエリ文字列、クライアント側 cookie、および、ユーザー エージェント文字列や IP アドレスなどのブラウザ環境値があります。

入力検証が不徹底であると、一般的な弱点がつかれて、アプリケーションが多数のインジェクション攻撃の標的になることがあります。 以下に、入力検証の不徹底または欠如に付け込む一般的なタイプの攻撃を示してあります。

  • SQL 注入。 ユーザー入力に基づいてダイナミック SQL クエリを生成すると、攻撃者が有害な SQL コマンドを注入し、それがデータベースで実行される可能性があります。
  • クロスサイト スクリプト。 クロスサイト スクリプト (XSS) アタックでは、クライアント側スクリプト コードの挿入によって、Web ページの検証における弱点がつかれます。 そのコードは次に、疑いを抱いていないユーザーのコンピュータに送られて、ブラウザ上で実行されます。 ブラウザは信頼サイトからスクリプト コードをダウンロードしたのだから、そのコードが適正かどうかの判断を下す必要もないはずです。
  • 無許可のファイル アクセス。 呼び出し元の入力を受け入れるようになっているコードの場合、不純な意図をもったユーザーが、コードのファイル操作を細工する可能性があります。たとえば、アクセスしてはならないファイルにアクセスしたり、有害データを注入することによって、コードを悪用したりすることができます。

注意   インジェクション攻撃は、HTTP および HTTPS SSL (Secure Sockets Layer) 接続上でも威力をもちます。 暗号化しても、防護することはできません。

入力検証の場合の一般アプローチを以下に要約してあります。 このアプローチは、ネットワークから着信するすべての入力に対して適用する必要があります。そのような入力には、テキスト ボックスやその他のフォーム フィールドの入力、クエリ文字列パラメータ、cookie、サーバー変数、および Web メソッド パラメータなどがあります。 この戦略では、まず正常な入力のみを許可し、次に有害な入力を拒否することに注意してください。 その理由は、アプリケーションにとって正常な入力は簡単に定義できますが、有害な入力のフォーマットをすべて予測することは事実上不可能だからです。

次のようにして、有効な入力をチェックします。

  • 制約: タイプ、長さ、フォーマット、および範囲を検証して、既知の正常なデータかどうかをチェックします。 サーバー コントロールからの入力を制約するには、ASP.NET バリデータ コントロールを使用します。 その他のソースからの入力を制約するには、正規表現とカスタム検証を使用します。
  • 拒否: 既知の有害データかどうかをチェックし、有害入力を拒否します。
  • 清浄化: 場合によっては、入力を清浄化して、潜在的に有害な入力を安全化する必要もあります。 たとえば、コメント フィールドなどの自由形式の入力フィールドがアプリケーションでサポートされている場合、<b> や <i> などの安全な HTML 要素だけ許可し、他のすべての HTML 要素を排除することができます。

ステップの概要

ASP.NET アプリケーションをインジェクション攻撃から保護するには、次のようなステップを行います。

  • ステップ 1 - ASP.NET の検証の要求の使用
  • ステップ 2 - 入力の制約
  • ステップ 3 - 安全でない出力のエンコード
  • ステップ 4 - SQL クエリでのコマンド パラメータの使用
  • ステップ 5 - ASP.NET エラーがクライアントに戻されないことの検証

この後、上記の項目を 1 つずつ解説します。

ステップ 1 - ASP.NET の検証の要求の使用

既定では、ASP.NET version 1.1 および 2.0 の検証の要求では、サーバーに送られたデータ内のすべての HTML 要素と予約文字が検出されます。 それによって、ユーザーはアプリケーションにスクリプトを挿入できなくなります。 検証の要求では、潜在的に危険な値をハードコーディングしたリストに照らし合わせて、すべての入力データがチェックされます。 一致が生じた場合、タイプ HttpRequestValidationException の例外がスローされます。

検証の要求を無効にするには、Web.config アプリケーション構成ファイル内で、validateRequest="false" を指定した <pages> 要素を追加するか、または、個々のページ上で、@ Pages 要素に ValidateRequest="false" を設定します。

検証の要求を無効にする必要が生じても、該当するページ上でのみ無効にしてください。 そのような例としては、HTML フォーマットの入力を受け入れる自由形式のテキスト フィールドを備えたページがあります。

ASP.NET の検証の要求が Machine.config 内で有効になっていることの確認

検証の要求は、ASP.NET 内で既定として有効になっています。 以下のような既定の設定を、Machine.config.comments ファイルで確認することができます。

<pages validateRequest="true" ... />

サーバーの Machine.config ファイルまたはアプリケーションの Web.config ファイル内でこの既定設定を指定変更して、検証の要求を無効にしていないことを確認してください。

ASP.NET の検証の要求のテスト

検証の要求の効果をテストすることができます。 テストするには、次のように、ValidateRequest="false" を設定して、検証の要求を無効にした ASP.NET ページを作成します。

<%@ Language="C#" ValidateRequest="false" %>
&#60;&#104;&#116;&#109;&#108;&#32;&#120;&#109;&#108;&#110;&#115;&#61;&#34;&#104;&#116;&#116;&#112;&#58;&#47;&#47;&#119;&#119;&#119;&#46;&#119;&#51;&#46;&#111;&#114;&#103;&#47;&#49;&#57;&#57;&#57;&#47;&#120;&#104;&#116;&#109;&#108;&#34;&#32;&#62;

<script runat="server">
void btnSubmit_Click(Object sender, EventArgs e)
{
// ValidateRequest が false の場合、'hello' と表示されます。
// ValidateRequest が true の場合、ASP.NET から例外が戻されます。
Response.Write(txtString.Text);
}
</script>
<body>
<form id="form1" runat="server">
<asp:TextBox id="txtString" runat="server"
Text="<script>alert('hello');</script>" />
<asp:Button id="btnSubmit" runat="server" OnClick="btnSubmit_Click"
Text="Submit" />
</form>
</body>
</html>

このページを実行すると、メッセージ ボックスに "Hello" と表示されます。txtString 内のスクリプトが引き渡されて、ブラウザ内でクライアント側スクリプトとしてレンダリングされるからです。

ValidateRequest="true" を設定するか、または ValidateRequest ページ属性を除去した場合、ASP.NET の検証の要求によって、スクリプト入力が拒否されて、以下のようなエラーが生成されます。

A potentially dangerous Request.Form value was detected from the client
(txtString="<script>alert('hello...").
注意   ASP.NET の検証の要求に頼りきらないでください。 ご自分で行う入力検証以外の追加の対抗手段として扱ってください。

ステップ 2 - 入力の制約

入力を制約するときは、以下のガイドラインを参考にしてください。

  • サーバー側入力検証を使用します。 クライアント側検証は、簡単にう回できるので、頼りきらないでください。 サーバー側検証に加えて、クライアント側検証を行い、サーバーへのラウンド トリップを削減し、ユーザー エクスペリエンスを改善します。
  • 長さ、範囲、フォーマット、およびタイプを検証します。 既知の正常な入力に関するガイドラインに、すべての入力が必ず準拠するようにします。
  • 強力なデータ タイプを使用します。 数値を、整数または倍精度などの、数値データ タイプに割り当てます。 文字列の値を文字列データ タイプに割り当てます。 日付を日時指定データ タイプに割り当てます。

サーバー コントロールを通して入力を取得する Web フォーム アプリケーションの場合、ASP.NET バリデータ コントロールを使用して入力を制約します。 クエリ文字列、cookie、および HTTP ヘッダーなどの、その他の入力データ ソースの場合、System.Text.RegularExpressions 名前空間の Regex クラスを使用して入力を制約します。

フォーム フィールドからの入力の明示的なチェック

サーバー コントロールを通して受信するフォーム フィールドの入力を制約するには、以下の ASP.NET バリデータ コントロールを使用することができます。

  • RegularExpressionValidator。 このコントロールは、テキスト入力を制約するのに使用します。
  • RangeValidator。 このコントロールは、数値、通貨、日付、および文字列の入力の範囲をチェックするのに使用します。
  • CustomValidator。 カスタム検証に対してこのコントロールを使用します。たとえば、日付が必ず将来または過去の日付になるようにするために使用します。

HTML 入力コントロールを通して受信したフォーム フィールド入力を検証するには、サーバー側コードで検証を実行し、Regex クラスを使用して、テキスト入力を制約しやすくします。 この後、さまざまな一般入力タイプを制約する方法について説明します。

テキスト フィールドの検証
  • 名前、アドレス、および納税者識別番号などの、テキスト フィールドを検証するには、以下を行う正規表現を使用します。
  • 入力文字の許容範囲を制約します。
  • フォーマット規則を適用します。 たとえば、納税者識別番号や郵便番号などのパターン ベースのフィールドでは、特定のパターンの入力文字が義務付けられます。
  • 長さをチェックします。

RegularExpressionValidator の使用

RegularExpressionValidator を使用するには、以下の例に示されているとおり、ControlToValidateValidationExpression、および ErrorMessage プロパティをそれぞれ適した値に設定します。

<form id="WebForm" method="post" runat="server">
<asp:TextBox id="txtName" runat="server"></asp:TextBox>
<asp:RegularExpressionValidator id="nameRegex" runat="server"
ControlToValidate="txtName"
ValidationExpression="^[a-zA-Z'.\s]{1,40}$"
ErrorMessage="Invalid name">
</asp:regularexpressionvalidator>
</form>

上記のコード サンプルで使用されている正規表現では、名前の入力フィールドは、英字 (小文字および大文字)、間隔文字、 O'Dell のような名前中で使用される単一アポストロフィ、およびピリオドに制限されます。 それ以外に、フィールド長は 40 文字に制約されます。

注意   RegularExpressionValidator コントロールの場合、脱字記号 (^) とドル記号 ($) をユーザーが追加しないと、式の先頭と末尾にこれらが区切り文字として自動的に追加されます。 すべての正規表現にこれらの記号を追加するのが得策です。 表現を区切り文字で囲むことによって、その表現が所定どおりの内容だけで構成されるようにすることができます。
Regex クラスの使用

サーバー コントロールを使用していない (つまり、バリデータ コントロールを使用できないということ) 場合や、フォーム フィールド以外のソース (クエリ文字列パラメータまたは cookie など) からの入力を検証する必要がある場合、Regex クラスを使用することができます。

Regex クラスの使用

  1. System.Text.RegularExpressions 名前空間を参照する using ステートメントを追加します。
  2. 正規表現を必ず ^ と $ アンカー文字で囲みます (文字列の先頭と末尾)。
  3. 以下のコード サンプルに示されているとおり、Regex クラスの IsMatch メソッドを呼び出します。

// インスタンス メソッド:
Regex reg = new Regex(@"^[a-zA-Z'.\s]{1,40}$");
Response.Write(reg.IsMatch(txtName.Text));

// 静的メソッド:
if (!Regex.IsMatch(txtName.Text,@"^[a-zA-Z'.\s]{1,40}$"))
{
// 名前は表現に一致しません。
}

頻繁に使用するために正規表現をキャッシュに入れられない場合、パフォーマンス上の理由から、可能なかぎり静的 IsMatch メソッドを使用して、不要なオブジェクトが作成されないようにする必要があります。

数値フィールドの検証

たいていの場合、数値フィールドの場合はタイプと範囲をチェックする必要があります。 サーバー コントロールを使用する数値入力フィールドのタイプと範囲を検証するときは、RangeValidator コントロールを使用することができます。 RangeValidator は、通貨、日付、整数、倍精度、および文字列の各データ タイプをサポートします。

RangeValidator を使用するには、以下の例に示されているとおり、ControlToValidateTypeMinimumValueMaximumValue、および ErrorMessage の各プロパティを、それぞれに適した値に設定します。

<asp:RangeValidator
ID="RangeValidator1"
Runat="server"
ErrorMessage="Invalid range. Number must be between 0 and 255."
ControlToValidate="rangeInput"
MaximumValue="255"
MinimumValue="0" Type="Integer" />

サーバー コントロールを使用しない場合に数値範囲を検証するときは、入力値を整数に変換してから、範囲チェックを実行することができます。 たとえば、整数が有効であることを検証するには、新規の Int32.TryParse メソッド (Microsoft .NET Framework version 2.0 で導入されました) を使用して、入力値をタイプ System.Int32 の変数に変換します。 タイプ変換が失敗した場合、このメソッドから false が戻されます。

Int32 i;
if (Int32.TryParse(txtInput.Text, out i) == false)
{
// 変換は失敗しました。
}

旧バージョンの .NET Framework を使用している場合、try/catch ブロック内部で Int32.Parse または Convert.ToInt32 を使用して、入力値が正しいタイプでなかった場合にスローされるタイプ FormatException のすべての例外を処理することができます。

以下のコードは、HTML テキスト入力コントロールを介して入力された整数のタイプと範囲のチェックを実行する方法を示しています。

<%@ Page Language="C#" %>

<script runat="server">

void Page_Load(object sender, EventArgs e)
{
if (Request.RequestType == "POST")
{
int i;
if (Int32.TryParse(Request.Form["integerTxt"], out i) == true)
{
// 変換が正常に完了すると、TryParse から true が戻されます。
if ((0 <= i && i <= 255) == true)
{
Response.Write("Input data is valid.");
}
else
Response.Write("Input data is out of range");
}
else
Response.Write("Input data is not an integer");
}
}

</script>

&#60;&#104;&#116;&#109;&#108;&#32;&#120;&#109;&#108;&#110;&#115;&#61;&#34;&#104;&#116;&#116;&#112;&#58;&#47;&#47;&#119;&#119;&#119;&#46;&#119;&#51;&#46;&#111;&#114;&#103;&#47;&#49;&#57;&#57;&#57;&#47;&#120;&#104;&#116;&#109;&#108;&#34;&#32;&#62;

<body>
<form id="form1" action="NumericInput.aspx" method="post">
<div>
Enter an integer between 0 and 255:
<input name="integerTxt" type="text" />
<input name="Submit" type="submit" value="submit" />
</div>
</form>
</body>
</html>
日付フィールドの検証

日付フィールドが正しいタイプであることを検証する必要があります。 たいていの場合、その範囲もチェックする必要があります。それによって、たとえば、日付が将来または過去のものであることを検証します。 サーバー コントロールを使用して入力日付を捕捉する場合に、ある特定の範囲内に日付が収まっていることを検証する必要もあるときは、Type フィールドを Date に設定した RangeValidator コントロールを使用することができます。 このコントロールを介して、定数の日付値を使用して範囲を指定することができます。 たとえば、日付が将来または過去のものであることを検証するために、今日の日付をベースにして日付範囲を検証する必要がある場合、CustomValidator コントロールを使用することができます。

CustomValidator コントロールを使用して日付を検証するには、検証ロジックを擁するカスタム メソッドを指すように、ControlToValidate および ErrorMessage プロパティと、OnServerValidate イベントを設定します。 以下のサンプル .aspx ページ コードは、そのようなアプローチを示しています。

<%@ Page Language="C#" %>

<script runat="server">

void ValidateDateInFuture(object source, ServerValidateEventArgs args)
{
DateTime dt;

// 有効な日付をチェックし、その日付が将来のものであることをチェックします。
if ((DateTime.TryParse(args.Value, out dt) == false) ||
(dt <= DateTime.Today))
{
args.IsValid = false;
}
}

</script>

&#60;&#104;&#116;&#109;&#108;&#32;&#120;&#109;&#108;&#110;&#115;&#61;&#34;&#104;&#116;&#116;&#112;&#58;&#47;&#47;&#119;&#119;&#119;&#46;&#119;&#51;&#46;&#111;&#114;&#103;&#47;&#49;&#57;&#57;&#57;&#47;&#120;&#104;&#116;&#109;&#108;&#34;&#32;&#62;

<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="Label1" Runat="server"
Text="Future Date:"></asp:Label>
<asp:TextBox ID="futureDatetxt" Runat="server"></asp:TextBox>
<asp:CustomValidator
ID="CustomValidator1" Runat="server"
ErrorMessage="Invalid date. Enter a date in the future."
ControlToValidate="futureDatetxt"
OnServerValidate="ValidateDateInFuture">
</asp:CustomValidator>
<br />
<asp:Button ID="submitBtn" Runat="server" Text="Submit"  />
</div>
</form>
</body>
</html>
注意   上記のコードでは、.NET Framework 2.0 の新機能である DateTime.TryParse が使用されています。

フリー テキスト フィールドの清浄化

入力を清浄化 するには、信頼されない入力がコードとして取り扱われないようにして、その入力を安全化します。 たとえば、アプリケーションが制約できないユーザー入力を取り扱う場合や、共用データベースからデータを読み取る場合、そのデータをページに書き込むときに、そのデータを清浄化するか、または出力を安全化する必要があります。 HttpUtility.HtmlEncode を使用して、出力の前にデータを清浄化してください。

制限付きの HTML 入力の使用可能化

たとえば、コメント フィールドなどのリッチ テキスト入力フィールドを通して、ある範囲の HTML 要素をアプリケーションが受け入れる必要がある場合、ASP.NET の検証の要求をオフにし、アプリケーションで受け入れようとしている HTML 要素だけを許容するフィルタを作成します。 一般的な対策としては、<b> (太字) や <i> (イタリック) といった、安全な HTML 要素のみにフォーマットを限定します。 データを書き込む前に、HTML エンコードします。 それによって、そのデータは、実行可能コードではなくテキストとして処理されることになるので、有害なスクリプトがすべて安全化されます。

制限付きの HTML 入力の使用可能化

  1. ValidateRequest="false" 属性を @ Page ディレクティブに追加して、ASP.NET の検証の要求を無効にします。
  2. HtmlEncode メソッドを使用して、文字列入力をエンコードします。
  3. StringBuilder を使用し、その Replace メソッドを呼び出して、許可しても差し支えのない HTML 要素に対するエンコードをより分けて除去します。

以下の .aspx ページ コードに、そのようなアプローチを示しています。 このページでは、ValidateRequest="false" が設定され、ASP.NET の検証の要求が無効になっています。 ここでは、入力が HTML エンコードされ、選択に応じて <b> と <i> の HTML 要素が、単純なテキスト フォーマットをサポートできるようになります。

<%@ Page Language="C#" ValidateRequest="false"%>
&#60;&#104;&#116;&#109;&#108;&#32;&#120;&#109;&#108;&#110;&#115;&#61;&#34;&#104;&#116;&#116;&#112;&#58;&#47;&#47;&#119;&#119;&#119;&#46;&#119;&#51;&#46;&#111;&#114;&#103;&#47;&#49;&#57;&#57;&#57;&#47;&#120;&#104;&#116;&#109;&#108;&#34;&#32;&#62;

<script runat="server">

void submitBtn_Click(object sender, EventArgs e)
{
//  文字列入力をエンコードします。
StringBuilder sb = new StringBuilder(
HttpUtility.HtmlEncode(htmlInputTxt.Text));
// <i> をより分けてサポート可能にします
sb.Replace("&lt;b"&gt;", "&lt;b&gt;");
sb.Replace("&lt;/b&gt;", "");
sb.Replace("&lt;i&gt;", "&lt;i&gt;");
sb.Replace("&;/i&gt;", "");
Response.Write(sb.ToString());
}
</script>

<html xmlns="http://www.w3.org/1999/xhtml" ;>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="htmlInputTxt" Runat="server"
TextMode="MultiLine" Width="318px"
Height="168px"></asp:TextBox>
<asp:Button ID="submitBtn" Runat="server"
Text="Submit" OnClick="submitBtn_Click" />
</div>
</form>
</body>
</html>

クエリ文字列の値の検証

長さ、範囲、フォーマット、およびタイプに関してクエリ文字列の値を検証します。 それには通常、正規表現を組み合わせて使用して、次のようにします。

  • 入力値を制約します。
  • 明示的な範囲チェックを設定します。
  • 実行する明示的なタイプ チェックを指定します。それには、入力値をそれと同等の .NET Framework タイプに変換し、その結果のすべての変換エラーを処理します。

以下のコード サンプルは、Regex クラスを使用して、クエリ文字列で渡された名前文字列を検証する方法を示しています。

void Page_Load(object sender, EventArgs e)
{
if (!System.Text.RegularExpressions.Regex.IsMatch(
Request.QueryString["Name"], @"^[a-zA-Z'.\s]{1,40}$"))
Response.Write("Invalid name parameter");
else
Response.Write("Name is " + Request.QueryString["Name"]);
}

cookie 値の検証

クエリ文字列パラメータなどの、cookie 内に保存されている値は、クライアントで簡単に細工することができます。 cookie 値は、クエリ文字列パラメータの場合と同じ方法で検証します。 すなわち、その長さ、範囲、フォーマット、およびタイプを検証します。

ファイルおよび URL パスの検証

入力ファイル名、ファイル パス、または URL パスをアプリケーションで受け入れる必要がある場合、パスが正しいフォーマットになっていて、アプリケーションのコンテキストに沿った有効な場所を指していることを検証する必要があります。 そうしないと、攻撃者はアプリケーションを思惑通りに操って、任意のファイルとリソースにアクセスしてしまう可能性があります。

ファイル パスの検証

有害なユーザーがコードのファイル操作を細工できないようにするには、ユーザー提供のファイルやパス入力を受け入れるコードを作成しないようにします。 たとえば、次のようにします。

  • ファイル名を入力として受け入れる必要がある場合、System.IO.Path.GetFileName の使用を介して、ファイルの絶対パス名を使用します。
  • ファイル パスを入力として受け入れる必要がある場合、System.IO.Path.GetFullPath の使用を介して、ファイルの絶対パスを使用します。

アプリケーション間マッピングの防止のための MapPath の使用

MapPath を使用して、入力された仮想パスを、サーバー上の物理パスにマップする場合、bool パラメータを受け入れる Request.MapPath の多重定義を使用して、アプリケーション間マッピングを防止できるようにします。 以下のコード サンプルは、その技法を示しています。

try
{
string mappedPath = Request.MapPath( inputPath.Text,
		   Request.ApplicationPath, false);
}
catch (HttpException)
{
// アプリケーション間マッピングが行われようとしました。
}

最後の false パラメータによって、アプリケーション間マッピングが阻止されます。 これは、ユーザーが、".." を使用したパスを入力して、アプリケーションの仮想ディレクトリ階層外に出ようとしても、失敗することを意味します。 そのような試みはすべて、タイプ HttpException の例外に帰結します。

サーバー コントロールの使用時は、Control.MapPathSecure メソッドを使用して、仮想パスのマップ先の物理パスを検索することができます。 Control.MapPathSecure は、コード アクセス セキュリティを使用し、その結果のマップ済みのファイルを読み取る許可がそのサーバー コントロールにないと、HttpException をスローします。 詳細は、.NET Framework SDK の資料の中の Control.MapPathSecure を参照してください。

ファイル I/O の制限のためのコード アクセス セキュリティの使用

管理者は、中の信頼度で稼働するようにアプリケーションを構成して、アプリケーションのファイル I/O をそれ自身の仮想ディレクトリ階層内に限定することができます。 その場合、.NET コード アクセス セキュリティによって、アプリケーションの仮想ディレクトリ階層外では、どのファイル アクセスも決して許可されないようになります。

中の信頼度で稼動するようにアプリケーションを構成するには、Web.config または Machine.config で、<trust> 要素を設定します。

<trust level="Medium" />
URL の検証

以下のような正規表現を使用して、有効な URL フォーマットをフィルタすることができます。

^(?:http|https|ftp)://[a-zA-Z0-9\.\-]+
(?:\:\d{1,5})?(?:[A-Za-z0-9\.\;\:\@\&\=\+\$\,\?/]
|%u[0-9A-Fa-f]{4}|%[0-9A-Fa-f]{2})*$

これで、入力は制約されますが、アプリケーション境界の見地から URL が有効かどうかの検証は行われません。 アプリケーションのコンテキストに沿って、ターゲットが有効かどうかをチェックする必要があります。 たとえば、アプリケーションの通信相手であるはずの許可済みのサーバーを指しているかどうかをチェックします。

ステップ 3 - 安全でない出力のエンコード

Web ページに出力されるテキストを作成する場合、HttpUtility.HtmlEncode を使用してエンコードします。 これを行うのは、ユーザー入力、データベース、またはローカル ファイルからテキストを取り込んだ場合です。

同様に、入力データまたは共用データベースのデータで作成したという理由で安全でないかもしれない文字を使用して URL を作成する場合は、HttpUtilty.UrlEncode を使用して安全化を図ります。

早すぎる時点でデータをエンコードするという過ちを犯さないでください。 必ず、クライアントに対してデータを表示する前の、可能なかぎり遅い時点でエンコードを行ってください。

安全でない出力のエンコードのための HtmlEncode の使用

HtmlEncode メソッドによって、特殊な意味をもつ文字を表わす HTML から HTML への変数内で、その文字が置き換えられます。 たとえば、< は &lt; に置き換えられ"&quot; に置き換えられます。 データをエンコードしても、ブラウザがそのコードを実行する原因にはなりません。 それどころか、データは無害なテキストに生まれ変わり、タグは HTML と解釈されなくなります。

HtmlEncode の使用法を示した以下のページでは、ユーザーからの入力が受け入れられ、ValidateRequest="false" の設定によって、潜在的に安全でない HTML 文字が許容されます。 入力を元のユーザーに書き戻す前に、入力されたテキストに対して HttpUtility.HtmlEncode がコードによって呼び出されます。 それによって、潜在的に安全でない HTML はすべて、無害なテキストに変わります。

<%@ Page Language="C#" ValidateRequest="false"%>

<script runat="server">
void submitBtn_Click(object sender, EventArgs e)
{
Response.Write(HttpUtility.HtmlEncode(inputTxt.Text));
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="inputTxt" Runat="server"
TextMode="MultiLine" Width="382px" Height="152px">
</asp:TextBox>
<asp:Button ID="submitBtn" Runat="server" Text="Submit"
OnClick="submitBtn_Click" />
</div>
</form>
</body>
</html>

HTML エンコードの効果を確かめるには、上記のページを仮想ディレクトリ内に置き、それをブラウズし、何らかの HTML コードを入力テキスト ボックスに入力し、[Submit] をクリックします。 たとえば、次のような入力がテキストに変わります。

Run script and say hello <script>alert('hello');</script>

上記は、次のような安全な出力を生じます。

Run script and say hello <script>alert('hello');</script>

HtmlEncode の呼び出しを除去し、入力を単に書き戻すだけにすると、ブラウザはスクリプトを実行してメッセージ ボックスを表示します。 有害なスクリプトは、多大な脅威を生じる可能性があります。

安全でない URL のエンコードでの UrlEncode の使用

完全には信頼していない入力に基づいて URL を作成する必要がある場合、HttpUtility.UrlEncode を使用して URL 文字列をエンコードします。

HttpUtility.UrlEncode( urlString );

ステップ 4 - SQL クエリでのコマンド パラメータの使用

SQL 注入の防止の一策として、SQL クエリに対してコマンド パラメータを使用します。 Parameters コレクションを使用して、タイプ チェックと長さの検証を行うことができます。 Parameters コレクションを使用すると、入力はリテラル値として扱われ、SQL で実行可能コードとして扱われることはありません。 Parameters コレクションを使用した場合の別の利点として、タイプと長さのチェックを実施することができます。 値が範囲外であると、例外が起動されます。

ストアド プロシージャの呼び出し時の Parameters コレクションの使用

以下のコード断片は、ストアド プロシージャを呼び出すための Parameters コレクションの使用法を示しています。

SqlDataAdapter myCommand = new SqlDataAdapter("AuthorLogin",
		 myConnection);
myCommand.SelectCommand.CommandType = CommandType.StoredProcedure;
SqlParameter parm = myCommand.SelectCommand.Parameters.Add(
		   "@LoginId", SqlDbType.VarChar, 11);
parm.Value = Login.Text;

SQL ステートメントの作成時の Parameters コレクションの使用

ストアド プロシージャを使用できない場合でも、以下のコードに示されているとおり、パラメータを使用することはできます。

SqlDataAdapter myCommand = new SqlDataAdapter(
"SELECT au_lname, au_fname FROM Authors WHERE au_id = @au_id", myConnection);
SQLParameter parm = myCommand.SelectCommand.Parameters.Add(
"@au_id" ,SqlDbType.VarChar, 11);
Parm.Value = Login.Text;

SQL 注入の防止方法の詳細は、How To: ASP.NET で SQL 注入から保護する方法 を参照してください。

ステップ 5 - ASP.NET エラーがクライアントに戻されないことの検証

<customErrors> 要素を使用して、アプリケーションの例外条件の発生時にクライアントに戻すカスタムの汎用エラー メッセージを構成することができます。

以下の例に示されているとおり、Web.config ファイル内で、mode 属性を必ず "remoteOnly"に設定してください。

<customErrors mode="remoteOnly" />

ASP.NET アプリケーションのインストール後、以下の例に示されているとおり、カスタムのエラー ページを指すように、設定値を変更することができます。

<customErrors mode="On" defaultRedirect="YourErrorPage.htm" />

関連資料

インジェクション攻撃からアプリケーションを保護する方法の詳細は、以下の資料を参照してください。


ご意見、ご提案

このガイドに関するご意見、ご提案等がございましたら、Wiki またはメールでお寄せください。


特に、以下に関するご意見、ご提案をお待ちしております。

  • 推奨事項に関する技術的な問題
  • 実用性および利便性に関する問題

テクニカル サポート

本ガイドに記載されているマイクロソフトの製品およびテクノロジに関するテクニカル サポートは、Microsoft Support Services で対応いたします。製品サポートの詳細につきましては、Microsoft Support のサイト http://support.microsoft.com/ を参照してください。

コミュニティおよびニュースグループ

次のフォーラムおよびニュースグループより、コミュニティ サポートが提供されています。


上手なご利用方法としては、実際にお使いのテクノロジあるいは実際の問題に対応したニュースグループを参照していただくとよいでしょう。たとえば、ASP.NET のセキュリティ機能に関する問題が発生している場合は、ASP.NET Security フォーラムのご利用をお奨めします。

ご協力いただいた方々

  • ご協力いただいた社外の方々: Andy Eunson; Chris Ullman, Content Master; David Raphael, Rudolph Araujo, Foundstone Professional Services; Manoranjan M. Paul
  • MCS (Microsoft Consulting Services) および PSS 関係者: Wade Mascia, Tom Christian, Adam Semel, Nobuyuki Akama, Microsoft Corporation
  • MPD (Microsoft Product Group) 関係者: Stefan Schackow, Vikas Malhotra, Microsoft Corporation
  • MSDN 関係者: Kent Sharkey, Microsoft Corporation
  • Microsoft IT 関係者: Eric Rachner, Shawn Veney (ACE Team), Microsoft Corporation
  • テスト チーム: Larry Brader, Microsoft Corporation; Nadupalli Venkata Surya Sateesh, Sivanthapatham Shanmugasundaram, Sameer Tarey, Infosys Technologies Ltd
  • 編集チーム: Nelly Delgado, Microsoft Corporation; Sharon Smith, Tina Burden McGrayne, Linda Werner & Associates Inc
  • リリース管理: Sanjeev Garg, Microsoft Corporation

Patterns and Practices ホーム


表示:
© 2014 Microsoft