How to prevent HttpRequestValidationException when calling IsAjaxRequest - asp.net-mvc

I am using MVC 4 and have Actions that need to accept input that includes HTML tags. The Actions are only accessible by trusted administrators, so I allowed the HTML tags by adding the ValidateInput(false) attribute to the relevant Action methods.
This worked fine initially, but subsequently I have added code to Global.asax to prevent Forms authentication redirection for Ajax requests:
if (FormsAuthentication.IsEnabled && context.Request.IsAjaxRequest())
{
context.Response.SuppressFormsAuthenticationRedirect = true;
}
After adding this code, I started getting an HttpRequestValidationException on these Actions, thrown from IsAjaxRequest:
System.Web.HttpRequestValidationException (0x80004005): A potentially dangerous Request.Form value was detected from the client (...).
at System.Web.HttpRequest.ValidateString(String value, String collectionKey, RequestValidationSource requestCollection)
at System.Web.HttpRequest.ValidateHttpValueCollection(HttpValueCollection collection, RequestValidationSource requestCollection)
at System.Web.HttpRequest.get_Form()
at System.Web.HttpRequest.get_Item(String key)
at System.Web.Mvc.AjaxRequestExtensions.IsAjaxRequest(HttpRequestBase request)
at MyApp.Application_BeginRequest(Object sender, EventArgs e)
...
What's the best way to fix this?

I'm wondering if SuppressFormsAuthenticationRedirect is breaking this option in web.config:
<pages validateRequest="false"
I had the exact same situation and putting [AllowHtml] on my password field fixed the issue.
Either one of two things is true:
1) SuppressFormsAuthenticationRedirect did disable the effect of validateRequest=false
2) It never worked in the first place.
Not sure which is true but now it works.

Related

How to handle "A potentially dangerous Request.Form value was detected from the client"?

I've received some "generic" errors within the protected void Application_Error() handler on an ASP.NET MVC Framework application. The exception message is:
A potentially dangerous Request.Form value was detected from the client
There are many ways to trigger this; just one example is making a call to e.g.,
http:/www.mywebsite.com/http:/www.mywebsite.com/
I'd like to create a "filter" for this kind of exception only, and redirect or manage the request accordingly. I don't want to disable it, just to manage it. I also don't want it to fall within the generic protected void Application_Error() handler—or, at least, I want to manage it internally within that method, so that it doesn't get handled by e.g. my logging.
How can I manage this?
It sounds like you already have an Application_Error() event handler configured, but don't want your standard logging to include this type of error, presumably because it's cluttering your logs with exceptions that you don’t intend to investigate further.
Background
This error is supposed to be represented by an HttpRequestValidationException. If this were the case here, of course, this would be a trivial problem. Based on the test case you've provided, however, you're actually getting the more general HttpException.
As you noted in the comments, this is due to the .NET Framework performing validation of characters in the URL early in the request pipeline, prior to the RequestValidator being evaluated. This may be a factor in why the HttpRequestValidationException isn't getting thrown, as would otherwise happen if the RequestValidator's IsValidRequestString() method returned false.
Workaround
Unfortunately, as the HttpException class is used for a wide range of errors, this makes it difficult to handle. Fortunately, as you also discovered, you can push this validation to the RequestValidator by disabling the requestPathInvalidCharacters in the web.config and configuring a custom RequestValidator:
<configuration>
<system.web>
<compilation targetFramework="4.6.1" />
<httpRuntime
targetFramework="4.6.1"
requestValidationType="CustomRequestValidator"
requestPathInvalidCharacters=""
/>
</system.web>
</configuration>
Note: The requestValidationType will need to be prefixed with its namespace, assuming it's not in your project's root namespace.
The default value for the requestPathInvalidCharacters is <,>,*,%,&,:,\,?, so you'll now need to reproduce that validation in your CustomRequestValidator:
public class CustomRequestValidator : RequestValidator
{
private static readonly char[] requestPathInvalidCharacters = new [] { '<', '>', '*', '%', '&', ':', '\\' };
protected override bool IsValidRequestString(
HttpContext context,
string value,
RequestValidationSource requestValidationSource,
string collectionKey,
out int validationFailureIndex
) {
if (requestValidationSource is RequestValidationSource.PathInfo || requestValidationSource is RequestValidationSource.Path) {
var errorIndex = value.IndexOfAny(requestPathInvalidCharacters);
if (errorIndex >= 0) {
validationFailureIndex = errorIndex;
return false;
}
}
return base.IsValidRequestString(
context,
value,
requestValidationSource,
collectionKey,
out validationFailureIndex
);
}
}
This first recreates the validation of the path (represented by the value parameter), and then performs the standard out-of-the-box IsValidRequestString() processing from the base RequestValidator. This will now throw the expected HttpRequestValidationException.
Managing the Exception
At this point, as noted above, this now becomes a trivial problem. As the RequestValidator is evaluated prior to MVC routes being parsed, you still can't use a Global Exception Filter here. Since you already have an Application_Error() event handler setup, however, you can manage this in your global.asax.cs with something like:
void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if (ex is HttpRequestValidationException)
{
Response.Clear();
Response.StatusCode = 200;
// Manage request as you deem appropriate; e.g.,
Response.Redirect("~/Errors/RequestValidation/");
Response.End();
return;
}
// Your current logging logic
}
Additional Details
The RequestValidator gets called at least twice for nearly every ASP.NET request—once for the pathinfo (which is typically empty) and once for the path (see requestValidationSource). Every QueryString, Form, Cookie, Header, or file bound to the route will also be validated.
Microsoft tries to limit what requests necessitate validation. For instance, they don't check requests to static files. Further, parameters not bound to the route are skipped. Since potentially dangerous characters cannot be used in route parameter keys, we don't need to worry about validating those.
Further, as you noted, there's also no need to validate parameter values (e.g., a cookie value) for invalid path characters. Collection values will still be evaluated for the presence of other potentially dangerous strings—such as <script—by the base IsValidRequestString() logic.

