Empty request body when Transfer-Encoding is Chunked - NancyFX - c#

I have a very simple NancyFX module which I simply want to echo the results of an API call back to the sender.
I am using a facade which converts incoming XML to JSON before handing it off to the Nancy endpoint. This facade changes the content to JSON correctly as I can test it using the echo service for the api and can see the response.
However, because the facade removes the content-length header and sets transfer-encoding to chunked, the Request.Body is always empty in my Nancy module.
Is there a configuration needed to enable support for Chunked encoding in NancyFX?
I am hosting on IIS 7 currently, but have access to IIS 8 as well.
I can see that using OWIN hosting it is possible to enable chunked transfer using HostConfiguration, but due to other factors I cannot use OWIN hosting and rely on IIS hosting.
I have enabled chunked transfer on IIS with the command:
appcmd set config /section:asp /enableChunkedEncoding:True
My web.config is currently:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5.1" />
<httpHandlers>
<add verb="*" type="Nancy.Hosting.Aspnet.NancyHttpRequestHandler" path="*" />
</httpHandlers>
<httpRuntime targetFramework="4.5.1" />
<webServices>
<protocols>
<add name="HttpGet" />
<add name="HttpPost" />
</protocols>
</webServices>
</system.web>
<system.webServer>
<modules>
<remove name="WebDavModule" />
</modules>
<handlers>
<remove name="WebDAV" />
<add name="Nancy" verb="*" type="Nancy.Hosting.Aspnet.NancyHttpRequestHandler" path="*" />
</handlers>
<validation validateIntegratedModeConfiguration="false" />
<httpErrors existingResponse="PassThrough" />
</system.webServer>
</configuration>
The module itself is very simple and consists of:
Post["/"] = parameters =>
{
var traceRef = Guid.NewGuid();
var body = this.Request.Body.AsString();
Logger.Trace("Trace ref: {0}, request inbound.", traceRef);
Logger.Trace(body);
AuthRequest auth = new AuthRequest();
try
{
auth = this.Bind<AuthRequest>();
}
catch (Exception ex)
{
Logger.Error("Trace ref: {0}, error: {1}. Exception: {2}", traceRef, ex.Message, ex);
}
var responseObject = new
{
this.Request.Headers,
this.Request.Query,
this.Request.Form,
this.Request.Method,
this.Request.Url,
this.Request.Path,
auth
};
return Response.AsJson(responseObject);
};

My first thought when reading this was Transfer-Encoding is only meant for responses not requests. Looking at the list of HTTP header fields, Transfer-Encoding is only listed under Response Fields. But the spec doesn't mention request or response just sender and recipient. Now I'm not so sure.
Anyway, the ASP.NET hosting code explicitly excludes the body if the content length is 0, but the self-hosting code doesn't seem to have the same restriction. I'm not sure if this difference is intentional. You could remove the if statement that checks the content length and send a PR to the Nancy team. See what they come back with.

Related

How to protect or secured ASP.NET MVC from XSS?

I'm creating a web application using the latest version of ASP.NET MVC 5.2.3. I just concern in XSS attack. I figure out in ASP.NET Core is perfectly working protecting from this attack the XSS and this framework totally amazing but it lacked third party I need to my project. Here's my concern. I already enabled the custom error too but I disabled it currently for testing.
But I want to make sure this will catch also.
Input Validation is passed. To avoid this exception or error.
A potentially dangerous Request.Form value was detected from the client (Name="").
using, the [AllowHtml] attribute this is fine or using the AntiXss library.
But, from the URL. Example URLs,
http://localhost:54642/Employees/
http://localhost:54642/Employees/?a=<script>
link or url
this error should like,
A potentially dangerous Request.Path value was detected from the client (<).
So my solution is enabling this from Web.config then it works!
But Troy Hunt said from his tutorial this is not a good or better practice for this error. So I decided to look the best solution from this XSS attack.
In my form I normally add this anti-forgery token
#Html.AntiForgeryToken()
then on my controller I made sure validate the token
[ValidateAntiForgeryToken]
also when passing the variable or data, I always declare correct variable. Anyways if its member area page you can always restrict access to correct member roles example like
[Authorize] // for registered user
or more filtered
[Authorize(Roles = "SUBSCRIBER.VIEW")]
Below is only applicable for .net 4.5 and above
// web.config
<system.Web>
<httpRuntime targetFramework="4.5" />
</system.Web>
// enabling anti-xss
<httpRuntime targetFramework="4.5" encoderType="System.Web.Security.AntiXss.AntiXssEncoder,System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
Request validation Lazy validation was introduced in ASP.NET 4.5, I
just did some testing on it and it seems that lazy validation is the
enabled regardless of how you set the "requestValidationMode", after
you've installed the 4.5 framework.
Check out OWASP site. Here is the common ones I add in system.web in web.config file of a webapi app.
<httpProtocol>
<customHeaders>
<remove name="Server" />
<remove name="X-Powered-By" />
<remove name="X-Frame-Options" />
<remove name="X-XSS-Protection" />
<remove name="X-Content-Type-Options" />
<remove name="Cache-Control" />
<remove name="Pragma" />
<remove name="Expires" />
<remove name="Content-Security-Policy"/>
<clear />
<add name="X-Frame-Options" value="DENY" />
<add name="X-XSS-Protection" value="1; mode=block"/>
<add name="X-Content-Type-Options" value="nosniff" />
<add name="Cache-Control" value="no-cache, no-store" />
<add name="Pragma" value="no-cache" />
<add name="Expires" value="Sun, 1 Jan 2017 00:00:00 UTC" />
<add name="Content-Security-Policy" value="default-src 'self' 'unsafe-inline' data; img-src https://*;"/>
</customHeaders>
</httpProtocol>

