ASP.NET MVCカスタムモデルバインダーを使用しているときに、潜在的に危険なRequest.Form値がクライアントから検出されました


95

ここでエラーを取得する:

ValueProviderResult value = bindingContext.ValueProvider.GetValue("ConfirmationMessage");

選択した値のみを許可するにはどうすればよいですか?すなわち

[ValidateInput(false)]
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
    ValueProviderResult value = bindingContext.ValueProvider.GetValue("ConfirmationMessage");
    ValueProviderResult value2 = bindingContext.ValueProvider.GetValue("ConfirmationMessage2");
}

1
潜在的に危険なRequest.Form値の重複の可能性がクライアントから検出されました。それがWebformsであるかMVCであるかは関係ありません。
エリックフィリップス

2
ありがとうございます、でもあなたは私の問題を別のものとして見ていない
DW

まったく同じ根本的な問題、唯一の違いは、MVC固有の方法で対処できる場合があることです。
エリックフィリップス2013年

EFを使用する場合は、ここでbizzehdeeの答えは見stackoverflow.com/questions/17964313/...
ペトル

回答:


223

いくつかのオプションがあります。

モデルで、HTMLを許可する必要がある各プロパティにこの属性を追加します- 最良の選択

using System.Web.Mvc;

[AllowHtml]
public string SomeProperty { get; set; }

コントローラアクションでこの属性を追加して、すべてのHTMLを許可します

[ValidateInput(false)]
public ActionResult SomeAction(MyViewModel myViewModel)

web.configのブルートフォース- 絶対にお勧めしません

web.configファイルのタグ内に、requestValidationMode = "2.0"属性を持つhttpRuntime要素を挿入します。また、pages要素にvalidateRequest = "false"属性を追加します。

<configuration>
  <system.web>
   <httpRuntime requestValidationMode="2.0" />
  </system.web>
  <pages validateRequest="false">
  </pages>
</configuration>

詳細:http : //davidhayden.com/blog/dave/archive/2011/01/16/AllowHtmlAttributeASPNETMVC3.aspx

上記は、デフォルトのモデルバインダーの使用法で機能します。

カスタムModelBinder

上記のコードでbindingContext.ValueProvider.GetValue()を呼び出すと、属性に関係なく、常にデータが検証されるようです。ASP.NET MVCソースを掘り下げると、DefaultModelBinderが最初に要求の検証が必要かどうかを確認してから、検証が必要かどうかを示すパラメーターを使用してbindingContext.UnvalidatedValueProvider.GetValue()メソッドを呼び出すことがわかります。

残念ながら、私たちはフレームワークコードを使用できません。それは、封印されているか、プライベートであるか、または無知の開発者が危険なことを行うのを防ぐためのものですが、AllowHtml属性とValidateInput属性を尊重する機能するカスタムモデルバインダーを作成することはそれほど難しくありません。

public class MyModelBinder: IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        // First check if request validation is required
        var shouldPerformRequestValidation = controllerContext.Controller.ValidateRequest && bindingContext.ModelMetadata.RequestValidationEnabled;

        // Get value
        var valueProviderResult = bindingContext.GetValueFromValueProvider(shouldPerformRequestValidation);
        if (valueProviderResult != null)
        {
            var theValue = valueProviderResult.AttemptedValue;

            // etc...
        }
    }
}

もう1つ必要なのは、未検証の値を取得する方法です。この例では、ModelBindingContextクラスの拡張メソッドを使用します。

public static class ExtensionHelpers
{
    public static ValueProviderResult GetValueFromValueProvider(this ModelBindingContext bindingContext, bool performRequestValidation)
    {
        var unvalidatedValueProvider = bindingContext.ValueProvider as IUnvalidatedValueProvider;
        return (unvalidatedValueProvider != null)
          ? unvalidatedValueProvider.GetValue(bindingContext.ModelName, !performRequestValidation)
          : bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
    }
}

この詳細については、http://blogs.taiga.nl/martijn/2011/09/29/custom-model-binders-and-request-validation/をご覧ください。


私はこれをコントローラ[HttpPost、ValidateInput(false)]に持っていますが、それでもエラーが発生します
DW

カスタムモデルバインダーを使用する場合の回避策については、私の修正された回答を参照してください
ericdc

