ASP.NET MVC: Programmatically set HTTP headers on static content - c#

I have an ASP.NET application with a filter wired up in RegisterGlobalFilters that performs the following:
public class XFrameOptionsAttribute : ActionFilterAttribute
{
public override void OnResultExecuting(System.Web.Mvc.ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.AddHeader("X-FRAME-OPTIONS", "SAMEORIGIN");
}
}
Looking in Fiddler, I can see that views returned from the webserver include this header. Static files however, such as JavaScript do not include this header in the HTTP response.
How do I get ASP.NET MVC to also apply this filter to any static files the web server returns?

One way to set headers for all the content of site is in web.config. The customHeaders section will make sure that this header is included for all files and responses.
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-FRAME-OPTIONS" value="SAMEORIGIN" />
</customHeaders>
</httpProtocol>
</system.webServer>
Another option is to create custom HttpModule as shown below. This way you have more control on the files and content to which headers needs to be appended.
namespace MvcApplication1.Modules
{
public class CustomOriginHeader : IHttpModule
{
public void Init(HttpApplication context)
{
context.PreSendRequestHeaders += OnPreSendRequestHeaders;
}
public void Dispose() { }
void OnPreSendRequestHeaders(object sender, EventArgs e)
{
// For example - To add header only for JS files
if (HttpContext.Current.Request.Url.ToString().Contains(".js"))
{
HttpContext.Current.Response.Headers.Add("X-FRAME-OPTIONS", "SAMEORIGIN");
}
}
}
}
And then register them in web.config as shown below -
<system.webServer>
<modules>
<add name="CustomHeaderModule" type="MvcApplication1.Modules.CustomOriginHeader" />
</modules>
</system.webServer>

This is something that if you want on every request (static or dynamic requests), you should probably set it up through IIS (the web server). Here are some details on different ways that you can achieve this - http://www.iis.net/configreference/system.webserver/httpprotocol/customheaders
In short, you could do this in your web.config file
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-Custom-Name" value="MyCustomValue" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
If you have access directly to IIS, you can use the UI to set this up as well.

Related

Getting 405 error when making a DELETE request from an asp.net core app

I have an asp.net core API, from which I am trying to make a DELETE request to another asp.net core API. When I call the first API I receive a 405 error when it makes the delete call to the second API. I've tried the solution found here; ASP.NET Core with IIS - HTTP Verb Not Allowed, and several other related solutions without success. I've also tried Enabling Cross-Origin Requests (CORS) in my Startup.cs file, however nothing seemed to change.
Here is my delete endpoint:
[HttpDelete("MyDeleteEndpoint")]
public async Task MyDeleteEndpoint([FromRoute] string id)
{
var http = new HttpClient();
var response = await http.DeleteAsync("https://myserver:443/api/mycontroller/{id});
//do more stuff
}
Here is my web.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<modules runAllManagedModulesForAllRequests="false">
<remove name="WebDAVModule" />
</modules>
</system.webServer>
</configuration>
Here is my ConfigureServices and my Configure methods in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddCors(options =>
{
options.AddPolicy("mypolicy",
builder =>
{
builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
});
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseCors("mypolicy");
app.UseHttpsRedirection();
app.UseMvc();
}
Any ideas on what I could be doing wrong?
I've had this problem before. The only way to resolve it that I found was to explicitly list the methods that were allowed in the web.config.
Here is an excerpt from the web.config. Note that you probably don't want all of these settings but I'm leaving them in for brevity:
...
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Credentials" value="true" />
<add name="Access-Control-Allow-Methods" value="GET,PUT,POST,DELETE,OPTIONS" />
<add name="Access-Control-Allow-Headers" value="authorization,content-type" />
</customHeaders>
</httpProtocol>
...
Without explicitly adding the DELETE request to the allowed methods, the request was automatically rejected before it even got to my code.
If your application is being hosted under IIS, include this line in the Web.Config file
<configuration>
<system.webServer>
<modules>
<remove name="WebDAVModule" />
</modules>
</system.webServer>
</configuration>

WCF : How to remove http headers like aspnet version, server etc from WCF service calls

I have requirement where in for security reason I am not supposed to disclose response headers like server, asp.net version etc.
How can I restrict these headers when calls are made for WCF services.
I have already tried the below config settings but works fine for aspx page calls but not for WCF service calls.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<remove name="Server" />
<remove name="X-Powered-By" />
<remove name="X-AspNet-Version" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
Thanks,
Mahantesh M. B.
You can go into IIS and select your Site where your webservice is running on, in the IIS section there is a button called HTTP Response Headers, click on it and remove the headers
following your comment you can try to add a message inspector
public class RemoveHeaders: IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request,
IClientChannel channel, InstanceContext instanceContext)
{
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
var httpCtx = HttpContext.Current;
if (httpCtx != null)
{
httpCtx.Response.Headers.Remove(HttpResponseHeader.Server.ToString());
}
}
}

