ASP.NET URL validation - asp.net

We have a custom REST handler on ASP.NET that is configured like this to handle all incoming requests:
<add path="*" verb="*" type="REST.RESTProtocolHandler"/>
However, passing it a pipe character, properly encoded or not at all, triggers a validation error that seems to come from inside ASP.NET.
Accessing http://localhost:8080/%7c or http://localhost:8080/| yields this error:
[ArgumentException: Illegal characters in path.]
System.IO.Path.CheckInvalidPathChars(String path) +7489125
System.IO.Path.Combine(String path1, String path2) +40
System.Web.Configuration.UserMapPath.GetPhysicalPathForPath(String path, VirtualDirectoryMapping mapping) +114
System.Web.Configuration.UserMapPath.GetPathConfigFilename(String siteID, VirtualPath path, String& directory, String& baseName) +72
System.Web.Configuration.UserMapPath.MapPath(String siteID, VirtualPath path) +30
System.Web.Configuration.UserMapPath.MapPath(String siteID, String path) +31
System.Web.Hosting.HostingEnvironment.MapPathActual(VirtualPath virtualPath, Boolean permitNull) +297
System.Web.Hosting.HostingEnvironment.MapPathInternal(VirtualPath virtualPath, Boolean permitNull) +51
System.Web.CachedPathData.GetConfigPathData(String configPath) +341
System.Web.CachedPathData.GetVirtualPathData(VirtualPath virtualPath, Boolean permitPathsOutsideApp) +110
System.Web.HttpContext.GetFilePathData() +36
System.Web.HttpContext.GetConfigurationPathData() +26
System.Web.Configuration.RuntimeConfig.GetConfig(HttpContext context) +43
System.Web.Configuration.CustomErrorsSection.GetSettings(HttpContext context, Boolean canThrow) +41
System.Web.HttpResponse.ReportRuntimeError(Exception e, Boolean canThrow, Boolean localExecute) +101
System.Web.HttpRuntime.FinishRequest(HttpWorkerRequest wr, HttpContext context, Exception e) +383
No userland code gets executed. Is this a configuration option somewhere? Reproduced on IIS 7 & VS Studio's 2008 devel server.
Stack Overflow seems to handle this error OK, it looks like a dynamically generated 404 MVC page gets rendered for https://stackoverflow.com/%7c.
Any ideas?

Try to intercept the exception in Global.asax file. Implement there (Global.asax.cs) this method:
protected void Application_Error(Object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
//do whatever you want with that exception
//or get the url from the context, reformat and redirect
}

First you need to tinker in the
Registry :
http://support.microsoft.com/default.aspx?scid=kb;EN-US;826437
Restart IIS
and voila it works.
But i've made this work with IIS7 without problems, but with IIS6 I get this error (Illegal characters in path).

I have a similar program that intercepts all and trying it with a pipe gives me the same error. I assume it has to do with IIS doing path tests (mappath) before it knows who is to handle the request.
Your handler takes the root(meaning all calls) but i assume the way IIS does it is generic.
So I assume any or most of pathing characters that you cant use on your filesystem will fail on IIS request (GET/POST).
Maybe someone knows how to disable the IIS check. According to the error, it seems to happens even before your web.config is read, as it is trying to locate the right config?,
Maybe it is possible to use your own error page as an redirect back to your handler?

I think the answer is in your stack trace. The error is thrown on the System.IO.Path.CheckInvalidPathChars() call - this is not checking the Url, but checking the Windows file system upon which IIS sits. It's not so much a case of the pipe character being Url illegal, but basically DOS illegal.
If you intercept the Url before IIS tries to find the matching path on the server, I expect you can deal with this error. That probably lies in having a rewrite rule or similar to find and rewrite the Url with unwanted characters in it.

By default IIS does not allow certain characters in the URL and considers them illegal. This is where you problem comes from - it doesn't even call the handler you have. As far as I know there is no place that you can configure which characters are accepted through UI, except for Windows Registry. I don't know why you want to use pipe, but I don't think it is good practice. As for the error page - you can always have your own error page for any exception, so that users don't see the ugly messages.

Related

Custom Error Page for 'Illegal Characters in path'