Servicestack SOAP - Invalid credentials returning html in response

In my service, I have a custom auth provider that throws a HttpError if the credentials are invalid like so:
throw HttpError.Unauthorized("Invalid Username or Password");
When I access this service via REST and purposely enter invalid credentials, I get the expected response:
{
"ResponseStatus": {
"ErrorCode": "Unauthorized",
"Message": "Invalid UserName or Password",
}
}
However, doing the same thing via a SOAP client, I get a Html response from the IIS server:
This causes my SOAP client to break as it can't deserialize the response. This can also occur if incorrect data values are included in the request e.g. setting a string value on an integer parameter. The response is fine if an exception occurs in one of my services where I am handling the request (i.e. HttpError.NotFound thrown). I know a similar question has been answered here but it hasn't been updated since 2013. Is there a way to configure the response or override it?
Edit 1
I've updated my web.config to look like so (in system.webServer, I had to use "modules" instead of "httpModules".):
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<httpModules>
<add name="FormsAuthenticationDisposition" type="ServiceStack.SuppressFormsAuthenticationRedirectModule, ServiceStack" />
</httpModules>
<httpHandlers>
<add path="*" type="ServiceStack.HttpHandlerFactory, ServiceStack" verb="*" />
</httpHandlers>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true">
<add name="FormsAuthenticationDisposition" type="ServiceStack.SuppressFormsAuthenticationRedirectModule, ServiceStack" />
</modules>
<urlCompression doStaticCompression="true" doDynamicCompression="false" />
<handlers>
<add path="*" name="ServiceStack.Factory" type="ServiceStack.HttpHandlerFactory, ServiceStack" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true" />
</handlers>
</system.webServer>
and my AppHost has the following:
SetConfig(new HostConfig
{
HandlerFactoryPath = "/api"
});
SuppressFormsAuthenticationRedirectModule.PathToSupress = Config.HandlerFactoryPath;
However I'm still getting the same error as before. I'm wondering if this is due to me passing in credentials as a header with every request rather than specifically authenticating first? It's worth pointing out that this same error occurs when e.g. a string is set on an integer parameter.
Edit 2
This solution does in fact work. I was defining the incorrect HandlerFactoryPath:
SetConfig(new HostConfig
{
HandlerFactoryPath = "api"
});
The Yellow Screen Of Death is the result of ASP.NET Hijacking the Error Response of Unauthorized Error Responses. You can prevent ASP.NET from hijacking the Error Response with the SuppressFormsAuthenticationRedirectModule.
First you need to register the HTTP Module in your web.config:
<system.web>
<httpModules>
<add name="FormsAuthenticationDisposition" type="ServiceStack.SuppressFormsAuthenticationRedirectModule, ServiceStack" />
</httpModules>
</system.web>
<!-- Required for IIS 7.0 (and above?) -->
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<httpModules>
<add name="FormsAuthenticationDisposition" type="ServiceStack.SuppressFormsAuthenticationRedirectModule, ServiceStack" />
</httpModules>
</system.webServer>
next, configure the module with where your API lives - defaults to /api, so in your AppHost Configure:
public override void Configure(Funq.Container container)
{
SetConfig(new HostConfig {
HandlerFactoryPath = "api",
});
//this is the configuration for Hijacking prevention
SuppressFormsAuthenticationRedirectModule.PathToSupress = Config.HandlerFactoryPath;
}