ASP.NET MVC 5 - Dynamically set CORS

In my MVC5 application, I've a controller that can be called from client applications (AngularJs in my case) and returns JSON.
For this particular Controller/Action, I want to set the Access-Control-Allow-Origin dynamically, depending of the "client_id" params in QueryString.
My problem is that I can't find a way to handle the Http Options request from the browser...
I've try many solutions:
1- [HttpOptions] Attribute on top of the Action Controller:
The code is never executed called
[HttpOptions]
public virtual ActionResult Refresh(string client_id)
{
// This code is never executed
// Should be setting CORS depending on the client_id
}
[HttpPost]
public virtual ActionResult Refresh(string client_id, FormCollection form)
{
// This is executed after the browser Http Options Request
}
2- Create my own ActionFilter, and put the CORS Headers from this filter: Never handle the Http Options Request.
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class ApplicationCrossOriginAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// This code is never executed on Http Options Request
// Set custom CORS header here on Http Options Request
base.OnActionExecuting(filterContext);
}
}
3- Use Global.asax Application_BeginRequest Event: Once again, the code is never reach with an Http Options Request...
I've so tried to simply configure CORS from the Web.config file, but I don't want to hardcode the Origins (and I can't since it's all domains are dynamic...)
But, yeah, everything works perfectly with this configuration:
<system.webServer>
<httpProtocol>
<customHeaders>
<clear/>
<add name="Access-Control-Allow-Origin" value="*" /><!--Not dynamic here-->
<add name="Access-Control-Allow-Methods" value="GET,POST,OPTIONS" />
<add name="Access-Control-Allow-Headers" value="Accept,Authorization" />
</customHeaders>
</httpProtocol>
</system.webServer>
I'm stuck here, as i don't know how to fill my needs...

httphandler intercept not working in IIS 7.0

I have an application done in .netframework 2.0 and trying to use an authentication handler in a security project, which is written in 3.5 framework. Also I m using IIS 7
Web.config of the application has the following entry
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<handlers accessPolicy="Read, Write, Script, Execute">
<add name="Pdfhandler" verb="*" path="/calderdale/*.pdf" type="NES.HiLo.Security.CalderDaleAuthenticationHandler, NES.HiLo.Security" preCondition="integratedMode" />
</handlers>
</system.webServer>
The code for CalderDaleAuthenticationHandler is
using System;
using System.Web;
namespace NES.HiLo.Security
{
public class CalderDaleAuthenticationHandler : IHttpHandler
{
/// <summary>
/// You will need to configure this handler in the web.config file of your
/// web and register it with IIS before being able to use it. For more information
/// see the following link: http://go.microsoft.com/?linkid=8101007
/// </summary>
#region IHttpHandler Members
public bool IsReusable
{
// Return false in case your Managed Handler cannot be reused for another request.
// Usually this would be false in case you have some state information preserved per request.
get { return false; }
}
public void ProcessRequest(HttpContext context)
{
//var application = (HttpApplication)sender;
//var context = application.Context;
HttpRequest request = context.Request;
HttpResponse response = context.Response;
// Check if the user is authenticated
}
#endregion
}
}
In my application I have a folder name calderdale and I have some pdf files. when I type in some thing like below to access the pdf file. I am expecting the control to go to handler, where I have set breakpoints. The control never goes to the handler. I appreciate any help.
http://local.knowledge.scot.nsh.uk/calderdale/abc.pdf
I used httphandlers to intercept the request. Then added a handler like this in web.config
<httpHandlers>
<add verb="GET" path="calderdale/*.pdf"
type="NES.HiLo.Security.CalderDaleAuthenticationHandler, NES.HiLo.Security" />
</httpHandlers>
After the above on IIS 7.0 I added the following handler from IIS Handlers section
<system.webServer>
<handlers>
<add name="Calderdale Handler" path="calderdale/*.pdf"
verb="GET" modules="IsapiModule"
scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll"
resourceType="Unspecified" requireAccess="Script"
preCondition="classicMode,runtimeVersionv2.0,bitness32" />
</handlers>
</system.webServer>

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

Categories