Preventing "A potentially dangerous Request.Path" in web api - c#

I have this controller.
public string Status([FromBody]StatusRequest p)
{
string ps= HttpContext.Current.Request["params"];
return ps;
}
It receives this post parameter value (The value is xml. Beneath is just part of it):
params=<Transaction hash=9
I get this infamous error:
A potentially dangerous Request.Form value was detected from the client
I tried a few solutions.
I tried to bind the post parameter. But there is no luck, it wont bind it so the value of 'p' is always null.
I tried setting web.config in the directory where my controller is:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<httpRuntime targetFramework="4.5" requestPathInvalidCharacters="?" />
<pages validateRequest="false" />
</system.web>
</configuration>
Those configurations have no effect on the files inside the directory.
Does anyone knows how to solve this?

This is really nasty exception because it reveals Server header even if you hide it so big bad guy can use that info against you.
I've found two solutions which help me. Let me explain both by using asterisk as example of dangerous symbol (but you can handle any single symbol or set of symbols in this way)
1st way is really ugly and I can't recommend it to anyone. But here it is:
Add to Global.asax.cs code
protected void Application_Error(object sender, EventArgs e)
{
if(Context.Request.RawUrl.Contains("*"))
{
Server.ClearError();
}
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
if(!Context.Request.RawUrl.Contains("*"))
{
return;
}
var newPath = Context.Request.RawUrl.Replace("*", "");
base.Context.RewritePath(newPath);
}
That's it. For any url with asterisk you'll omit this annoying exception and just replace dangerous symbol with anything you want.
2nd way is slightly trickier, but as for me, much better. Just keep in mind, that you can't use it if you don't have possibilities to install URL Rewrite module for IIS. Check next article for the details. Article is a little bit dated, if you use IIS 10 as I do, you need to get URL Rewrite module here.
So first of all you have to install this module. After that add this section to your web config file in system.webServer section:
<rewrite>
<rules>
<rule name="Rewrite URL to remove asterisk from path.">
<match url="^(.*)\*(.*)$" />
<conditions logicalGrouping="MatchAny" />
<action type="Rewrite"
url="{R:1}{R:2}" />
</rule>
</rules>
</rewrite>
That's all. Now almost any malformed url with asterisk will work without this annoying error.
Why almost? Because you'll still get exception if dangerous symbol presents in the name of, for example, IIS virtual directory.
So both ways handle errors like http://localhost/WebApplication1/api*/Values
And both ways fails with url like this http://localhost/WebApplication1*/api/Values

Just remove asterisk from requestPathInvalidCharacters under Web.config
...
<system.web>
<httpRuntime requestPathInvalidCharacters="<,>,*,%,&,:,\,?" />
...

Related

OData Function with DateTimeOffset? parameter