CORS headers not being set when using dot (".") in query string

I'm having a strange and weird situtation here.
If I send a request to: /scenes/?lang=es-ar, the headers are set just fine and everything seems OK.
However, if I send one to: /scenes/?lang=es-ar&sort.asc=creation, the headers are missing and I'm unable to fetch the response due to cross origin.
CORS is automatically managed by Owin's CORS Middleware, so this is out of my hands.
Here is my middleware's configuration:
private void ConfigureCors(IAppBuilder application)
{
CorsPolicy policy = new CorsPolicy()
{
AllowAnyHeader = true,
AllowAnyOrigin = true,
SupportsCredentials = true,
};
policy.Methods.Add("GET");
policy.Methods.Add("POST");
policy.Methods.Add("PUT");
policy.Methods.Add("DELETE");
policy.Methods.Add("OPTIONS");
policy.ExposedHeaders.Add("Location");
application.UseCors(new CorsOptions()
{
PolicyProvider = new CorsPolicyProvider()
{
PolicyResolver = request => System.Threading.Tasks.Task.FromResult(policy)
}
});
}
Why are the headers not being sent on the response?
I'm guessing it has something to with the "." (dot) in sort.asc=creation
I'm using latest version of ASP.NET Web Api (5.2.3) and Microsoft.Owin.Cors (3.0.1)
There might be a possibility that hosting server IIS might be intercepting the pre-flight requests. To ensure ASP.NET handles OPTION requests, add the following in web.config:
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
In my opinion this is not a decent choice to use Microsoft.Owin.Cors with WebAPI, if you're planning to use IIS as hosting environment. A better choice for Asp.net WebAPi would be Asp.net web API implementation of CORS.

ASP.NET HTTP Handler Unrecognized Request

