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.
Related
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.
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.
My understanding was OOTB, MVC will validate input to prevent XSS Attack and SQL Injection.
For example, In one of my app, the "a dangerous input has been detected" error will be received when I put in HTTP Get request. However, the post actions can let these values posted successfully through html input element without error. Even after I marked the controller action as [ValidateInput(true)]. How can I make them validate those post input?
Any advice will be appreciated!
Without seeing your GET handler, or what you're sending to it, it's tough to say why it behaves that way. However, OOTB MVC guards against SQL injection through the use of Entity Framework, and against XSS through ModelState validation.
Inside the body of your POST action that handles this forms submission you'll want to use code much like the following:
if (ModelState.IsValid)
{
//do the stuff I want to do when things are valid and free of XSS
}
else
{
//something went wrong. Probably shouldn't process this one. Have the user try again
}
Update: please disregard my filthy lies. ValidateInput(true) is not necessary because it is on by default. So, the only things I can think of would be that you have the AllowHtml attribute on your class or properties, or you are not posting back a model for modelBinding, and therefore input validation, to occur. At this point, you're probably going to need to put up some code for further help. There's too many unknowns right now.
I ran into a similar issue - we had JQuery using $.ajax to post JSON to the MVC action. The default model binder does not validate posted JSON allowing unsafe XSS to be posted against our action.
To solve this, I found the RequestValidator has a static method InvokeIsValidRequestString that allowed
public class ValidateJsonXssAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var request = filterContext.HttpContext?.Request;
if (request != null && "application/json".Equals(request.ContentType, StringComparison.OrdinalIgnoreCase))
{
if (request.ContentLength > 0 && request.Form.Count == 0) //
{
if (request.InputStream.Position > 0)
request.InputStream.Position = 0; // InputStream has already been read once from "ProcessRequest"
using (var reader = new StreamReader(request.InputStream))
{
var postedContent = reader.ReadToEnd(); // Get posted JSON content
var isValid = RequestValidator.Current.InvokeIsValidRequestString(HttpContext.Current, postedContent,
RequestValidationSource.Form, "postedJson", out var failureIndex); // Invoke XSS validation
if (!isValid) // Not valid, so throw request validation exception
throw new HttpRequestValidationException("Potentially unsafe input detected");
}
}
}
}
}
Then, you can just decorate relevant MVC actions expecting JSON-posted data that might bypass the standard XSS prevention:
[HttpPost]
[ValidateJsonXss]
public ActionResult PublishRecord(RecordViewModel vm) { ... }
You can see other options for customizing request validation with OWASP .NET recommendations by extending the RequestValidator object, which exposes the string validation done by the ValidateInput automatically utilized by MVC for other scenarios of query string, form collection, and cookie values.
For more info: https://www.owasp.org/index.php/ASP.NET_Request_Validation
I am new to ASP.NET MVC , Kendo UI (razor) , Jquery. I have an application that throws 3 kinds of errors
Unhanded exceptions (400, 403,500 503 etc) - throw generic exceptions
Expected exceptions/ errors (custom exceptions) - e.g. Trying to create a contact that already exist in the system - The system needs to throw "Contact_duplicated_exception" and show this to the user as "Contact was previously created. This action could not proceed".
Model state errors (UI). Errors that I add to modelstate to showup on the page using #Html.ValidationSummary(true)
What is the best standard way of handling the above throughout the application ?
I need to send these messages back to the user using Jquery Ajax [POST].
I have used the following concepts but I need to implement a standard way of dealing with the above
1. I have used ELMAH (for unhanded exceptions)
2. Application_Error(object sender, EventArgs e) in global.asax.cs
3. Custom HandleErrorArrtibute
public class HandleErrorWithAjaxFilter : HandleErrorAttribute, IExceptionFilter
Thanks!
For #1 and #3, you're looking good, IMHO. However, I think your weak-point is #2 and here is why:
If the exception is expected it should not be allowed to fall to Application_Error; because, well... it's expected, it's workflow, not an exception.
Therefore as a reaction to user input and part of workflow, it should be handled as part of #3.
So, in your shoes, I would go about in the specific instance of finding duplicates adding a validation attribute onto the potentially duplicate class like so:
[AttributeUsage(AttributeTargets.Class)]
public class UniqueContactAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
bool isValid = true;
Contact contact = value as Contact;
if(contact != null)
{
// check for your duplicate in the database and set isValid to false if you find one.
}
return isValid;
}
}
Usage for your metadata class:
[UniqueContact(ErrorMessage = "Contact was previously created. This action could not proceed.")]
public class Contact_Validation
{
}
I'm having an issue with custom errors on an ASP.NET MVC app I've deployed on my shared host. I've created an ErrorController and added the following code to Global.asax to catch unhandled exceptions, log them, and then transfer control to the ErrorController to display custom errors. This code is taken from here:
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
Response.Clear();
HttpException httpEx = ex as HttpException;
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Error");
if (httpEx == null)
{
routeData.Values.Add("action", "Index");
}
else
{
switch (httpEx.GetHttpCode())
{
case 404:
routeData.Values.Add("action", "HttpError404");
break;
case 500:
routeData.Values.Add("action", "HttpError500");
break;
case 503:
routeData.Values.Add("action", "HttpError503");
break;
default:
routeData.Values.Add("action", "Index");
break;
}
}
ExceptionLogger.LogException(ex); // <- This is working. Errors get logged
routeData.Values.Add("error", ex);
Server.ClearError();
IController controller = new ErrorController();
// The next line doesn't seem to be working
controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
}
Application_Error is definitely firing because the logging works fine, but instead of displaying my custom error pages, I get the Go Daddy generic ones. From the title of the blog post the above code is taken from, I notice that it uses Release Candidate 2 of the MVC framework. Did something change in 1.0 that makes the last line of code not work? As usual it works great on my machine.
Any suggestions will be greatly appreciated.
Edit: Forgot to mention that I've tried all 3 possiblities for the customErrors mode in Web.config (Off, On, and RemoteOnly). Same results regardless of this setting.
Edit 2: And I've also tried it with and without the [HandleError] decoration on the Controller classes.
Update: I've figured out and fixed the 404s. There is a section of the Settings panel in Go Daddy's Hosting Control Center where 404 behavior can be controlled and the default is to show their generic page, and apparently this overrides any Web.config settings. So my custom 404 page is now showing as intended. However, 500s and 503s are still not working. I've got code in the HomeController to grab a static text version of the content if Sql Server throws an exception as follows:
public ActionResult Index()
{
CcmDataClassesDataContext dc = new CcmDataClassesDataContext();
// This might generate an exception which will be handled in the OnException override
HomeContent hc = dc.HomeContents.GetCurrentContent();
ViewData["bodyId"] = "home";
return View(hc);
}
protected override void OnException(ExceptionContext filterContext)
{
// Only concerned here with SqlExceptions so an HTTP 503 message can
// be displayed in the Home View. All others will bubble up to the
// Global.asax.cs and be handled/logged there.
System.Data.SqlClient.SqlException sqlEx =
filterContext.Exception as System.Data.SqlClient.SqlException;
if (sqlEx != null)
{
try
{
ExceptionLogger.LogException(sqlEx);
}
catch
{
// couldn't log exception, continue without crashing
}
ViewData["bodyId"] = "home";
filterContext.ExceptionHandled = true;
HomeContent hc = ContentHelper.GetStaticContent();
if (hc == null)
{
// Couldn't get static content. Display friendly message on Home View.
Response.StatusCode = 503;
this.View("ContentError").ExecuteResult(this.ControllerContext);
}
else
{
// Pass the static content to the regular Home View
this.View("Index", hc).ExecuteResult(this.ControllerContext);
}
}
}
Here's the code that attempts to fetch the static content:
public static HomeContent GetStaticContent()
{
HomeContent hc;
try
{
string path = Configuration.CcmConfigSection.Config.Content.PathToStaticContent;
string fileText = File.ReadAllText(path);
string regex = #"^[^#]([^\r\n]*)";
MatchCollection matches = Regex.Matches(fileText, regex, RegexOptions.Multiline);
hc = new HomeContent
{
ID = Convert.ToInt32(matches[0].Value),
Title = matches[1].Value,
DateAdded = DateTime.Parse(matches[2].Value),
Body = matches[3].Value,
IsCurrent = true
};
}
catch (Exception ex)
{
try
{
ExceptionLogger.LogException(ex);
}
catch
{
// couldn't log exception, continue without crashing
}
hc = null;
}
return hc;
}
I've verified that if I change the connection string to generate a SqlException, the code properly logs the error and then grabs and displays the static content. But if I also change the path to the static text file in Web.config to test the 503 version of the Home View, what I get instead is a page with nothing other than "service unavailable". That's it. No custom 503 message with the look and feel of the site.
Does anyone have any suggestions on improvements to the code that might help? Would it help to add different headers to the HttpResponse? Or is Go Daddy heavy-handedly hijacking the 503s?
I've found the solution and it's incredibly simple. Turns out the problem was actually in IIS7. While debugging this issue in Visual Studio I saw a property of the HttpResponse object that I hadn't noticed before:
public bool TrySkipIisCustomErrors { get; set; }
This lead me to my nearest search engine which turned up a great blog post by Rick Strahl and another on angrypets.com as well as this question here on SO. These links explain the gory details much better than I can, but this quote from Rick's post captures it pretty well:
The real confusion here occurs because the error is trapped by
ASP.NET, but then ultimately still handled by IIS which looks at the
500 status code and returns the stock IIS error page.
It also seems this behavior is specific to IIS7 in Integrated mode. From msdn:
When running in Classic mode in IIS 7.0 the TrySkipIisCustomErrors
property default value is true. When running in Integrated mode, the
TrySkipIisCustomErrors property default value is false.
So essentially all I ended up having to do is add Response.TrySkipIisCustomErrors = true; right after any code that sets the Response.StatusCode to 500 or 503 and everything now functions as designed.
I host an ASP.NET MVC site on GoDaddy and also faced issues dealing with custom error pages. What I found, through trial and error, was that GoDaddy intercepts errors at the HTTP level.
For example, any page which returned an HTTP status code of 404 caused GoDaddy's custom error page to take over. Eventually I changed my custom error pages to return 200 status and the 404-related problem went away. My HTML was the same, just the HTTP status needed to change.
I admittedly never tried doing the same with 503 status responses, but it's possible that the same mitigation may work. If you change from returning a 503 status to returning 200 status, does the problem go away?
Note that, if you do this workaround, you'll want to prevent search engines from indexing your error pages, which once then return a 200 status will be indistinguishable (from the search engine's perspective) from a regular page. So make sure to add a META ROBOTS tag to prevent indexing of your error pages, e.g.
<META NAME="ROBOTS" CONTENT="NOINDEX">
The downside of this approach may be that your page might be removed from Google, which is definitely not a good thing!
UPDATE: So, in addition, you can also detect whether the user agent is a crawler or not, and if it's a crawler return a 503 while if it's not a crawler, return a 200. See this blog post for info about how to detect crawlers. Yes, I know that returning different content to crawlers vs. users is an SEO no-no, but I've done this on several sites with no ill effect so far, so I'm not sure how much of a problem that is.
Doing both approaches (META ROBOTS and bot detection) may be your best bet, in case any oddball crawlers slip through the bot detector.