The custom error page I set in the web.config does not get displayed when an error of "Illegal Characters in path" is raised. It does work for other server errors, so I'm not sure if there is anything I can do?
Example Request that correctly shows Custom Error Page: website.com/3f.jsp
Example Request that does not: website.com/%3f.jsp
Web.config: <customErrors mode="On" defaultRedirect="ErrorDisplay.aspx"></customErrors>
Stacktrace (customErrors Off)
[ArgumentException: Illegal characters in path.]
System.Security.Permissions.FileIOPermission.HasIllegalCharacters(String[] str) +276
System.Security.Permissions.FileIOPermission.AddPathList(FileIOPermissionAccess access, String[] pathListOrig, Boolean checkForDuplicates, Boolean needFullPath, Boolean copyPathList) +88
System.Security.Permissions.FileIOPermission..ctor(FileIOPermissionAccess access, String[] pathList, Boolean checkForDuplicates, Boolean needFullPath) +43
System.IO.Path.GetFullPath(String path) +82
System.Web.HttpApplication.CheckSuspiciousPhysicalPath(String physicalPath) +19
System.Web.Configuration.HttpConfigurationSystem.ComposeConfig(String reqPath, IHttpMapPath configmap) +175
System.Web.HttpContext.GetCompleteConfigRecord(String reqpath, IHttpMapPath configmap) +434
System.Web.HttpContext.GetCompleteConfig() +49
System.Web.HttpContext.GetConfig(String name) +195
System.Web.CustomErrors.GetSettings(HttpContext context, Boolean canThrow) +20
System.Web.HttpResponse.ReportRuntimeError(Exception e, Boolean canThrow) +39
System.Web.HttpRuntime.FinishRequest(HttpWorkerRequest wr, HttpContext context, Exception e) +486
I tried to manually catch the error in the Global.asax Application_Error handler, but that never gets called. Application_BeginRequest doesn't even get called when there are illegal characters, so where is IIS throwing this error and is there a way for me to display a custom page?
According to this article I may be out of luck.
As your stack trace shows and you observed in Application_BeginRequest not getting called, this error occurs in IIS's request handling before your application code even gets called - the answer to your first question: therefore, your Web.config and Application_Error implementation are not considered.
A related discussion on ASP.NET forums indicates as much too.
On my local IIS (7.5) server, I get back...
Bad Request - Invalid URL
HTTP Error 400. The request URL is invalid.
...for the URL http://localhost/%&what.
Curious, I tried setting a static custom error page for HTTP status code 400 under my local server's Error Pages in IIS Manager, also configuring my local server to use custom error pages for local and remote requests; but I never saw the custom error page I set for this particular error.
A TechNet article explains why:
You cannot customize the following HTTP errors: 400, 403.9, 411, 414, 500, 500.11, 500.14, 500.15, 501, 503, and 505.
So I think the answer to your second question is, no, IIS does not provide a way for you to display a custom error page for this.

CSHTML rendering text only - static page?