I have ASP.NET handler. But when I try to call it it says :
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
namespace SimpleHTTPHanlder
{
public class SimpleHandler : IHttpHandler
{
#region IHttpHandler Members
bool IHttpHandler.IsReusable
{
get { return true; }
}
void IHttpHandler.ProcessRequest(HttpContext context)
{
HttpResponse response = context.Response;
response.Write("<html><body><h1>Wow.. We created our first handler");
response.Write("</h1></body></html>");
}
#endregion
}
}
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
<httpHandlers>
<add verb="*" path="vishal.nayan" type="SimpleHTTPHanlder.SimpleHandler"/>
</httpHandlers>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
</system.webServer>
</configuration>
I try to make request like this, but with unsuccess:
http://localhost:60223/SimpleHTTPHanlder/vishal.nayan
Looking at our code which works, some ideas:
Try adding the handler under system.webServer instead of system.web
Try adding the attribute preCondition="integratedMode"
Try specifying a name attribute
I think as you have written your path as
http://localhost:60223/SimpleHTTPHanlder/vishal.nayan.
Instead of this try
http://localhost:60223/vishal.nayan
This is because your path element contain vishal.nayan only.
<httpHandlers>
<add verb="*" path="vishal.nayan" type="SimpleHTTPHanlder.SimpleHandler"/>
</httpHandlers>
if you still have issue then tell me does you have hosted on IIS or IIS express ?
If you have configured in IIS ( IIS 7 or 7.5 later then you have to configure in
<system.webServer>
<handlers>
<add name="test" verb="*" path="vishal.nayan" type="SimpleHTTPHanlder.SimpleHandler"/>
</handlers>
...... other configuration
</system.webServer>
http://localhost:60223/SimpleHTTPHanlder/vishal.nayan
is it a copy/paste with a typo ? ( Hanlder )

Dot character '.' in MVC Web API 2 for request such as api/people/STAFF.45287

The URL I'm trying to let work is one in the style of: http://somedomain.com/api/people/staff.33311 (just like sites as LAST.FM allow all sort of signs in their RESTFul & WebPage urls, for example "http://www.last.fm/artist/psy'aviah" is a valid url for LAST.FM).
What works are following scenarios:
- http://somedomain.com/api/people/ - which returns all people
- http://somedomain.com/api/people/staff33311 - would work as well, but it's not what I'm after
I'd want the url to accept a "dot", like the example below
- http://somedomain.com/api/people/staff.33311 - but this gives me a
HTTP Error 404.0 - Not Found
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
I've set up following things:
The controller "PeopleController"
public IEnumerable<Person> GetAllPeople()
{
return _people;
}
public IHttpActionResult GetPerson(string id)
{
var person = _people.FirstOrDefault(p => p.Id.ToLower().Equals(id.ToLower()));
if (person == null)
return NotFound();
return Ok(person);
}
The WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
I already tried following all the tips of this blogpost http://www.hanselman.com/blog/ExperimentsInWackinessAllowingPercentsAnglebracketsAndOtherNaughtyThingsInTheASPNETIISRequestURL.aspx but it still won't work.. I also think it's quite tedious and I wonder if there isn't another, better and more secure way.
We have our Id's internally like this, so we're going to have to find a solution to fit the dot in one way or another, preferably in the style of "." but I'm open to alternative suggestions for urls if need be...
Suffix the URL with a slash e.g. http://somedomain.com/api/people/staff.33311/ instead of http://somedomain.com/api/people/staff.33311.
Following setting in your web.config file should fix your issue:
<configuration>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
I've found that adding the following before the standard ExtensionlessUrlHandler solves the issue for me:
<add name="ExtensionlessUrlHandler-Integrated-4.0-ForApi"
path="api/*"
verb="*"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
I don't think the name actually matters all that much except it probably helps if your IDE (Visual Studio in my case) is managing your site configuration.
H/T to https://stackoverflow.com/a/15802305/264628
I don't know what I am doing really, but after playing with the previous answer a bit I came up with another, perhaps more appropriate, solution:
<system.webServer>
<modules>
<remove name="UrlRoutingModule-4.0" />
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />
</modules>
</system.webServer>
I found that I needed to do more than just set the runAllManagedModulesForAllRequests attribute to true. I also had to ensure that the extensionless URL handler was configured to look at all paths. In addition, there is one more bonus configuration setting you can add which will help in some cases. Here is my working Web.config:
<system.web>
<httpRuntime relaxedUrlToFileSystemMapping="true" />
</system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true" />
<handlers>
<remove name="WebDAV" />
<remove name="OPTIONSVerbHandler" />
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*" verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
Note, specifically, that the ExtensionlessUrlHandler-Integrated-4.0 has its path attribute set to * as opposed to *. (for instance).
I'd use this in Web.config file:
<add name="ManagedSpecialNames" path="api/people/*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
before standard "ExtensionlessUrlHandler".
For instance in my case I put it here:
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ManagedFiles" path="api/people/*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
So you force URLs of such pattern to be managed by you, instead of standard management as files in application directory tree.
I got stuck in this situation but appending /
at the end of URL wasn't look clean for me.
so just add below in web.config handlers tag
and you will be good to go.
<add name="Nancy" path="api" verb="*" type="Nancy.Hosting.Aspnet.NancyHttpRequestHandler" allowPathInfo="true" />
I found that both way works for me: either setting runAllManagedModulesForAllRequests to true or add ExtentionlessUrlHandler as following. Finally i choose to add extensionUrLHandler since runAllManagedModulesForAllRequests do have performance impact to the site.
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<remove name="WebDAV" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*" verb="*"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
I also faced this issue. I was under a circumstance where I was not supposed to play with IIS and website config related settings. So I had to make it working by making changes at the code level only.
The point is that the most common case where you would end up having dot character in the URL is when you get some input from the user and pass it as a query string or url fragment to pass some argument to the parameters in the action method of your controller.
public class GetuserdetailsbyuseridController : ApiController
{
string getuserdetailsbyuserid(string userId)
{
//some code to get user details
}
}
Have a look at below URL where user enters his user id to get his personal details:
http://mywebsite:8080/getuserdetailsbyuserid/foo.bar
Since you have to fetch some data from the server we use http GET verb. While using GET calls any input parameters can be passed only in the URL fragments.
So to solve my problem I changed the http verb of my action to POST. Http POST verb has the facility of passing any user or non-user input in body also. So I created a JSON data and passed it into the body of the http POST request:
{
"userid" : "foo.bar"
}
Change your method definition as below:
public class GetuserdetailsbyuseridController : ApiController
{
[Post]
string getuserdetailsbyuserid([FromBody] string userId)
{
//some code to get user details
}
}
Note: More on when to use GET verb and when to use POST verb here.

Categories