I'm trying to implement an OData collection function that receives two DateTimeOffset? parameters (MinSentOn and MaxSentOn) and will return some summary information from an Orders table, but I'm having routing problems when I pass the time part of the DateTimeOffset, receiving an HTTP Error 500.0 - Internal Server Error directly from IIS, because it seems it's trying to reach a file and not the controller itself.
This is my current OData configuration:
odataBuilder.Namespace = "D";
var fc =
odataBuilder.EntityType<Order>().Collection
.Function("ToExecutiveSummary")
.Returns<ExecutiveSummary>();
fc.Parameter<DateTimeOffset?>("MinSentOn");
fc.Parameter<DateTimeOffset?>("MaxSentOn");
This is the function in my controller:
[HttpGet]
public async Task<IHttpActionResult> ToExecutiveSummary(DateTimeOffset? minSentOn, DateTimeOffset? maxSentOn, CancellationToken ct)
{
return await _uow.ExecuteAndCommitAsync(async () =>
{
var query = _uow.Orders.Query();
if (minSentOn != null) query = query.Where(e => e.SentOn >= minSentOn.Value);
if (maxSentOn != null) query = query.Where(e => e.SentOn <= maxSentOn.Value);
// TODO needs optimization, test only
var executiveSummary =
query.Select(e =>
new ExecutiveSummary
{
TotalOrders = query.Count(),
TotalProducts = query.Sum(ex => ex.Quantity),
TotalPharmacies = query.GroupBy(ex => ex.Pharmacy.Id, ex => ex.Pharmacy.Id).Count()
}).FirstOrDefault();
return Ok(executiveSummary);
}, ct);
}
Snippet of the web.config changes to support the OData path and solve some routing problems I faced until I hit this wall, like dots or double escapes (changes have comments):
<configuration>
<!-- ... -->
<system.web>
<compilation debug="true" targetFramework="4.5.2" />
<!-- Removed : and % from the path filter -->
<httpRuntime targetFramework="4.5.2" requestPathInvalidCharacters="<,>,*,&,\,?"/>
<globalization uiCulture="pt-PT" culture="pt-PT" />
</system.web>
<!-- ... -->
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<!-- to support the dot (.) for functions or actions -->
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="/*" verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
<security>
<!-- to support double escapings, like 2015-08-10%2000:00:00.0000%2B01:00 -->
<requestFiltering allowDoubleEscaping="true"/>
</security>
</system.webServer>
<!-- ... -->
</configuration>
Now, during my testings, I'm facing the following:
If I don't pass the time part (example: http://localhost:58806/odata/Order/D.ToExecutiveSummary(MinSentOn=null,MaxSentOn=2015-08-10) ) the request reaches my code without any problem, making me believe that there aren't any problem with the OData configuration and route.
But when I include the time part (example: http://localhost:58806/odata/Order/D.ToExecutiveSummary(MinSentOn=null,MaxSentOn=2015-08-10%2000:00:00.0000%2B01:00) ) I receive an Internal Server Error (image attached) directly from the IIS. It seems it is trying to resolve to a file instead to the controller, whence the problem.
Ultimately, I know I could receive the parameters as strings and make the parse myself, but I would like to implement this without using the "hammer" :)
I do think you can use the parameter alias for DateTimeOffset parameter value.
For example:
http://localhost:58806/odata/Order/D.ToExecutiveSummary(MinSentOn=null,MaxSentOn=#p)?#p=2015-08-10%2000:00:00.0000%2B01:00
In the following Uri, you can find many parameter alias examples:
https://github.com/OData/WebApi/blob/master/OData/test/UnitTest/System.Web.OData.Test/OData/Formatter/ODataFunctionTests.cs#L24-L43
Moreover, in http://odata.github.io/WebApi/#04-06-function-parameter-support, you can find a simple guidance about function parameter.
However, the issue is a known issue related to IIS and be tracked on odata Web APi#github
Thanks.
I finally found the problem! It was related to the DateTimeOffset format I was using. I was forgetting the T, and writing 2015-08-10 00:00:00.0000%2B01:00 instead of 2015-08-10T00:00:00.0000%2B01:00 and it couldn't parse correctly.
What confused me was IIS throwing an Internal Server Error instead of some Bad Request or Not Found, and because the application exception handler wasn't being invoked, so I assumed the format was ok but IIS was having some problem with the path having unusual characters.
#Sam Xu suggestion lead me in the right path, because even using alias (I didn't know OData had support for parameter alias - thanks for that!) it was still throwing the exception...
In the end, it was a failure of mine, even if the server response should have been more enlightening...
You need to cast it to a DateTimeOffset like this:
cast(2015-08-10%2000:00:00.0000%2B01:00,Edm.DateTimeOffset)
Source: https://github.com/OData/WebApi/blob/master/OData/test/E2ETest/WebStack.QA.Test.OData/DateAndTimeOfDay/DateAndTimeOfDayTest.cs#L181

Web.config httpredirect is inserting a backslash when I don't want one

I'm updating a site into a more dynamic version of the site. And in the new site I use hash tags rather than a new page for every change in content.
I'm using web.config files in directories to redirect but it's adding a backslash. Is there anyway to avoid this? I'm already handling it in the redirect, but I feel it's kinda kludgy.
Here is an example web.config
<?xml version="1.0"?>
<configuration>
<system.webServer>
<httpRedirect enabled="true" destination="/legal/#!terms-of-use" />
</system.webServer>
</configuration>
Edit: It's worth mentioning, that instead of going to "/legal/#!terms-of-use" it goes to "/legal/#!terms-of-use/" Note the backslash at the end.
Turn on exactDestination in your redirect element, as below:
<httpRedirect enabled="true" destination="/legal/#!terms-of-use" exactDestination="true" />

URLParameter value bug in Intelligencia.UrlRewriter

my rewrite rule is
**<rewriter>
<rewrite url="~/categories/([0-9,A-Z,a-z,-]+)/(.+).aspx" to="~/inventory/product-list.aspx?categorycode=$1" processing="stop"/>
</rewriter>**
it works for url with
/category/abc/abc.aspx
but causes problem with
/category/con/abc.aspx
i dont understand why?
if we pass "con" as url parameter value in any site used by Intelligencia.UrlRewriter.
you may find similar problem.
Have researched so much and found an answer.
Actually IIS restricts us from use certain keywords in URL like
COM1-9, LPT1-9, AUX, PRT, NUL, CON
but we can solve this by using following settings in web.config file.
<configuration>
<system.web>
<httpRuntime relaxedUrlToFileSystemMapping="true"/>
</system.web>
</configuration>
It solved my problem.

