Our site is not currently safe from clickjacking, so I went into the web.config and added
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="X-Frame-Options" value="DENY" />
</customHeaders>
</httpProtocol>
</system.webServer>
This is very straight forward code. My issue is that it's just not working. The questions I have are:
Is there a way for me to see if the X-Frame-Options is in the header response? I looked for it with httpfox and got nothing, so I can't verify if the web.config is actually putting things in the header.
Why is this not working? What can I do to test or move forward?
I did try to add it in the Global.asax in the Application_Start method, but I cant seem to "hit" this method when I debug; it does not hit breakpoints.
private void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
HttpContext.Current.Response.AddHeader("x-frame-options", "DENY");
LogHelper.Info("Cost of Care Web Application Starting");
}
I would like to add that I have tried to add it straight into the head tag and I've also tried to add it in a meta tag like so
<meta http-equiv="X-Frame-Options" content="deny">
The X-Frame-Options header can be used to control whether a page can be placed in an IFRAME. Because the Framesniffing technique relies on being able to place the victim site in an IFRAME, a web application can protect itself by sending an appropriate X-Frame-Options header.
To configure IIS to add an X-Frame-Options header to all responses for a given site, follow these steps:
Open Internet Information Services (IIS) Manager.
In the Connections pane on the left side, expand the Sites folder and select the site that you want to protect.
Double-click the HTTP Response Headers icon in the feature list in the middle.
In the Actions pane on the right side, click Add.
In the dialog box that appears, type X-Frame-Options in the Name field and type SAMEORIGIN or DENY in the Value field.
Click OK to save your changes.
Since my comments answered the question here's the end result:
For some reason setting the X-Frame-Options in web.config doesn't seem to actually work even though the documentation makes it sound like it should.
An easy work around is to set the headers manually using:
Response.AddHeader("X-Frame-Options", "DENY");
If you need this set for every request with no exceptions you can add the Application_BeginRequest to Global.asax:
protected void Application_BeginRequest()
{
Response.AddHeader("X-Frame-Options", "DENY");
}
The answer of siva.k does not work in connection with MVC5 as the header is generated twice here. The following code should work:
protected void Application_Start()
{
// MVC5 generates the "X-Frame-Options SAMEORIGIN" header by default, the following line disables the default behaviour
System.Web.Helpers.AntiForgeryConfig.SuppressXFrameOptionsHeader = true;
}
protected void Application_BeginRequest()
{
Response.AddHeader("X-Frame-Options", "DENY");
}
The SuppressXFrameOptionsHeader flag was mentioned here: https://stackoverflow.com/a/20262211/3936440
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Content-Security-Policy" value="default-src: https:; frame-ancestors 'self' X-Frame-Options: SAMEORIGIN" />
</customHeaders>
</httpProtocol>
</system.webServer>
Your web.config entry needs to be under content security policy to make use of current coding not previously depreciated. The value under content security policy of value="default-src: https: is unique to your website.
The content that matters is what comes after 'value="default-src: https:' but most importantly is contained within Content Security Policy.
Here is another thing to consider:
If you have a separate back-end and UI projects (as is very common for REST based sites), make sure that you put X-Frame-Options in the UI web.config. Your API is probably allowing cross site calls so adding the header to your API project would make no sense.
I found that some file types (.asp and .htm files) were getting the X-Frame-Options header added by this mechanism and others (.js) weren't. Using the IIS Admin utility I removed the header from the application level and added it at the server level, and then all files were getting the header added.
Related
The issue I have is we currently are using IdentityServer as our SSO authentication for our corporate applications. However, the bulk of our applications are under the same Site ID in IIS 7.5. When navigating to more than 5 of these applications under the same Site ID, you end up getting a 400 error, request header too long. The reason being each application has its own cookie, so the request header is passing around 5+ cookies with token information and the becoming too large.
My question is, are you able to prevent the sharing of cookies between applications under the same Site ID in IIS 7.5?
We also have IdentityServer for SSO and internal applications hosted on the same machine on IIS.
And I faced with the same problem too.
Here is a solution:
1) You need to solve Owin/Katana middleware problem to avoid nonce overfloating. Here you can find the code for that fix
2) You have to stop sharing cookies.
So if your base address for applications is "mysite.com".
And you have a lot of different applications like this:
Good App: mysite.com/good_app/
Best App: mysite.com/best_app/
Super App: mysite.com/super_app/
Use CookiePath for each application on an application's side and it will limit cookies (and look here too).
Use the code like this (for "Good App"):
var cookieOptions = new CookieAuthenticationOptions
{
AuthenticationType = "Cookies",
CookieName = "GoodAppCookies",
// Cookie Path same as application name on IIS
CookiePath = "/good_app
};
Hope it'll help.
Few things that you can try. Make the following changes at the server level.
Highlight the server name in IIS, select "configuration editor", select "system.web" and "httpRuntime" and change "maxRequestLength" to "1048576".
You can also edit the "applicationHost.config" file in the following way- C:\Windows\System32\inetsrv\Config
<configuration>
<system.web>
<httpRuntime maxRequestLength="1048576" />
</system.web>
</configuration>
Edit "Request Filtering" settings at server level on IIS and set "maxAllowedContentLength" to "1073741824"
You can also edit the root web.config file in the following manner - C:\Windows\Microsoft.NET\Framework64*\v4.0.30319*\Config
*Folder is based on your application. if its a 32 bit application, navigate to "Framework" folder. If its a .net 2.0 application, navigate to v2.0.50727.
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="1073741824" />
</requestFiltering>
</security>
</system.webServer>
First of all - I want to say that I have not tried this myself, so I can't assure that it is a solution, but I'm trying to help.
The problem with the cookies originates from the Microsoft OWIN/Katana and the way they are encrypting them. They become enormous, but this has nothing to do with Identity Server. However here and here there are good discussion around this.
The main thing to try first is in the Startup.cs of the IdentityServer project, in the IdentityServerOptions.AuthenticationOptions there is a property SignInMessageThreshold which defaults to 5. Try setting it to something lower, this will keep your header smaller (which may cause round trips to identity server when an app doesn't have its message in the cookies, but this will not force the user to re-login).
Another thing, that we achieved in one of out projects, is to create a DataBase backed cookie session handler. In your clients, where you use
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies",
CookieName = cookieName,
});
There is also a property SessionStore. You can have a custom implementation of the Microsoft.Owin.Security.Cookies.IAuthenticationSessionStore. In our case this reduced the cookie size to less than (or around) 300.
I'm trying to implement an application that uses the same Token Based Authentication mechanism demonstrated in this really awesome example by Taiseer Joudeh.
In my application I kept encountering Cors problems. In some configurations I would get a 500 error on the Preflight (OPTIONS) request for the POST to get the token or I could get the token but then get a 404 error on the preflight request for the GET request to the actual API call with the Bearer token.
One difference was that Taiseer's code was setup to host in IISExpress (or Azure) and mine is hosted on Local IIS (running on Windows 7 at the moment).
On a hunch I tried hosting his API under Local IIS and I found the exact same problem. (500 error on the preflight request for the token and it looks like the actual API will work properly)
From what I've been reading it seems like this may be some conflict between the modules and handlers in IIS and the Cors implementation in WebApi but Taiseer's implementation works when hosted in Azure so perhaps it is a difference in the version of IIS (I'm currently running under Windows 7).
How can I sort out what is causing the problem?
The root of the problem
The Token action is not hosted in a controller but is instead built in somewhere in the lower level plumbing. The only access to the mechanism is through the override method GrantResourceOwnerCredentials() in the class that extends OAuthAuthorizationServerProvider. (In our case is ApplicationOAuthProvider.cs).
GrantResourceOwnerCredentials() does have the context available but it is not called as part of the PreFlight request so you have no way to insert the appropriate PreFlight response headers for CORS.
The solution
We eventually settled on the following solution. I'm not a big fan of it because it forces these headers into every response but at least it works.
The solution was to override Application_PreSendRequestHeaders() method in Global.asax to insert the appropriate headers.
Global.asax.cs
void Application_PreSendRequestHeaders(Object sender, EventArgs e)
{
var origin = Request.Headers.Get("Origin");
var validOrigins = ConfigurationManager.AppSettings["allowedCorsOrigins"].Split(',');
if(validOrigins.Any(o => o == origin))
{
Response.Headers.Set("Access-Control-Allow-Origin", origin);
Response.Headers.Set("Access-Control-Allow-Credentials", "true");
Response.Headers.Set("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization, withcredentials, Prefer");
Response.Headers.Set("Access-Control-Expose-Headers", "Claims, *");
Response.Headers.Set("Access-Control-Max-Age", "600");
Response.Headers.Set("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,OPTIONS");
}
}
This requires the following web.config entries:
web.config
<configuration>
<appSettings>
<add key="allowedCorsOrigins" value="http://www.allowedsite1.net,http://localhost:22687" />
<add key="allowedCorsMethods" value="get, post, put, delete, options, batch" />
<add key="allowedCorsHeaders" value="*" />
</appSettings>
...
</configuration>
The reason for the loop to search for the valid origins is that you can't respond with a list of allowed origins...
This solved most of the problems with one exception (If I recall correctly was problems with PUT and DELETE verbs). This required removing the "ExtensionlessUrlHandler-Integrated-4.0" and re-adding it with a path and verb in the handlers section of the web.config.
web.config (2nd change)
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="" />
</handlers>
....
</system.webServer>
Useful links related CORS
Really good description of PreFlight for CORS
Excellent Sample Application using Token Auth
It is not the IdentityServer you are using but it could be the same problem. Regarding to the IdentityServer´s Github page you have to activate RAMMFAR (runAllManagedModulesForAllRequests) for your application when running under the IIS.
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
</modules>
</system.webServer>
I had this same issue, I did everythin as suggested by Mr. Tom hall. But still chrome reported no Access-control-allow-origin header is present.. after inspecting with fidler i realized that my request goes through a proxy server and my proxy server is handling the preflight options request..
So in "internet options" i removed the proxy server and found out that everything is working...!!!
Following the procedure in this article I disabled the ARR Affinity cookie on my Azure Web App with this header in my responses:
Arr-Disable-Session-Affinity: True
It does remove the cookie, which is very much a good thing. But, the header itself is still coming through. This header doesn't really hurt anything, but according to that same doc it shouldn't be there:
If you add the Arr-Disable-Session-Affinity header to disable the affinity cookie, ARR will not set the cookie, but it will also remove the Arr-Disable-Session-Affinity header itself, so if your process is working correctly, you will see neither.
So...how do I get it to remove the header, too?
if you have added the Arr-Disable-Session-Affinity custom header as below in your Azure Web App web.config, then it is a correct behavior you still see the Arr-Disable-Session-Affinity header with value set to true and the ARR cookie removed in your HTTP response. I think it's an incorrect statement in the reference blog you provided which stated that the Arr-Disable-Session-Affinity header will be removed.
If you want to remove that header then the cookie will present, it's mutually exclusive.
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Arr-Disable-Session-Affinity" value="true" />
</customHeaders>
</httpProtocol>
The article you refer to doesn't say specifically how to add the header so I can't tell if you did it correctly. I haven't tested but according to this article you should set it in the Application_PreSendRequestHeaders:
protected void Application_PreSendRequestHeaders()
{
Response.Headers.Remove("Server");
Response.Headers.Remove("X-AspNet-Version");
Response.Headers.Remove("X-AspNetMvc-Version");
Response.Headers.Add("Arr-Disable-Session-Affinity", "True");
}
How can we remove the server header response in IIS 8.0/8.5?
My current server report:
Microsoft-IIS/8.0
Microsoft-IIS/8.5
For IIS 7.0 I used the URLScan 3.1 however this is only supported for IIS 7.0 and not 8.x
There is another solution and in my opinion this solution is the best and safe.
You can use UrlRewrite module created by the Microsoft. The Url Rewrite module redirects your url and can also change your IIS server name in the response header.
You don't have to use redirect property. You can use just change the Server header value.
Here are the steps:
First, download UrlRewrite module from this link:
http://www.iis.net/downloads/microsoft/url-rewrite and install
it on your IIS server. After that, restart IIS by this command on cmd
console
iisreset /restart
Add the following item to the your web config file under the <system.WebServer> tag. You can write anything to the Value item as server name.
Finally we changed the IIS version name on the data's header. Restart IIS again. via cmd console.
Bonus: If you want to test your website to see if it is working or not... You can use "HttpRequester" mozilla firefox plugin. for this plugin: https://addons.mozilla.org/En-us/firefox/addon/httprequester/
PS: I tested it and it worked for me on the IIS server. Not on the has been created temproray IIS server by the Visual studio.
It is possible now to remove Server header from web.config starting from IIS 10.0 :
<security>
<requestFiltering removeServerHeader ="true" />
</security>
More details on how to remove all unwanted/unnecessary headers can be found here.
Please note that this hides server header from the "application", as do all the other approaches. If you e.g. reach some default page or an error page generated by the IIS itself or ASP.NET outside your application these rules won't apply. So ideally they should be on the root level in IIS and that sill may leave some error responses to the IIS itself.
Note there is a bug in IIS 10 that makes it sometimes show the header even with the modified config prior to 2019.1C. It should be fixed by now, but IIS/Windows has to be updated.
Add the below code in Global.asax.cs:
protected void Application_PreSendRequestHeaders()
{
// Remove the default Server header
Response.Headers.Remove("Server");
// Optionally, add your own Server header
Response.AddHeader("Server", "My-App/1.0");
}
This has been tested to work under IIS 8.5 and 10.0.
Unfortunately most of the recommendations you will find online for removing the "Server" header in IIS will not work for IIS 8.0 and 8.5. I have found the only working option, and in my opinion, also the best, is to use an IIS Native-Code module.
Native-Code modules differ from the more common Managed modules, as they are written using the win32 APIs rather than ASP.NET. This means that they work for all requests (including static pages and images) rather than just requests that past though the ASP.NET pipeline. Using a Native-Code module, it is possible to remove unwanted headers at the very end of the request, meaning that you can remove headers (including the "Server" header) regardless of where they have been set.
Binaries and source code of an example Native-Code module for removing headers in IIS 7.0 to 8.5 are available in the following article.
https://www.dionach.com/en-au/blog/easily-remove-unwanted-http-headers-in-iis-7-0-to-8-5/
Just use clear tag in custom headers segment in web.config:
<system.webServer>
<httpProtocol>
<customHeaders>
<clear />
<add name="X-Custom-Name1" value="MyCustomValue1" />
<add name="X-Custom-Name2" value="MyCustomValue2" />
</customHeaders>
</httpProtocol>
</system.webServer>
For dynamic headers, You can use this code in Global.ascx:
protected void Application_PreSendRequestHeaders()
{
Response.Headers.Remove("Server");
Response.AddHeader("Sample1", "Value1");
}
This is dead simple. Just create a custom module:
public class HeaderStripModule : IHttpModule
{
public void Init(HttpApplication application)
{
application.PreSendRequestHeaders += (sender, args) => HttpContext.Current.Response.Headers.Remove("Server");
}
public void Dispose(){}
}
And then register in web.config or applicationHost.config if you want machine wide implementation.
<system.webServer>
<modules>
<add name="HeaderStripModule" type="MyNamespace.HeaderStripModule" />
</modules>
</system.webServer>
URLScan has been discontinued starting from IIS 7.5, since its functionalities are supposed to be available through "request filtering" option (feature added in IIS 7.5).
But the URLScan's 'Remove server header' option does not look like having any equivalent in "request filtering".
As said on this answer and this answer to you question, you can emptied the Server with URLRewrite instead, which remains available on IIS 8/8.5 (with some update required for having its UI in IIS administration console).
It turns out, looking at this blog, that URLScan can still be installed on IIS 8/8.5, if lack of official support is not an issue.
I have not tested myself. Here are the steps:
Install IIS 6 Metabase compatibility (if not already there)
Install Isapi Filters (if not already there)
Install URLScan (from download-able installer, not from web platform installer)
Configure URLScan through its ini file (by default in C:\Windows\System32\inetsrv\urlscan)
Maybe some iisreset or even a reboot should be done. URLScan should be visible in IIS among Isapi filters
In IIS Manager, at the server level, go to the Features view. Click on HTTP Response Headers. You can add/remove headers there. You can also manage the response headers at the site level as well.
I have a asp.net mvc application and am trying to get custom errors working with IISExpress.
Works in Casini fine:
<customErrors mode="On" defaultRedirect="/error">
<error statusCode="404" redirect="/error/notfound"/>
</customErrors>
When I've deployed mvc sites to IIS (7.5) before, all I had to do get my custom errors working was to set:
<httpErrors errorMode="Detailed"/>
I've tried explicitly specifying the status codes within the httpErrors section but nothing works. Here's an example:
<httpErrors errorMode="Detailed" defaultResponseMode="Redirect">
<clear/>
<error statusCode="404" path="/error/notfound"/>
</httpErrors>
Any ideas?
Thanks
Ben
This was caused partly due to my misunderstanding of how custom errors are actually invoked and also the fact that (IMHO), the handling of errors in asp.net mvc is a bit messed up.
The first issue was that in a number of my action methods, I was checking for the existence of an object e.g. a blog post, and returning a HttpNotFoundResult if the blog post was null. I was under the assumption that this would then display the custom error page that I had set up for 404 errors.
However, this is not the case. Returning a HttpNotFoundResult simply sets the status code of the response to 404. The rest is then handled by IIS, displaying the IIS 404 error page or by your browser if it has it's own custom error page.
One solution here is to return a HttpException which will use your custom error pages since the request is be handled by asp.net.
I chose instead to create a new ActionResult that allowed me to specify a view along with a http status code. I preferred this to throwing exceptions.
The next issue was that by default a new MVC project has a greedy route defined. If you make a request to /foo/bar the default MvcHandler will look for a controller called Foo. When it can't find it, it will return 404.
I had removed the default route and had no greedy routes. This meant that urls not matching any of my routes would not be handled by asp.net and would just fall back to IIS.
The solution here was to create a wildcard route at the bottom of my routing configuration to match all other requests and forward them to a custom PageNotFound action, that sets the status code to 404 and displays my custom view.
Some things worth pointing out.
You will need to set httpErrors errorMode="Detailed" for your custom error pages to be displayed in IIS/IISExpress. The rest however can be left alone.
Setting the defaultRedirect path in the customErrors section has no effect on 500 errors. This is because the global HandleErrorAttribute handles all 500 errors and just looks for a view called "Error" to display. This means that if your custom error page is actually a controller action, it will not be invoked. The above is true even if you explicitly specify a 500 error page.
You should still keep the defaultRedirect path however, as it will be used for other status codes if they are not specified explicitly.
If you are using iisexpress you can just comment out the entire httpErrors section < !-- --> in the applicationhost.config and replace it with the following:
<httpErrors errorMode="Custom">
<error responseMode="Redirect" statusCode="404" path="../missing/index.php" />
</httpErrors>
path is the url path to your custom site specific page