This is a continuation of my previous question (.CSHTML pages will not render), but I am no longer getting a 500 error, thus the new post. My pages are now just rendering plain text / html (regardless of what I do).
I can get the pages to work correctly if I try to view them through WebMatrix3, but I cannot view them from the browser (either localhost or through the web).
I recently realized that my pages were set up for ASP.NET v2.0, which I am guessing does not support .cshtml. So, I changed everything to v4.0 but I still don't have any luck view the pages correctly. It's just plain text.
I have:
MVC 3 installed
IIS 7.5 on Win7 Home Premium
The dir of the pages that I want to load converted to application
web.config functioning, though I am not sure what else, if anything I need to have it in
My server functioning normally with HTML, .css, .php, python, etc... But I am having horrible luck with any ASP.NET functionality (this includes .aspx).
I really don't know what other information I need to put here, but if you ask for it, I shall provide it.
EDIT 1:
Now I am just getting 404 errors on any .cshtml page I try to view. This happened before when I didn't have the MIME types in, but was corrected (to at least plain text) when I entered the MIME type in. I have no idea what is going on... at this point I am almost ready to just uninstall everything and try to start over. =\
EDIT 2:
Okay, so I have gotten rid of my 404 and 500 errors. I ended up adding a privileged user to the application pool (advanced settings > process model > Identity). It was set as defaultAppPool before. Now I am getting this:
Type 'ASP._Page_default2_cshtml' does not inherit from 'System.Web.WebPages.WebPage'.
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.Web.HttpException: Type 'ASP._Page_default2_cshtml' does not inherit from 'System.Web.WebPages.WebPage'.
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:
[HttpException (0x80004005): Type 'ASP._Page_default2_cshtml' does not inherit from 'System.Web.WebPages.WebPage'.]
System.Web.UI.Util.CheckAssignableType(Type baseType, Type type) +9633480
System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(VirtualPath virtualPath, Type requiredBaseType, HttpContext context, Boolean allowCrossApp) +66
System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(String virtualPath, Type requiredBaseType) +28
System.Web.WebPages.BuildManagerWrapper.CreateInstanceOfType(String virtualPath) +203
System.Web.WebPages.VirtualPathFactoryExtensions.CreateInstance(IVirtualPathFactory factory, String virtualPath) +145
System.Web.WebPages.VirtualPathFactoryManager.CreateInstanceOfType(String virtualPath) +153
System.Web.WebPages.VirtualPathFactoryExtensions.CreateInstance(IVirtualPathFactory factory, String virtualPath) +73
System.Web.WebPages.WebPageHttpHandler.CreateFromVirtualPath(String virtualPath, IVirtualPathFactory virtualPathFactory) +23
System.Web.WebPages.WebPageRoute.DoPostResolveRequestCache(HttpContextBase context) +349
System.Web.WebPages.WebPageHttpModule.OnApplicationPostResolveRequestCache(Object sender, EventArgs e) +89
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +136
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +69
Any more ideas? Oh, and creating a new application didn't help, but it was a good idea.
It could be that an older version of System.Web.WebPages.dll is loaded to memory, and it tries to cast the your cshtml page to a version of WebPages class from that dll.
To test this, try to see what http modules are currently registered:
var allModules = HttpContext.Current.ApplicationInstance.Modules;
for( int i = 0; i < allModules.Count; i++ ) {
Trace(allModules.GetKey(i));
}
In my case that was:
....
__DynamicModule_System.Web.WebPages.WebPageHttpModule, System.Web.WebPages, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35_bca8e05a-5746-45b0-be95-2b920b455ccf
__DynamicModule_System.Web.WebPages.WebPageHttpModule, System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35_c1a67b42-31a9-47f1-8483-9e712fabe2a7
To fix the problem you need to replace the older version of System.Web.WebPages.dll in your /Bin folders, or some other dlls that might be referencing it.
You can try explicitly setting the ContentType in the action:
public ActionResult NotFound() {
Response.ContentType = "text/html";
return View(); }

ASP.NET 4.0 application cannot find Default.aspx under IIS6

I've got an ASP.NET 4.0 web application (webforms, not mvc; asp.net routing isn't used) that runs fine under IIS7. When I try to run it under IIS6 and navigate to http://localhost/MyApp/, I get the following exception:
File does not exist.
System.Web.HttpException
at System.Web.StaticFileHandler.GetFileInfo(String virtualPathWithPathInfo, String physicalPath, HttpResponse response) (+0 IL, +2509040 JIT)
at System.Web.StaticFileHandler.ProcessRequestInternal(HttpContext context, String overrideVirtualPath) (+54 IL, +198 JIT)
at System.Web.DefaultHttpHandler.BeginProcessRequest(HttpContext context, AsyncCallback callback, Object state) (+263 IL, +347 JIT)
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() (+214 IL, +8967220 JIT)
at System.Web.HttpApplication.ExecuteStep(HttpApplication.IExecutionStep step, Boolean& completedSynchronously) (+54 IL, +184 JIT)
Note that this output comes from my own custom error page. Thus, .NET itself is working fine. I can even remotely debug it and stuff.
Now, if I enter http://localhost/MyApp/Default.aspx, all works fine, I get the default page, etcetera. The first thought would be that the default document isn't specified in IIS, but it is. Even worse - if I disable it altogether, I still get the same error message (and yes, I restarted IIS and cleared my browser cache)!
It seems as if the request for / is always sent directly to ASP.NET which then gets confused because it doesn't have any default document concept. But I don't have any wildcard mappings defined, so how can that be?
After Googling I found this one as a solution. Its unrelated but some commented its working.
Can you please try this.
In the Windows registry, open the following node: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ASP.NET\4.0.30319.0
1.Create a new DWORD value named EnableExtensionlessUrls.
2.Set EnableExtensionlessUrls to 0. This disables extensionless URL behavior.
3.Save the registry value and close the registry editor.
4.Run the iisreset command-line tool, which causes IIS to read the new registry value

