MVC bundle with Azure CDN - how to enable caching - azure

I have a web site to be hosted in Azure that has a lot of javascript and CSS but very small pages. I would like to have the javascript and the CSS delivered via a CDN.
Azure provides a really neat and convenient mechanism to allow this as described here https://azure.microsoft.com/en-us/documentation/articles/cdn-cloud-service-with-cdn/#integrate-aspnet-bundling-and-minification-with-azure-cdn
In short, you add the following code to your BundleConfig.cs
bundles.UseCdn = true;
var version = System.Reflection.Assembly.GetAssembly(typeof(Controllers.HomeController))
.GetName().Version.ToString();
var cdnUrl = "http://axxxxxx6.vo.msecnd.net/{0}?v=" + version;
ScriptBundle scriptBundle = new ScriptBundle("~/bundles/xx", string.Format(cdnUrl, "bundles/xx"));
scriptBundle.Include(
"~/Scripts/modernizr-*",
"~/Scripts/jquery-{version}.js",
"~/Scripts/jquery.signalR-{version}.js",
"~/Scripts/jquery.watermark.js", ....
I have followed the instructions to the letter and on the surface it appears to work exactly as expected.
But I realised that the caching for these CDN provided resources is disabled. Every time the web page is requested the JS and the CSS are downloaded again - which defeats the purpose of the CDN altogether.
I have also included the following in the web.config
<staticContent>
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="15.00:00:00"/>
</staticContent>
What am I missing here?
Thanks in advance.
Dave A

Related

Why am I getting a 404 for my LESS file on my Azure App Service?

Ok, so... famous saying... this works locally, but not when I deploy.
I recently switched to using Less.js so that I could dynamically change my less variables with Javascript. Again, locally this works like a champ.
In my header I have it referenced:
<link rel="stylesheet/less" type="text/css" href="~/Content/main.less" />
<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/3.9.0/less.min.js"></script>
When I use Visual Studio to deploy this to my Azure App Service I get a 404 on the less file and it all breaks.
I FTP'd into my server and the file is indeed there. https://i.imgur.com/cV5FQOW.png
I double checked to make sure that my properties for the less file are right. I have the build action set to Content and Copy if Newer. https://i.imgur.com/I3DbfHg.png
No matter what I do, if I go looking for that main.less file the azure server returns a 404.
As an FYI, the site is a ASP.Net MVC 5 website. I am using bundling, but only for external css like JQueryUI. I have removed the bundling of my CSS to work with the new stuff.
What am I missing?
Ok! After a bunch of attempts and searches I finally found a related error and found my solution.
This poor gentleman was having an issue serving up JSON files (angular2 app, http request for file json file, 404 on azure) and that made me think I had the same problem.
Eureka! I needed to update my web.config to let it serve LESS files.
<system.webServer>
<staticContent>
<mimeMap fileExtension=".less" mimeType="text/css" />
</staticContent>
<system.webServer>
Hope this helps someone else who runs into the same issue.

How Can I have IIS properly serve .webmanifest files on my web site?

The Favicon Generator assembles a package for webmasters to use in order to have icons available for many different devices. The page comes with a file called site.manifest which is linked to via the following tag in the web page's document <head>:
<link rel="manifest" href="site.webmanifest">
According to Mozilla: "The web app manifest provides information about an application (such as name, author, icon, and description) in a JSON text file. The purpose of the manifest is to install web applications to the homescreen of a device, providing users with quicker access and a richer experience."
Unfortunately if you are using Microsoft's Internet Information Services (IIS), you'll get a 404.3 error if you try and access the site.webmanifest file.
The exact error message is as follows: "The page you are requesting cannot be served because of the extension configuration. If the page is a script, add a handler. If the file should be downloaded, add a MIME map."
How can I properly serve site.webmanifest files in IIS?
By default, IIS does not serve any files that does not have a MIME map associated with it in its (IIS) core settings.
To address this challenge, you will need to map the .webmanifest file extension to its appropriate MIME type.
To accomplish this, open IIS and follow the steps below;
On the left hand side, select either your web site or the entire server in the "Connections" menu.
If you select the server, your MIME mapping will apply to every web site on the server.
If you select a web site, it will only apply to a single web site.
Next, select "MIME Types" from the IIS menu:
Once there, click "add..." from the right hand menu.
In the dialog box that opens specify .webmanifest in the file name extension box application/manifest+json in the MIME type box.
Click "OK".
Congratulations; you've just defined the MIME type for .webmanifest on IIS.
For Azure I added this as the web.config
<?xml version="1.0"?>
<configuration>
<system.webServer>
<staticContent>
<mimeMap fileExtension=".json" mimeType="application/json" />
<mimeMap fileExtension=".webmanifest" mimeType="application/manifest+json" />
</staticContent>
</system.webServer>
</configuration>
For those using ASP.NET Core (I am using 2.1) you can configure the MIME types that can be served in the application Startup.cs file as per the static files docs:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
FileExtensionContentTypeProvider provider = new FileExtensionContentTypeProvider();
provider.Mappings[".webmanifest"] = "application/manifest+json";
app.UseStaticFiles(new StaticFileOptions()
{
ContentTypeProvider = provider
});
app.UseMvc();
}
Easier solution is to rename your manifest file to site.webmanifest.json and link as
<link rel="manifest" href="site.webmanifest.json">
IIS should already have a MIME Type for .json files
This is also helpful if deploying to Azure where its not so easy to change the IIS settings.
Adding to #Ben's answer: if you have a SPA you should put StaticFileOptions code into the UseSpaStaticFiles() call:
FileExtensionContentTypeProvider provider = new FileExtensionContentTypeProvider();
provider.Mappings[".webmanifest"] = "application/manifest+json";
app.UseSpaStaticFiles(new StaticFileOptions()
{
ContentTypeProvider = provider
});
I found that the IIS server had ".json" listed in the Request Filtering feature saying it was not allowed.
Removing that allowed the file to be served.

Stop Sharing Cookies between Applications under same Site ID in IIS

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.

X-Frame-Options not working IIS web.config

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.

Remove Server Response Header IIS 8.0 / 8.5

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.

Resources