Handling a timeout in ASP.NET MVC

In ASP.NET MVC3, I can't seem to override a session timeout. I have set breakpoints at all the relevant server-side code points I can think of (controller actions and methods in globax.ax.cs) but nothing seems to get hit on session timeout.
I even applied an attribute as suggested here: (http://www.tyronedavisjr.com/2008/11/23/detecting-session-timeouts-using-a-aspnet-mvc-action-filter/) but even it was not hit when the session timed out. Surely the timeout must be session-side, but where?
Does anyone know what exactly happens when an ASP.NET MVC application has a session timeout?
What sessionState mode are you using? (<sessionState mode=" ... "> in web.config)
You should be able to add the following method to your Global.asax.cs to override the default Session_End behaviour:
protected void Session_OnEnd(object sender, EventArgs e)
{
// insert code here
}
Things to bear in mind:
The Session_OnEnd / Session_End event will only be called if the HttpSessionState.Mode property value is InProc (this is the default, so if you've not changed it in the web.config this should be fine). If you've changed it to StateServer or SQLServer, then the Session_OnEnd event in the Global.asax file is ignored.
The Session_OnEnd / Session_End event is called by the application when it abandons the session - not when you close the browser. You can manually trigger it by calling Session.Abandon
Typically, session timeouts can be handled in the Session_End event in your Global.asax
void Session_End(object sender, EventArgs e) {
// perform last minute procedures before session ends
}
According to the MSDN, the HttpSessionState.Timeout property has a setter and can be changed from within your application's code as well as permanently in the web.config

Dangerous Request.Form value was detected from the client - why?

I read all other posts here that are related to this error. Maybe I am missing something here but I don't know what. I am using textArea to input text in it (html text).
This text area is bounded to my domain class property
public class SomeClass{
...
[AllowHtml]
public string CommentText { get; set; }
...
}
I have also tried to add [ValidateInput(false)] attribute but nothing. But by reading error text I see that request doesn't even come to controller it is broken in Application_BeginRequest().
This is error message:
A potentially dangerous Request.Form value was detected from the client (CommentText="<p>ddd</p>")
Line 23: protected void Application_BeginRequest(Object sender, EventArgs e)
Line 24: {
Line 25: if (HttpContext.Current.Request["RequireUploadifySessionSync"] != null)
Line 26: UploadifySessionSync();
Line 27: }
Source File: D:\Projects\...\Global.asax.cs Line: 25
Stack Trace:
[HttpRequestValidationException (0x80004005): A potentially dangerous Request.Form value was detected from the client (CommentText="<p>ddd</p>").]
System.Web.HttpRequest.ValidateString(String value, String collectionKey, RequestValidationSource requestCollection) +8755668
System.Web.HttpRequest.ValidateNameValueCollection(NameValueCollection nvc, RequestValidationSource requestCollection) +122
System.Web.HttpRequest.get_Form() +114
I know that I can turn off check ok whole application in web config. But I need this only in one case (to allow HTML input).
More strange is that this works a few days ago and I didn't change anything here, just login and logout users.
What am I doing wrong here?
Ok now I remove this code fom global.asax:
if (HttpContext.Current.Request["RequireUploadifySessionSync"] != null)
UploadifySessionSync();
And now it works. But I need this code here. Why is it produce this error?
This has already been answered.
Previous Question
You need to change the way your handling request validations to revert it back to 2.0
Your specific issue is that you've got code looking at the request parameters in BeginRequest which is earlier in the ASP.NET pipeline than when your models are bound (where an AllowHtml or ValidateInput attribute would come into play).
It looks like you are enforcing security around a flash upload with your code (I am doing something very similar.
In my case I ended up just catching an HttpRequestValidationException in the BeginRequest method and swallowing the exception. It is not best practice, but the validation will be performed later in the pipeline so you still have control over the validation.

Page Redirect when session end in ASP.Net MVC

I would like to do redirect to login when current session end and that config must be working at any View and Controller.
My current code in Global.asax:
protected void Session_End(object sender, EventArgs e)
{
Session.Abandon();
//GetPath() is getting currently path
// eg. http://localhost/mymvcproject
Response.Redirect(PATH.GetPath() + "User/LogOn");
}
Check the following setting under <system.web> in your web.config file:
<sessionState mode="InProc" cookieless="false" timeout="1"></sessionState>
then fill the following text in your site.Master
if (Session.IsNewSession)
{
Response.Redirect(PATH.GetPath() + "User/LogOn");
}
I don't think your code can work because Session_End() is more usually invoked when there is NO request made by the browser after a specific duration. Therefore, Response here would correspond to no particular request, and thus, no redirection.
Instead, try to handle Application_Start and check for Session.IsNew property. If it's true, then perform the redirection. (Consider doing that by invoking FormsAuthentication.RedirectToLoginPage() though.)
When checking for IsNew, beware of the situation described here. I guess assigning some dummy session variable during the login process will address that, although I haven't tried myself.

Lower case URLs in ASP.NET MVC

Is it possible to force/extend the routing engine to generate URLs in lower case, giving /controller/action instead of /Controller/Action?
What's more, you should force any incoming requests that are uppercase to be redirected to the lowercase version. Search engines treat URLs case-sensitively, meaning that if you have multiple links to the same content, that content's page ranking is distributed and hence diluted.
Returning HTTP 301 (Moved Permanently) for such links will cause search engines to 'merge' these links and hence only hold one reference to your content.
Add something like this to your Global.asax.cs file:
protected void Application_BeginRequest(object sender, EventArgs e)
{
// Don't rewrite requests for content (.png, .css) or scripts (.js)
if (Request.Url.AbsolutePath.Contains("/Content/") ||
Request.Url.AbsolutePath.Contains("/Scripts/"))
return;
// If uppercase chars exist, redirect to a lowercase version
var url = Request.Url.ToString();
if (Regex.IsMatch(url, #"[A-Z]"))
{
Response.Clear();
Response.Status = "301 Moved Permanently";
Response.StatusCode = (int)HttpStatusCode.MovedPermanently;
Response.AddHeader("Location", url.ToLower());
Response.End();
}
}
Yes, just change it in the routing in the global.asax file.
#All asking if it matters: Yes I do think it matters. Having the url all in lower case just looks better.
Every time you don't make something look nice when you can, Bill Buxton kills a kitten.

Resources