How to deploy an ASP.NET website with a Linq to Sql component

I have a .NET 3.5 web application that I recently added some Linq to Sql functionality to -- a dbml file, etc. Locally, it works fine.
However, when I try to deploy it, I get a null reference exception, apparently when it's trying to call the constructor for the context object.
To add to the complexity, I use a Web Deployment Project which compiles it into a single DLL. I assumed the Linq to Sql stuff would get compiled along with everything else. However, now I'm thinking that I need to move the dbml file up along with the DLL.
I had the dbml file in the App_Code directory, so I tried recreating that directory structure on the remote server. But .NET will not let me have an App_Code directory on a precompiled application. So I just moved the dbml file into the root directory -- but I still get the error.
Help!
Here's the stack trace for the error I'm getting:
[NullReferenceException: Object reference not set to an instance of an object.]
codeCS.SarcStateDataDataContext..ctor() +28
DB_Interface.SarcStateDataDB..ctor() +26
eSARC_Basic..ctor() +56
ASP.esarc_basic_aspx..ctor() +14
__ASP.FastObjectFactory_sarcwriting.Create_ASP_esarc_basic_aspx() +20
System.Web.Compilation.BuildResultCompiledType.CreateInstance() +32
System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(VirtualPath virtualPath, Type requiredBaseType, HttpContext context, Boolean allowCrossApp, Boolean noAssert) +119
System.Web.UI.PageHandlerFactory.GetHandlerHelper(HttpContext context, String requestType, VirtualPath virtualPath, String physicalPath) +33
System.Web.UI.PageHandlerFactory.System.Web.IHttpHandlerFactory2.GetHandler(HttpContext context, String requestType, VirtualPath virtualPath, String physicalPath) +40
System.Web.HttpApplication.MapHttpHandler(HttpContext context, String requestType, VirtualPath path, String pathTranslated, Boolean useAppConfig) +160
System.Web.MapHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +93
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155
DB_Interface.SarcStateDataDB is a class I wrote that calls the constructor for the context object:
codeCS.SarcStateDataDataContext context = new SarcStateDataDataContext();
I don't send it a connection string or connection object, because both the local and deployed versions of the program use the same remote database. But could that be the problem? The local application has access to the connection string in the dbml file, but the deployed application doesn't ... ??
UPDATE: I looked at the code in Reflector and it is getting the connection string from the web.config, and everything looks copasetic on that issue ...
OK, I found the problem! The connection string name it was looking for -- SarcWritingConnectionString -- was something that apparently Linq to Sql had added to the web.config when I was setting it up initially, going through the wizard. And I did not move up the new web.config to the server when I deployed the project, because I thought that it had not changed. When I move it up, everything works!
(I used a data connection I had already set up in Server Explorer instead of a connection string that was already in the web.config -- I wasn't even sure how to do that.)
Thanks for your help -- it's good to know I don't need to move up the dbml file. Next time will be easier!
Hi Cynthia
You don't need to deploy .dbml file. The null reference exception is not caused by the lack of .dbml. It's hard to guess the problem with the provided information, but first of all check that the data on the production and development database are the same. Maybe the production database lacks some records and you get nullreference from there. Also make sure that you deploy the project using VS Publishing Wizard (Right click on the project -> Publish). Also, if this doesn't help, could you post a stack trace of the exception?
Thanks
I'd suggest that you pass DB_Interface.SarcStateDataDB the connection string you want to use when you instantiate the class, then use that in its codeCS.SarcStateDataDataContext context = new SarcStateDataDataContext();.
Then you can manage the connection string at the application level, presumably in your web.config file. This way if you ever switch to using a dev db that is separate from prod, then you easily transition to separate connection strings.

Handle URI hacking gracefully in ASP.NET

I've written an application that handles most exceptions gracefully, with the page's design intact and a pretty error message. My application catches them all in the Page_Error event and there adds the exception to HttpContext.Curent.Context.Items and then does a Server.Transfer to an Error.aspx page. I find this to be the only viable solution in ASP.NET as there seems to be no other way to do it in a centralized and generic manner.
I also handle the Application_Error and there I do some inspection on the exception that occurred to find out if I can handle it gracefully or not. Exceptions I've found I can handle gracefully are such that are thrown after someone hacking the URI to contain characters the .NET framework considers dangerous or basically just illegal at the file system level.
Such URIs can look like e.g.:
http://exmample.com/"illegal"
http://example.com/illegal"/
http://example.com/illegal /
(notice the space before the slash at the end of the last URI).
I'd like these URIs to respond with a "404 Not Found" and a friendly message as well as not causing any error report to be sent to avoid DDOS attack vectors and such. I have, however, not found an elegant way to catch these types of errors. What I do now is inspect the exception.TargetSite.Name property, and if it's equal to CheckInvalidPathChars, ValidatePath or CheckSuspiciousPhysicalPath, I consider it a "path validation exception" and respond with a 404.
This seems like a hack, though. First, the list of method names is probably not complete in any way and second, there's the possibility that these method names gets replaced or renamed down the line which will cause my code to break.
Does anyone have an idea how I can handle this less hard-coded and much more future-proof way?
PS: I'm using System.Web.Routing in my application to have clean and sensible URIs, if that is of any importance to any given solution.
It may be that System.Web.Routing supports some sort of url filtering, but it is quite easy to implement your own.
Look at the System.Web.IHttpModule interface and read about implementing custom HTTP Modules. Http modules enter that Asp.Net pipeline and run before your page is run. You can use it to perform logging of requests, to modify requests and in your case to filter requests. The Asp.Net routing module is also implemented as a custom HTTP Module.
What you can do is to implement a Http Module that looks at the requested url and check if it is valid. If the url is invalid you can do whatever you need, for example redirect it to your 404 - not found page or you can just stop the request.
I don't think using System.Web.IHttpModule is the correct answer for IIS7+. I am trying to implement IHttpModule to validate the path but the exception has been thrown before the HttpModule is executed.
This is my exception stack:
[ArgumentException: Illegal characters in path.]
System.IO.Path.CheckInvalidPathChars(String path) +7493413
System.IO.Path.Combine(String path1, String path2) +40
System.Web.Configuration.UserMapPath.GetPhysicalPathForPath(String path, VirtualDirectoryMapping mapping) +114
System.Web.Configuration.UserMapPath.GetPathConfigFilename(String siteID, VirtualPath path, String& directory, String& baseName) +72
System.Web.Configuration.UserMapPath.MapPath(String siteID, VirtualPath path) +30
System.Web.Configuration.UserMapPath.MapPath(String siteID, String path) +31
System.Web.Hosting.HostingEnvironment.MapPathActual(VirtualPath virtualPath, Boolean permitNull) +297
System.Web.Hosting.HostingEnvironment.MapPathInternal(VirtualPath virtualPath, Boolean permitNull) +51
System.Web.CachedPathData.GetConfigPathData(String configPath) +341
System.Web.CachedPathData.GetVirtualPathData(VirtualPath virtualPath, Boolean permitPathsOutsideApp) +110
System.Web.HttpContext.GetFilePathData() +36
System.Web.HttpContext.GetConfigurationPathData() +26
System.Web.Configuration.RuntimeConfig.GetConfig(HttpContext context) +43
System.Web.Configuration.CustomErrorsSection.GetSettings(HttpContext context, Boolean canThrow) +41
System.Web.HttpResponse.ReportRuntimeError(Exception e, Boolean canThrow, Boolean localExecute) +101
System.Web.HttpRuntime.FinishRequest(HttpWorkerRequest wr, HttpContext context, Exception e) +383
and this is the link to Application Life Cycle for IIS 7.0 (http://msdn.microsoft.com/en-us/library/bb470252.aspx)
I am guessing that the exception caused by the "RESOLVE CACHE" step
Writing Custom HttpModule didn't work for me - I still got the "Illegal characters in path" error, but answer to this question solved the problem:
Turns out you could avoid this by setting allowDoubleEscaping="false" in for requestFiltering in web.Config. I.e:
<configuration>
<system.webServer>
<security>
<requestFiltering allowDoubleEscaping="false" />
</security>
</system.webServer>
</configuration>
Perhaps not the perfect solution (any suggestions for a better one is much appreciated), but it solves the problem.

Resources