Middlewares to help secure your apps
To install Helmet.Net, run the following command in the NuGet Package Manager Console
Install-Package Helmet.Net
- X-XSS-Protection middleware
- "Don't infer the MIME type" middleware
- Middleware to turn off caching
- IE, restrict untrusted HTML
- Frameguard middleware
- Hide powered by
- Crossdomain
Trying to prevent: Cross-site scripting attacks (XSS), a subset of the above.
How we mitigate this: The X-XSS-Protection
HTTP header is a basic protection against XSS. It was originally by Microsoft but Chrome has since adopted it as well. To use it:
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
//omitted for brevity
appBuilder.Use<XssFilterMiddleware>();
//...
}
}
This sets the X-XSS-Protection
header. On modern browsers, it will set the value to 1; mode=block
. On old versions of Internet Explorer, this creates a vulnerability (see here and here), and so the header is set to 0
to disable it. To force the header on all versions of IE, add the option:
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
//omitted for brevity
appBuilder.Use<XssFilterMiddleware>(new XssFilterOptions
{
SetOnOldIE = true
});
// This has some security problems for old IE!
//...
}
}
Limitations: This isn't anywhere near as thorough as Content Security Policy
. It's only properly supported on IE9+ and Chrome; no other major browsers support it at this time. Old versions of IE support it in a buggy way, which we disable by default.
Some browsers will try to "sniff" mimetypes. For example, if my server serves file.txt with a text/plain content-type, some browsers can still run that file with <script src="file.txt"></script>
. Many browsers will allow file.js to be run even if the content-type isn't for JavaScript. There are some other vulnerabilities, too.
This middleware to keep Chrome, Opera, and IE from doing this sniffing (and Firefox soon). The following example sets the X-Content-Type-Options
header to its only option, nosniff
:
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
//omitted for brevity
appBuilder.Use<DontSniffMimetypeMiddleware>();
//...
}
}
MSDN has a good description of how browsers behave when this header is sent.
This only prevents against a certain kind of attack.
It's possible that you've got bugs in an old HTML or JavaScript file, and with a cache, some users will be stuck with those old versions. This will (try to) abolish all client-side caching.
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
//omitted for brevity
appBuilder.Use<NoCacheMiddleware>();
//...
}
}
This will set Cache-Control
and Pragma
headers to stop caching. It will also set an Expires header of 0, effectively saying "this has already expired."
If you want to crush the ETag
header as well, you can:
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
//omitted for brevity
appBuilder.Use<NoCacheMiddleware>(new NoCacheOptions
{
NoEtag = true
});
//...
}
}
Caching has some real benefits, and you lose them here. Browsers won't cache resources with this enabled, although some performance is retained if you keep ETag support. It's also possible that you'll introduce new bugs and you'll wish people had old resources cached, but that's less likely.
This middleware sets the X-Download-Options
header to noopen
to prevent IE users from executing downloads in your site's context.
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
//omitted for brevity
appBuilder.Use<IeNoOpenMiddleware>();
//...
}
}
Some web applications will serve untrusted HTML for download. By default, some versions of IE will allow you to open those HTML files in the context of your site, which means that an untrusted HTML page could start doing bad things in the context of your pages. For more, see this MSDN blog post.
This is pretty obscure, fixing a small bug on IE only. No real drawbacks other than performance/bandwidth of setting the headers, though.
Trying to prevent: Your page being put in a <frame>
or <iframe>
without your consent. This helps to prevent things like clickjacking attacks.
How do we mitigate this: The X-Frame-Options
HTTP header restricts who can put your site in a frame. It has three modes: DENY
, SAMEORIGIN
, and ALLOW-FROM
. If your app does not need to be framed (and most don't) you can use the default DENY
. If your site can be in frames from the same origin, you can set it to SAMEORIGIN
. If you want to allow it from a specific URL, you can allow that with ALLOW-FROM
and a URL.
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
// Don't allow me to be in ANY frames:
appBuilder.Use<FrameGuardMiddleware>("deny");
//...
}
}
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
// Only let me be framed by people of the same origin:
appBuilder.Use<FrameGuardMiddleware>("SAMEORIGIN");
//...
}
}
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
// Allow from a specific host:
appBuilder.Use<FrameGuardMiddleware>("allow-from","http://example.com");
//...
}
}
Limitations: This has pretty good (but not 100%) browser support: IE8+, Opera 10.50+, Safari 4+, Chrome 4.1+, and Firefox 3.6.9+. It only prevents against a certain class of attack, but does so pretty well. It also prevents your site from being framed, which you might want for legitimate reasons.
Simple middleware to remove the X-Powered-By
HTTP header if it's set.
Hackers can exploit known vulnerabilities in .net web apps if they see that your site is powered by .net web apps (or whichever framework you use). For example, X-Powered-By: aspnet/mvc
is sent in every HTTP request coming from .net, by default.
The hidePoweredBy
middleware will remove the X-Powered-By
header if it is set.
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
appBuilder.Use<HidePoweredByHeaderMiddleware>();
//...
}
}
You can also explicitly set the header to something else, if you want. This could throw people off:
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
appBuilder.Use<HidePoweredByHeaderMiddleware>(new HidePoweredOptions { SetTo = "steampowered" });
//...
}
}
Adobe defines the spec for crossdomain.xml, a policy file that grants some Adobe products (like Flash) read access to resources on your domain. An unrestrictive policy could let others load things off your domain that you don't want.
To serve up a restrictive policy:
appBuilder.Use<CrossDomainMiddleware>()
This serves the policy at /crossdomain.xml
. By default, this is case-insensitive. To make it case-sensitive:
appBuilder.Use<CrossDomainMiddleware>(new CrossDomainOptions()
{
CaseSensitive = false
});
// This will now ONLY match all-lowercase /crossdomain.xml.
This doesn't make you wildly more secure, but it does help to keep Flash from loading things that you don't want it to. You might also want some of this behavior, in which case you should make your own less-restrictive policy and serve it.
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
// Some other configuration.
appBuilder.Use<PermanentRedirectMiddleware>(new PermanentRedirectOptions()
{
RedirectRules = new List<RedirectRule>()
{
new RedirectRule("http://localhost:9000/test", "http://localhost:9000/test/r"),
new RedirectRule("http://localhost:9000/test2", "http://localhost:9000/test2/r")
}
});
}
}