ASP.Net C# Routing; HttpHandler; and HttpModule not working

I am having quite a few problems with custom extensions and intercepting existing handlers.
What am I trying to do
Based upon persisted options, I would like all 'virtual' extensions to be handled by set handlers. All pages are dynamically built, and no actual files exist on the site. The site populates the content, forms the html output and returns it as the web result.
This is required as I am setting up a fat/thin relationship between 2 servers. The thin server will simply pass on the request to the fat server - where the request is processed and response issued back down the line.
The project is for a dynamic multi-domain content management system. The thin server may not be .net compatible (hence the external request), but will be .net optimised (hence the need for handlers).
The Problem
What I want is to re-route existing extensions - aspx; php; html.
I have achieved this in my local environment using a custom HttpModule which sets the appropriate handler. I have explored setting the tag in config, but the the extensions are re-routed using dynamic rules that are persisted.
As mentioned, this solution works on localhost.
When uploaded, the .Net extensions are handled by the module correctly but any custom extensions or non-.net extensions return a 404 error.
Seeking an alternative, I have experimented with routing within Global, but this dis not work either.
I have also attempted to use to register the custom extensions... but each are met with the same result - 404 not found.
Global Routing attempt:
public class Global : System.Web.HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.Add(new Route("{action}.sqs", new SqlRequestHandler()));
}
.Config (for handler and module attempt)
<system.web>
<compilation debug="true" targetFramework="4.0" />
<httpRuntime requestValidationMode="2.0" />
<customErrors mode="Off"/>
<httpHandlers>
<add path="*.sqs" verb="*" type="CmsMapper.VirtualHandler, CmsMapper" />
<add path="*.sql" verb="*" type="CmsMapper.VirtualHandler, CmsMapper" />
</httpHandlers>
<httpModules>
<add name="SisBerCMS" type="CmsMapper.VirtualModule, CmsMapper" />
</httpModules>
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<modules>
<add name="SisBerCMS" type="CmsMapper.VirtualModule, CmsMapper" />
</modules>
<handlers>
<add path="*.sqs" verb="*" type="CmsMapper.VirtualHandler, CmsMapper" name="sqsHandler" />
<add path="*.sql" verb="*" type="CmsMapper.VirtualHandler, CmsMapper" name="sqlHandler" />
</handlers>
</system.webServer>
Custom Module (CmsMapper.VirtualModule)
if (extentionMap != null)
{
// note that extentionMap.ExtentionType is a predetermined enum
switch (extentionMap.ExtentionType)
{
// If the extention is banned then pass back a generic message
case ExtentionType.Banned:
this.WriteTextResponce("Invalid extention detected:" + extentionMap.Extention);
break;
// Remap .Ajax requests to the ajax handler
case ExtentionType.Ajax:
this._app.Context.RemapHandler(new AjaxHandler());
break;
// Remap session query or sql requests to the sql handler
case ExtentionType.SessionQuery:
this._app.Context.RemapHandler(new SqlRequestHandler());
break;
// if the extention is not ignored, re map to the virtual page handler
default:
bool isManagementServer = this._app.Context.Request.Url.Authority != VirtualModule.RESPONSE_SERVER;
bool isPostRequest = !String.IsNullOrEmpty(this._app.Context.Request.Form[HtmlRequest.RequestOrigin]);
bool isGetRequest = !String.IsNullOrEmpty(this._app.Context.Request.QueryString[HtmlRequest.RequestOrigin]);
bool isIgnored = extentionMap.ExtentionType == ExtentionType.Ignore;
if ((isPostRequest || isGetRequest) && !isIgnored)
{
this._app.Context.RemapHandler(new VirtualHandler());
}
else
{
this._app.Context.RemapHandler(new ExternalRequestHandler());
}
break;
}
}
All the handlers are pretty standard implementing the following:
public class SqlRequestHandler : IHttpHandler, IRequiresSessionState, IRouteHandler
Again, the preferred method - HttpModule - works on my localhost machine. This could be a server config issue (in which case I'm looking for a work around), but the fact that the .net extensions are being handled is strange - as this would imply that issues with medium trust should not apply, however issues regarding extension handling on the server may take priority over the .net application.
The server is shared hosting (therefore I am unable to alter the machine.config files), is IIS6 using 4.0.
Thank you for any suggestions on how to resolve this issue.
Mike
You need to configure web site in IIS 6.0 to route all extensions (including extensionless paths known as wildcard extension mapping) to ASP.NET ISAPI dll (and disable the check for file exists).
You can of course do this mapping selectively only for those extensions that you want to route via ASP.NET code. But wildcard mapping will be more useful in case you don't have predefined set of extensions.
In the absence of such mappings, IIS will not forward requests for unknown extensions to ASP.NET (and routing code will not even come into picture) - rather IIS will pass the extension to default (static file) handler that will issue 404 if file is not present.
See this article that describes these steps (for ASP.NET MVC but the same applies to your case): http://haacked.com/archive/2008/11/26/asp.net-mvc-on-iis-6-walkthrough.aspx
Near the end of article, author has given how to add wildcard script map

Using ELMAH and URLRewritingNet Together

I have ELMAH setup on my production server and it has done a fantastic job of letting me know about any niggles - as well as any creative SQL injection!
I've decided to introduce URl Rewriting and went for http://www.urlrewriting.net/ in the end. It was nice and easy to setup and it's doing exactly what I want with the customer-facing site.
The problem is ELMAH. Because I've set the urlrewritingnet node in my config like so:
<urlrewritingnet
rewriteOnlyVirtualUrls="true"
contextItemsPrefix="QueryString"
defaultPage = "default.aspx"
defaultProvider="RegEx"
xmlns="http://www.urlrewriting.net/schemas/config/2006/07" >
...ELMAH likes to do this to it's axd links;
http://www.mydomain.com/elmah.axd/stylesheet/default.aspx
Does anyone have any idea how to either
a) stop the re-writer following the .axd; or
b) add rules to the re-writer to get ELMAH to work
Any ideas? I'm happy to hack about with the httpHandlers...
I had the same issue - urlrewritingnet messing up my elmah - but found an answer here: http://markmail.org/message/ctbh6ozzqpe4qn6j#query:+page:1+mid:ctbh6ozzqpe4qn6j+state:results
Basically set defaultPage to empty like this:
Before (shortened):
<urlrewritingnet defaultPage="default.aspx" ... >
After (shortened):
<urlrewritingnet defaultPage="" ... >
Now all css styles work for Elmah.
I came up with a simpler solution if others are interested.
I just modify the source code directly and add in some basic logic to ignore specific rewrite rules.
I kind of solved this, but not in the way I wanted too. For the reference of others, I will provide a breakdown of what I did and the resources;
ELMAH: http://code.google.com/p/elmah/
URLRewritingNet: http://www.urlrewriting.net/149/en/home.html
This was really the only available option to me: http://csharpin.blogspot.com/2009/03/using-urlrewritingnet-and-elmah.html, but I had untold difficulty to get the code into my existing architecture without other adverse affects. I did try adding rules to the ExternalRewrite.config (URL Rewrite) to ignore *.axd, but that didn't pan out either. I was getting all sorts of weird behaviour.
I then decided to use Health Monitoring: https://web.archive.org/web/20211020102851/https://www.4guysfromrolla.com/articles/031407-1.aspx instead of ELMAH. Sorry ELMAH :(
Health Monitoring was a snip to setup and then all I had to do was solve the nasty postback problem on rewritten URLs;
Health Monitoring web.config;
<!--he-mon-->
<healthMonitoring enabled="true">
<eventMappings>
<clear />
<add name="All Errors" type="System.Web.Management.WebBaseErrorEvent" startEventCode="0" endEventCode="2147483647" />
</eventMappings>
<providers>
<clear />
<add connectionStringName="healthMonitoringConnectionString" maxEventDetailsLength="1073741823" buffer="false" name="SqlWebEventProvider" type="System.Web.Management.SqlWebEventProvider" />
<add type="System.Web.Management.SimpleMailWebEventProvider" name="EmailWebEventProvider" from="xxx" to="yyy" bodyHeader="zzz" bodyFooter="000" buffer="false" />
</providers>
<rules>
<clear />
<add name="All Errors Default" eventName="All Errors" provider="SqlWebEventProvider" profile="Default" minInstances="1" maxLimit="Infinite" minInterval="00:00:00" />
<add name="All Errors Default Email" eventName="All Errors" provider="EmailWebEventProvider" profile="Default" minInstances="1" maxLimit="Infinite" minInterval="00:00:00" />
</rules>
</healthMonitoring>
<!--he-mon-->
Add the connection string to the connectionString node too.
To fix the rather nasty postback on URL rewritten strings, I tried ScottGu's suggestion; Handling ASP.NET PostBacks with URL Rewriting: http://weblogs.asp.net/scottgu/archive/2007/02/26/tip-trick-url-rewriting-with-asp-net.aspx, but I couldn't get that to work at all.
Starting to really regret getting into URL Rewriting, I finally added this to the one problematic page I had; Me.Form.Action = Me.Request.RawUrl within the Page_Load and it worked a treat.
I know this doesn't directly answer the question, but I hope it helps. I hope someone finds my information at least somewhat useful.

Categories