Answered by:
MVC3 RC & ValidateInput

Question
-
User-1041395518 posted
Hi,
I installed MVC 3 RC, was using MVC 3 Beta before. On controller actions that have the ValidateInput(false) attribute now break, meaning that I get a potentially dangerous input error message when submitting HTML tags. I've been reading about the SkipRequestVerification attribute, but that applies to model attributes. In my situation, various actions will use the same generic model so I can't apply it on the model itself but rather on the action as some will allow html tags and some will not. Also, my model is in another assembly so am I to assume that this assembly which holds nothing but linq to sql models, should reference System.Web.Mvc just for this attribute?? Is there any way to disable this SkipRequestVerification processing? Or does anyone know why suddenly ValidateInput stopped working?
Thanks
Tuesday, November 9, 2010 7:24 PM
Answers
-
User-797310475 posted
We've made some under-the-covers changes to how request validation works. The short of it is that in the past any input submitted to your application caused a validation error, even if your application did not actually ever look at that input. In MVC 3 we've made it so that in certain scenarios (for example model-binding to models using SkipRequestValidation) request validation is performed on-demand or does not happen at all. However, not all scenarios currently support this and binding to a FormCollection falls into that category. We will consider improving this scenario, though no promises right now.
Regarding why your ValidateInput(false) attribute has no effect, this is related to the fact that request validation got moved to a different point in the ASP.NET processing pipeline in .NET 4 and this attribute will not work in this particular scenario unless you specify 2.0-mode request validation.
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Wednesday, November 10, 2010 3:11 AM -
User-1660457439 posted
Thanks for the sample. We're seeing what we can do about this for the next release. You should be able to work around it in the meantime by changing your controller code to the following:
[HttpPost] [ValidateInput(false)] public ActionResult LogOn(LogOnModel model, string returnUrl) { FormCollection form = new FormCollection(Request.Unvalidated().Form); \\ ... }
The Request.Unvalidated() extension method is located in the System.Web.Helpers namespace.
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Wednesday, November 10, 2010 8:20 PM -
User-1660457439 posted
I'm not having much luck on the MVC 3 ugrade. On pages that have controller actions for both get and post I'm receiving errors on the Get related to antiforgery.This is a different issue. After upgrading your site, please close all open browser instances to clear your session cookies. This should remove the old anti forgery token cookie, so the next time you generate the form it will create a new valid cookie. We have an active work item to handle this condition better (without forcing you to restart your browser) and plan on getting it in shortly.
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Friday, November 12, 2010 4:14 PM -
User401360897 posted
I have created a regular expression that automatically removes FormCollection parameter from all action methods and add this line into the action method body.
http://weblogs.asp.net/imranbaloch/archive/2010/11/14/mvc-3-rc-bug-and-quick-solution.aspx
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Sunday, November 14, 2010 1:28 PM -
User-797310475 posted
Joe, sorry about the troubles this is giving you. We're aware of the issue with binding to FormCollection and are looking at ways of fixing it. If this issue is blocking your upgrade then I suggest you hold off on using MVC 3 RC and wait for the next release.
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Sunday, November 14, 2010 4:24 PM -
User-1032240251 posted
I checked the change in yesterday. 99.999% that it will be in the RTM bits (nothing is ever 100% guaranteed to happen until it's already happened :-p).
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Thursday, November 18, 2010 4:20 PM
All replies
-
User-1041395518 posted
So I created a blank MVC 3 RC site. I discovered that an action method that has FormCollection as a parameter will result in a potentially dangerous input error even with ValidateInput(false). But an empty method signature does not cause an error.
"<html></html>" is submitted in both cases below.
--This does not cause an error
[ValidateInput(false)]
public ActionResult Test()
{
return View("~/Views/Home/About.cshtml");
}
--This causes error
[ValidateInput(false)]
public ActionResult Test(FormCollection Values)
{
return View("~/Views/Home/About.cshtml");
}
Does anyone know why this is in RC and how to resolve this?
Wednesday, November 10, 2010 12:56 AM -
User-797310475 posted
We've made some under-the-covers changes to how request validation works. The short of it is that in the past any input submitted to your application caused a validation error, even if your application did not actually ever look at that input. In MVC 3 we've made it so that in certain scenarios (for example model-binding to models using SkipRequestValidation) request validation is performed on-demand or does not happen at all. However, not all scenarios currently support this and binding to a FormCollection falls into that category. We will consider improving this scenario, though no promises right now.
Regarding why your ValidateInput(false) attribute has no effect, this is related to the fact that request validation got moved to a different point in the ASP.NET processing pipeline in .NET 4 and this attribute will not work in this particular scenario unless you specify 2.0-mode request validation.
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Wednesday, November 10, 2010 3:11 AM -
User654706407 posted
I want to upgrade MVC2 to mvc3. But this problem breaked me..
I have already add:
<httpRuntime requestValidationMode="2.0" />
this works in MVC2, but breaking in MVC3. Temporarily give up.
Wednesday, November 10, 2010 5:06 AM -
User-1660457439 posted
Please post a stack trace of the exception along with the controller code that's causing the exception. That would help us determine what changes we would need to make to our request validation implementation to make this scenario start working again.
Thanks!
Wednesday, November 10, 2010 7:34 PM -
User654706407 posted
The conroller is:
HttpPost] [ValidateInput(false)] public ActionResult LogOn(LogOnModel model, string returnUrl, FormCollection form)
The web.config:<pages validateRequest="false"> <namespaces> <add namespace="System.Web.Helpers" /> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Routing" /> <add namespace="System.Web.WebPages"/> </namespaces> </pages> <httpRuntime requestValidationMode="2.0" />
The exception:A potentially dangerous Request.Form value was detected from the client (UserName="<abddd"). Description: Request Validation has detected a potentially dangerous client input value, and processing of the request has been aborted. This value may indicate an attempt to compromise the security of your application, such as a cross-site scripting attack. To allow pages to override application request validation settings, set the requestValidationMode attribute in the httpRuntime configuration section to requestValidationMode="2.0". Example: <httpRuntime requestValidationMode="2.0" />. After setting this value, you can then disable request validation by setting validateRequest="false" in the Page directive or in the <pages> configuration section. However, it is strongly recommended that your application explicitly check all inputs in this case. For more information, see http://go.microsoft.com/fwlink/?LinkId=153133. Exception Details: System.Web.HttpRequestValidationException: A potentially dangerous Request.Form value was detected from the client (UserName="<abddd"). Source Error: An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below. Stack Trace: [HttpRequestValidationException (0x80004005): A potentially dangerous Request.Form value was detected from the client (UserName="<abddd").] System.Web.HttpRequest.ValidateString(String value, String collectionKey, RequestValidationSource requestCollection) +8730740 Microsoft.Web.Infrastructure.DynamicValidationHelper.DeferredValidator.EnsureEntryValidated(NameObjectEntryWrapper nameObjectEntry) +165 Microsoft.Web.Infrastructure.DynamicValidationHelper.ValidatingArrayList.get_Item(Int32 index) +56 System.Collections.Specialized.NameValueCollection.GetKey(Int32 index) +16 System.Collections.Specialized.NameValueCollection.Add(NameValueCollection c) +68 System.Web.Mvc.FormCollection..ctor(NameValueCollection collection) +49 System.Web.Mvc.FormCollectionModelBinder.BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) +62 System.Web.Mvc.ControllerActionInvoker.GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) +319 System.Web.Mvc.ControllerActionInvoker.GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +116 System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +345 System.Web.Mvc.Controller.ExecuteCore() +115 System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +94 System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +10 System.Web.Mvc.<>c__DisplayClassb.<BeginProcessRequest>b__5() +37 System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +21 System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +12 System.Web.Mvc.Async.WrappedAsyncResult`1.End() +55 System.Web.Mvc.<>c__DisplayClasse.<EndProcessRequest>b__d() +47 System.Web.Mvc.SecurityUtil.<GetCallInAppTrustThunk>b__0(Action f) +7 System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(Action action) +23 System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +59 System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +9 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8836977 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +184
Wednesday, November 10, 2010 8:12 PM -
User-1660457439 posted
Thanks for the sample. We're seeing what we can do about this for the next release. You should be able to work around it in the meantime by changing your controller code to the following:
[HttpPost] [ValidateInput(false)] public ActionResult LogOn(LogOnModel model, string returnUrl) { FormCollection form = new FormCollection(Request.Unvalidated().Form); \\ ... }
The Request.Unvalidated() extension method is located in the System.Web.Helpers namespace.
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Wednesday, November 10, 2010 8:20 PM -
User654706407 posted
Looking forward the new version!
Wednesday, November 10, 2010 10:21 PM -
User-613285958 posted
I'm not having much luck on the MVC 3 ugrade. On pages that have controller actions for both get and post I'm receiving errors on the Get related to antiforgery.
Exception Details: System.ArgumentNullException: Buffer cannot be null.
Line 35: <% Html.EnableClientValidation();%>
Line 36: <% using (Html.BeginForm()) {%>
Line 37: <%= Html.AntiForgeryToken() %>
Line 38:
Line 39: <%= Html.ValidationSummary("Error Summary:", new { @class = "TextArial10B" })%>
Source File: c:\inetpub\ForumsMVC\forums\Views\About\Edit.aspx Line: 37
Stack Trace:
[ArgumentNullException: Buffer cannot be null. Parameter name: buffer] System.IO.MemoryStream..ctor(Byte[] buffer, Boolean writable) +9638183 System.IO.MemoryStream..ctor(Byte[] buffer) +6 System.Web.Mvc.AntiForgeryDataSerializer.Deserialize(String serializedToken) +97 [HttpAntiForgeryException (0x80004005): A required anti-forgery token was not supplied or was invalid.] System.Web.Mvc.AntiForgeryDataSerializer.Deserialize(String serializedToken) +397 System.Web.Mvc.HtmlHelper.GetAntiForgeryTokenAndSetCookie(String salt, String domain, String path) +160 System.Web.Mvc.HtmlHelper.AntiForgeryToken(String salt, String domain, String path) +16 System.Web.Mvc.HtmlHelper.AntiForgeryToken() +10 ASP.views_about_edit_aspx.__RenderContent2(HtmlTextWriter __w, Control parameterContainer) in c:\inetpub\ForumsMVC\forums\Views\About\Edit.aspx:37 System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +109 System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +8 System.Web.UI.Control.Render(HtmlTextWriter writer) +10 System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27 System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +100 System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25 ASP.views_shared_site_master.__Render__control1(HtmlTextWriter __w, Control parameterContainer) in c:\inetpub\ForumsMVC\forums\Views\Shared\Site.Master:91 System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +109 System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +8 System.Web.UI.Control.Render(HtmlTextWriter writer) +10 System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27 System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +100 System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25 System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children) +208 System.Web.UI.Control.RenderChildren(HtmlTextWriter writer) +8 System.Web.UI.Page.Render(HtmlTextWriter writer) +29 System.Web.Mvc.ViewPage.Render(HtmlTextWriter writer) +43 System.Web.UI.Control.RenderControlInternal(HtmlTextWriter writer, ControlAdapter adapter) +27 System.Web.UI.Control.RenderControl(HtmlTextWriter writer, ControlAdapter adapter) +100 System.Web.UI.Control.RenderControl(HtmlTextWriter writer) +25 System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3060
Friday, November 12, 2010 4:02 PM -
User-1660457439 posted
I'm not having much luck on the MVC 3 ugrade. On pages that have controller actions for both get and post I'm receiving errors on the Get related to antiforgery.This is a different issue. After upgrading your site, please close all open browser instances to clear your session cookies. This should remove the old anti forgery token cookie, so the next time you generate the form it will create a new valid cookie. We have an active work item to handle this condition better (without forcing you to restart your browser) and plan on getting it in shortly.
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Friday, November 12, 2010 4:14 PM -
User-613285958 posted
Thank you. I'll take another stab at an upgrade.
Friday, November 12, 2010 5:19 PM -
User-613285958 posted
Using your suggestion of
FormCollection form = new FormCollection(Request.Unvalidated().Form);
creates another problem where both the GET and the Post have the same action name. In MVC2 the action parameters were different because the GET might contain just an id whereas the Post contained the an id AND a FormCollection. Doing what you suggest for MVC means moving the forms collection line to the body of the action and results in the GET and the POST action having the same parameters, thus producing an error.
Perhaps there is some simple way around this without modifying quite a bit of code on many form post pages??????
Saturday, November 13, 2010 11:23 PM -
User401360897 posted
I have created a regular expression that automatically removes FormCollection parameter from all action methods and add this line into the action method body.
http://weblogs.asp.net/imranbaloch/archive/2010/11/14/mvc-3-rc-bug-and-quick-solution.aspx
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Sunday, November 14, 2010 1:28 PM -
User-613285958 posted
Imran, your search/replace is great. HOWEVER, it does not solve the problem where a MVC2 application had an action of the same name for GET and POST. In MVC 2 the form collection item as a parameter in the POST differentiated the two actions of the same name because they had different parameters.
By removing the forms collection as a parameter in MVC 3 the GET and POST actions have identical parameter and thus produce an error.
For an MVC2 site with many of these duplicate GET-POST actions the upgrade to MVC3 becomes extensive if a new action name has to be added for every POST that was a duplicate action name in MVC2.
GET -- MVC2
action Index (int id)POST -- MVC2
action Index (int id, FormsCollection forms)How can the upgrade to MCV3 be handled when the forms collection parameter is removed from the POST -- without renaming all the POST actions and whatever else is required to make the renaming work?
Sunday, November 14, 2010 3:24 PM -
User-797310475 posted
Joe, sorry about the troubles this is giving you. We're aware of the issue with binding to FormCollection and are looking at ways of fixing it. If this issue is blocking your upgrade then I suggest you hold off on using MVC 3 RC and wait for the next release.
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Sunday, November 14, 2010 4:24 PM -
User-613285958 posted
Thanks Marcin. If you guys don't have a quick fix then I'm not gonna try to find one.
It is either re-write a lot of code or, as you suggest, wait until MVC4. Of course that could be 6 moths or more away with no guarantee 4 won't require similar extensive code reworking.
Breaking existing code to the point where upgrading requires a fair amount of code rewrite isn't too developer friendly.
However, I do appreciate your input on this site. Thanks again.
Sunday, November 14, 2010 5:02 PM -
User-1660457439 posted
Use a different dummy parameter to differentiate them, like string unused. That's all the FormCollection parameter is really doing anyway.
Edit: also, we never said we're waiting until MVC 4 to fix this. We're investigating what it would take to fix this right now, e.g. in the next preview release of MVC 3.
Sunday, November 14, 2010 6:26 PM -
User401360897 posted
Use a different dummy parameter to differentiate them, like string unused. That's all the FormCollection parameter is really doing anyway.Good Idea. So If you willing to use Regular Expression then Replace
({[(]}:Wh*FormCollection:Wh*{[^,)]*}:Wh*[,]*)|({[,]}:Wh*FormCollection:Wh*{[^,)]*}):Wh*{[,)]}{([^{]|\n)*[{]}[ ]*{\n}
With
\1\3string unused\5\6\7\t\t\tFormCollection \2\4 = new FormCollection(Request.Unvalidated().Form);\7
Sunday, November 14, 2010 10:24 PM -
User-83425827 posted
Levi/Marcin,
Thanks for the Request.Unvalidated() workaround. Just wanted to add +1 to the votes that this is a legit regression and needs to be fixed before RTM. I'm sure you guys are almost done and under a lot of pressure from PMs, but I think this will bite a *lot* of devs and leave a sour taste about the upgrade.
I know a lot of companies with coding standards of including the "FormCollection form" argument with every HttpPost, even if unused, and all of those methods will be affected by this.
Wednesday, November 17, 2010 2:40 PM -
User-1032240251 posted
I checked the change in yesterday. 99.999% that it will be in the RTM bits (nothing is ever 100% guaranteed to happen until it's already happened :-p).
- Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
Thursday, November 18, 2010 4:20 PM -
User-613285958 posted
Thanks Brad. Fingers crossed at this end.
Friday, November 19, 2010 12:30 AM