ありがとう、でもこの行は好きではないbindingContext.GetValueFromValueProvider
DW

GetValueFromValueProviderはパブリック静的クラスにある必要があります。上記の編集内容を確認してください。
ericdc 2013年

Ta、valueProviderResultはnullを返しますか?var valueProviderResult = bindingContext.GetValueFromValueProvider(shouldPerformRequestValidation);
DW 2013年

30

試してください:

HttpRequestBase request = controllerContext.HttpContext.Request;
string re = request.Unvalidated.Form.Get("ConfirmationMessage")

これを試すと、次のような例外が発生します。呼び出しできないメンバー「System.web.HttpRequestBase.Unvalidated」はメソッドのように使用できません。これは変わった?
Stack0verflow 2014

7
2行目は実際にvar re = request.Unvalidated.Form["ConfirmationMessage"];
Stack0verflow

4

@DWからの回答を拡張すると、編集コントローラーで、フォーム値を反復するときに、Request.Params.AllKeyswithのすべてのインスタンスとwithのすべてのインスタンスを置き換える必要がRequest.Unvalidated.Form.AllKeysありRequest[key]ましたRequest.Unvalidated.Form[key]

これが私にとって有効な唯一の解決策でした。


0

マイク・ゴダンあなたは[ValidateInput(偽)]属性を設定した場合でも、書いたように、あなたが使用する必要がありRequest.Unvalidated.Formをするのではなく、あるRequest.Form このASP.NET MVCで私のために働い5


1
これは実際には便利なアドバイスでした。ベースコントローラーからデータにアクセスする(つまり、ログまたはデバッグの目的で)ため、Request.Formへのアクセスは、モデルにこの属性があっても例外をスローします。
nsimeonov

-5

クライアントレベルでエンコードし、サーバーレベルでデコードする手順は次のとおりです。

  1. jquery submitメソッドを使用してフォームを投稿します。

  2. jqueryボタンで、サーバーに投稿するイベントメソッドエンコードフィールドをクリックします。例:

    $("#field").val(encodeURIComponent($("#field").val()))
    $("#formid").submit();
  3. コントローラレベルでは、次を使用してすべてのフォームID値にアクセス

    HttpUtility.UrlDecode(Request["fieldid"])

サンプルの例:

  • コントローラレベル:

    public ActionResult Name(string id)
    {
    
        CheckDispose();
        string start = Request["start-date"];
        string end = Request["end-date"];
        return View("Index", GetACPViewModel(HttpUtility.UrlDecode(Request["searchid"]), start, end));
    }
  • クライアントレベル:

    <% using (Html.BeginForm("Name", "App", FormMethod.Post, new { id = "search-form" }))
    { %>
    <div>
    <label  for="search-text" style="vertical-align: middle" id="search-label" title="Search for an application by name, the name for who a request was made, or a BEMSID">App, (For Who) Name, or BEMSID: </label>
    <%= Html.TextBox("searchid", null, new {value=searchText, id = "search-text", placeholder = "Enter Application, Name, or BEMSID" })%>
    </div>
    <div>
    <input id="start-date" name="start-date" class="datepicker" type="text"  placeholder="Ex: 1/1/2012"/>
    </div>
    <div>
    <input id="end-date" name="end-date" class="datepicker" type="text"  placeholder="Ex: 12/31/2012"/>
    </div>
    <div>
    <input type="button" name="search" id="btnsearch" value="Search" class="searchbtn" style="height:35px"/>
    </div> 
    <% } %>

ドキュメント準備機能では:

$(function () {     
  $("#btnsearch").click(function () {  
    $("#search-text").val(encodeURIComponent($("#search-text").val()));
    $("#search-form").submit();
  });
});

4
jqueryとクライアント側のテクノロジーはMVCとは何の関係もありません。検証はMVCフレームワークを使用してサーバー側で行われます。有効な答えではありません
diegosasw

1
Microsoftが文字通りAllowHtml属性を無視し、サーバー側で実行可能な唯一のソリューションがデフォルトのモデルバインダーの機能を置き換えることであることを考えると、クライアント側のエンコーディングは完全に有効なオプションであると私は主張します。
ジョナサン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.