ASP.Net MVC, JS injection and System.ArgumentException - Illegal Characters in path - asp.net-mvc

In my ASP.Net MVC application, I use custom error handling.
I want to perform custom actions for each error case I meet in my application.
So I override Application_Error, get the Server.GetLastError();
and do my business depending on the exception, the current user, the current URL (the application runs on many domains), the user IP, and many others.
Obviousely, the application is often the target of hackers.
In almost all the case it's not a problem to detect and manage it, but for some JS URL attacks, my error handling does not perform what I want it to do.
Ex (from logs) :
http://localhost:1809/Scripts/]||!o.support.htmlSerialize&&[1
When I got such an URL, an exception is raised when accessing the ConnectionStrings section in the web.config, and I can't even redirect to another URL.
It leads to a "System.ArgumentException - Illegal Characters in path, etc."
The screenshot below shows the problem :
http://screencast.com/t/Y2I1YWU4
An obvious solution is to write a HTTP module to filter the urls before they reach my application, but I'd like to avoid it because :
I like having the whole security being managed in one place (in the Application_Error() method)
In the module I cannot access the whole data I have in the application itself (application specific data I don't want to debate here)
Questions :
Did you meet this problem ?
How did you manage it ?
Thanks for you suggestions,
Mose
PS : here is the stack trace :
System.ArgumentException: Illegal characters in path.
at System.IO.Path.CheckInvalidPathChars(String path)
at System.IO.Path.Combine(String path1, String path2)
at System.Web.Configuration.UserMapPath.GetPhysicalPathForPath(String path, VirtualDirectoryMapping mapping)
at System.Web.Configuration.UserMapPath.GetPathConfigFilename(String siteID, VirtualPath path, String& directory, String& baseName)
at System.Web.Configuration.UserMapPath.MapPath(String siteID, String path)
at System.Web.Hosting.HostingEnvironment.MapPathActual(VirtualPath virtualPath, Boolean permitNull)
at System.Web.Hosting.HostingEnvironment.MapPathInternal(VirtualPath virtualPath, Boolean permitNull)
at System.Web.CachedPathData.GetPhysicalPath(VirtualPath virtualPath)
at System.Web.CachedPathData.GetConfigPathData(String configPath)
at System.Web.CachedPathData.GetVirtualPathData(VirtualPath virtualPath, Boolean permitPathsOutsideApp)
at System.Web.HttpContext.GetFilePathData()
at System.Web.HttpContext.GetConfigurationPathData()
at System.Web.Configuration.RuntimeConfig.GetConfig(HttpContext context)
at System.Web.HttpContext.get_ImpersonationToken()
at System.Web.ClientImpersonationContext.Start(HttpContext context, Boolean throwOnError)
at System.Web.HttpApplication.ThreadContext.Enter(Boolean setImpersonationContext)
at System.Web.HttpApplication.OnThreadEnterPrivate(Boolean setImpersonationContext)
at System.Web.HttpApplication.ApplicationStepManager.ResumeSteps(Exception error)

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.

WebSecurity.InitializeDatabaseConnection method can be called only once

I'm trying Windows Azure to host an MVC4 web application.
I've created a test app, using VS2012 MVC4 internet application template and added a custom Model and Controller to it.
I've published it on Azure and managed to get 'update-database' apply migrations to the Azure Database.
When i try the app locally, but using the Azure SQL database, it works fine.
I can login/register and use my test controller.
When i try the app online, i can use the test controller but login or register links give the following exception:
Server Error in '/' Application.
The "WebSecurity.InitializeDatabaseConnection" method can be called only once.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: The "WebSecurity.InitializeDatabaseConnection" method can be called only once.
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:
[InvalidOperationException: The "WebSecurity.InitializeDatabaseConnection" method can be called only once.]
WebMatrix.WebData.WebSecurity.InitializeMembershipProvider(SimpleMembershipProvider simpleMembership, DatabaseConnectionInfo connect, String userTableName, String userIdColumn, String userNameColumn, Boolean createTables) +123
WebMatrix.WebData.WebSecurity.InitializeProviders(DatabaseConnectionInfo connect, String userTableName, String userIdColumn, String userNameColumn, Boolean autoCreateTables) +51
WebMatrix.WebData.WebSecurity.InitializeDatabaseConnection(String connectionStringName, String userTableName, String userIdColumn, String userNameColumn, Boolean autoCreateTables) +52
MembershipTest2.Filters.SimpleMembershipInitializer..ctor() +193
Do you have any idea where that comes from ?
If i debug (the local version), this method is only called once.
Thanks.
You could try encapsulating the call(s) to that method to ensure it's not called more then once
if (!WebMatrix.WebData.WebSecurity.Initialized)
{
WebSecurity.InitializeDatabaseConnection(...);
}
in my case I had both
(in web.config)
<add key="enableSimpleMembership" value="true" />
and
(in _ViewStart.cshtml)
WebSecurity.InitializeDatabaseConnection("club", "Account", "UserID", "UserName", autoCreateTables: true);
Solution: it seems you cannot have both, so remove one
Does the following SO discussion help you?
Cannot seed Users & Roles
I did find the following article helped me lot to use newer MVC4 & EF together with Simple Membership Provider so if you haven't read it please take a look:
SimpleMembership, Membership Providers, Universal Providers and the new ASP.NET 4.5 Web Forms and ASP.NET MVC 4 templates

Controller other than Home will not pass MvcIntegrationTesting tests

I am using an adaptation of Steve Sanderson's wonderful MVC Integration Testing Framework.
If I take any view in my application and serve it through this framework (which basically creates a 'fake' worker request through HttpRuntime.ProcessRequest()) I can host it within the ASP.NET Runtime in the context of my integration test.
My question is why would any view from the HomeController go nicely through this process but any other controller give a response with
Path 'get' is forbidden
I can move any view to the HomeController and test it without issue. I see no difference (url not withstanding) of the worker request fake between the two calls. I am at a loss!
Stack trace in test output:
ContentControllerTwitterReturnsTheTwitterView :
FailedSystem.NullReferenceException : Object reference not set to an
instance of an object.
Server stack trace: at
website.tests.ContentControllerTwitterTests.b__0(BrowsingSession
session) at
MvcIntegrationTestFramework.Hosting.AppDomainProxy.RunBrowsingSessionInAppDomain(SerializableDelegate`1
script) in AppDomainProxy.cs: line 19 at
System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr
md, Object[] args, Object server, Int32 methodPtr, Boolean
fExecuteInContext, Object[]& outArgs) at
System.Runtime.Remoting.Messaging.StackBuilderSink.SyncProcessMessage(IMessage
msg, Int32 methodPtr, Boolean fExecuteInContext)
Exception rethrown at [0]: at
System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage
reqMsg, IMessage retMsg) at
System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(ref
MessageData msgData, Int32 type) at
MvcIntegrationTestFramework.Hosting.AppDomainProxy.RunBrowsingSessionInAppDomain(SerializableDelegate1
script) at MvcIntegrationTestFramework.Hosting.AppHost.Start(Action1
testScript) in AppHost.cs: line 34 at
website.tests.ContentControllerTwitterTests.ContentControllerTwitterReturnsTheTwitterView()
in HomeControllerTwitterTests.cs: line 25
Problem was naming ... answer is
Do not name your controllers with same name as a folder within solution!
Old fool :)

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.

WCF NullReferenceException

I'm hosting an ASP.NET MVC site on Winhost and recently added a WCF data service for users providing feedback. The service works fine from my local machine, but when I deploy it I get the following System.NullReferenceException returned in Fiddler whenever I try to save an entry to the service:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
<code></code>
<message xml:lang="en-US">An error occurred while processing this request.</message>
<innererror>
<message>Object reference not set to an instance of an object.</message>
<type>System.NullReferenceException</type>
<stacktrace> at System.Data.Services.Providers.ObjectContextServiceProvider.SetValue(Object targetResource, String propertyName, Object propertyValue)
at System.Data.Services.Serializers.Deserializer.SetPropertyValue(ResourceProperty resourceProperty, Object declaringResource, Object propertyValue, ContentFormat contentFormat, IDataService service)
at System.Data.Services.Serializers.PlainXmlDeserializer.ApplyProperty(XmlReader reader, String propertyName, ResourceType resourceType, Object resource)
at System.Data.Services.Serializers.PlainXmlDeserializer.ApplyContent(XmlReader reader, ResourceType resourceType, Object resource)
at System.Data.Services.Serializers.PlainXmlDeserializer.ApplyContent(Deserializer deserializer, XmlReader reader, ResourceType resourceType, Object resource, EpmAppliedPropertyInfo propertiesApplied, Int32 currentObjectCount)
at System.Data.Services.Serializers.SyndicationDeserializer.ApplyProperties(SyndicationItem item, ResourceType resourceType, EpmAppliedPropertyInfo propertiesApplied, Object resource)
at System.Data.Services.Serializers.SyndicationDeserializer.CreateObject(SegmentInfo segmentInfo, Boolean topLevel, SyndicationItem item)
at System.Data.Services.Serializers.SyndicationDeserializer.CreateSingleObject(SegmentInfo segmentInfo)
at System.Data.Services.Serializers.Deserializer.ReadEntity(RequestDescription requestDescription)
at System.Data.Services.Serializers.Deserializer.HandlePostRequest(RequestDescription requestDescription)
at System.Data.Services.DataService`1.HandlePostOperation(RequestDescription description, IDataService dataService)
at System.Data.Services.DataService`1.ProcessIncomingRequest(RequestDescription description, IDataService dataService)
at System.Data.Services.DataService`1.HandleNonBatchRequest(RequestDescription description)
at System.Data.Services.DataService`1.HandleRequest()</stacktrace>
</innererror>
</error>
Turn on tracing both on the server and on the client (see http://msdn.microsoft.com/en-us/library/ms733025.aspx), then use SvcTraceViewer (http://msdn.microsoft.com/en-us/library/ms732023.aspx). It will usually give you a more detailed exception.
My problem turned out to be 2 issues:
My site reroutes Url's for all GET requests to lower case. ODATA queries are case sensitive. This was causing me trouble with diagnosing the problem but wasn't causing the POST issue. Removing this for my service uri helped me identify the real problem.
The real issue was that my DataContext for my POCO entities had proxy generation enabled.
Here's a lengthier description of how I found the problem in case it helps anyone debug a similar issue:
Per Dan's suggestion, I enabled tracing to see if I could get any additional details. This showed me that I was getting a System.ServiceModel.CommunicationObjectAbortedException. I searched for the cause of this for a while with no success.
Next, I set my EntitySetRights for my DataService to EntitySetRights.All to see if I could determine the error by attempting to read my entity set (note that in my case this is a temporary change for debugging).
static public void InitializeService(DataServiceConfiguration config) {
...
config.SetEntitySetAccessRule("myentityset", EntitySetRights.All);
...
}
I then queried the service http://mydomain.com/myservice.svc/myentityset and received the following error:
Resource not found for the segment 'myentityset'
This turned out to be due to my site forcing all urls to lower case (apparently ODATA queries are case sensitive). My entity set is named something like 'MyEntitySet', but it was being queried as 'myentityset' Once I disabled this for my service url, I received an error similar to the following:
Internal Server Error. The type 'System.Data.Entity.DynamicProxies.myentity_XXXX' is not a complex type or an entity type
Looking up this error led me to this link identifying my core problem. The problem is with POCO Entity Generation for DataServices. In order to fix the problem ProxyCreationEnabled needs to be set to false. I added the following method to my T4 template that generates my ObjectContext.
<#+
private void WriteProxyCreation()
{
#>
this.ContextOptions.ProxyCreationEnabled = false;
<#+
}
#>
I then added a call to my method in each of the constructors similar to the following:
public <#=code.Escape(container)#>()
: base(ConnectionString, ContainerName)
{
<#
WriteLazyLoadingEnabled(container);
WriteProxyCreation();
#>
}

Resources