How to disable open ASP.NET MVC site in IFrame? - asp.net-mvc

As I have already mentioned in topic, I have a MVC site and I need to disable loading it into IFrame.
I have created simple page for testing purpose and I try to load into two IFrames my site and Google.com. I can see that my site is loaded but Google isn't. It means that it's necessary to change something in my MVC site.
<!DOCTYPE html>
<html>
<body>
<iframe src="http://localhost:61831/" width="1200" height="800">
<p>Your browser does not support iframes.</p>
</iframe>
<iframe src="http://google.com" width="1200" height="800">
<p>Your browser does not support iframes.</p>
</iframe>
</body>
</html>
So what and where in MVC site I have to write to achieve that?

It is possible to use X-Frame-Options HTTP header attribute to avoid ASP.NET MVC application be opened in IFrame.
There are several different way to insert this attribute to HTTP header:
1.Configure IIS to add this attribute to all HTTP responses
2.Set this attribute in every necessary action method of every controller
public class HomeController : Controller
{
public ActionResult Index()
{
Response.AppendHeader("X-Frame-Options", "SAMEORIGIN");
return View();
}
}
3.Create C# attribute in a way described here and apply it to action methods and controllers
[HttpHeader("X-Frame-Options", "SAMEORIGIN")]
public class HomeController : Controller
{
public ActionResult Index()
{
}
}
4.Set this attribute in Global.asax file
public class MvcApplication : HttpApplication
{
protected void Application_Start()
{
...
}
protected void Application_PreSendRequestHeaders(object sender, EventArgs e)
{
Response.AppendHeader("X-Frame-Options", "SAMEORIGIN");
}
}

Simple and quick Solution is to add following in Global.asax -
protected void Application_PreSendRequestHeaders(object sender, EventArgs e)
{
Response.AddHeader("X-Frame-Options", "SAMEORIGIN");
}
Then give a try with iframe. Pages will not open in iframes. HTH.

You can also add an entry in web.config:
<system.webServer>
...
<httpProtocol>
<customHeaders>
<add name="X-Frame-Options" value="SAMEORIGIN" />
</customHeaders>
</httpProtocol>
...
</system.webServer>

You can configure IIS to always append the X-Frame-Options SAMEORIGIN header in it's responses.
From IIS Management Console, select your application.
In the main panel, double click Http Response Headers.
Click Add from the upper right pane.
Set the name to X-Frame-Options and the value to SAMEORIGIN then
click OK.
This should prevent your site from being loaded into an iframe on a different host, without using any javascript or any extra code.
See developper.mozilla.org for the header documentation and technet.microsoft.com for IIS' configuration.

As DrewMan suggested, you want to use X-Frame-Options header.
I would suggest you to download Nuget Package NWebsec and there's MVC specific package. Also check out the configuration part.

Related

MVC Custom errors not working in IIS8.5 (but working locally)

I can't get ANY custom error pages to appear in IIS8.5!
When I run my MVC 5 app locally in Visual Studio, custom error pages are displayed. But when I deploy to IIS on my webserver, and navigate to the site sub-page with a 'bad URL' my custom 404 page should be displayed, but the default generic 404 page is shown instead.
Here is what I've done:
web.config
customError section has been deleted.
Added the following section
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" />
<remove statusCode="500" />
<error statusCode="404" responseMode="ExecuteURL" path="/Error/NotFound" />
<error statusCode="500" responseMode="ExecuteURL" path="/Error/ServerError" />
</httpErrors>
</system.webServer>
Controller
namespace MyApp.Controllers
{
[Authorize(Roles = "MyRole")]
public class ErrorController : Controller
{
[AllowAnonymous]
public ActionResult NotFound()
{
Response.StatusCode = 404;
return View();
}
[AllowAnonymous]
public ActionResult ServerError()
{
Response.StatusCode = 500;
return View();
}
}
}
Views
Very simple and straight forwards (not included here).
IIS
Verified the IIS Error Page feature is identical to what's in my config. A page for each error status code. Feature and Pages are set to 'custom'.
Checked Windows Features\Web Server (IIS)\Web Server\Common HTTP Features\HTTP Errors is installed.
Developer Tools
Navigating to a sub-page spelt incorrectly shows I'm getting a 404 Client Error.
Help
I've tries many things! Am I missing something? IIS environmental issue, i.e. a setting somewhere?
Custom errors work in my IDE but not on IIS. I've spent over a day on this! Read many pages, articles, and similar questions on SO.
After several days of investigating, finally found the issue.
In IIS, my website was residing as an Application under the Default Web Site, e.g. Default Web Site\MyDevSite. (All my dev sites are under the default web site).
When I moved the website to it's own IIS site, custom error pages are now being displayed!
If anyone knowns the reason why having an Application in IIS prevents custom error pages from being displayed, please add a comment here. It would be good to understand why this occurs.
I hope this helps somebody out. Had me going for quite a while.
How are you browsing IIS? If you're doing it from the same machine, then you aren't going to see your custom error pages, because the customErrors section will default to using RemoteOnly if not specified.
the problem is with the path in web.config(path="/Error/NotFound"). the url path of NotFound page will be changed when you move your website under the Default Web Site. So, give the correct url of the page at path then it will work(this is worked for me).

sitemap.xml url returns 404 Error

I have a large affiliate marketing site with millions of products hosted on Windows Azure.
For SEO I have to provide a sitemap.xml which is dynamically created.
public ActionResult SiteMap()
{
string sitemapUrl = "https://trendley.blob.core.windows.net/sitemap/sitemap.xml";
byte[] bImage = null;
using (WebClient wc = new WebClient())
{
bImage = wc.DownloadData(sitemapUrl);
}
return File(bImage, "application/octet-stream");
}
I added the follwoing route to my RouteConfig:
routes.MapRoute("Sitemap",
"sitemap.xml",
new { controller = "Home", action = "Sitemap" });
Unfortunately this is not workting.
I get -> HTTP Error 404.0 - Not Found
When I change "sitemap.xml" to sitemapxml (remove the extension) my controller method is invoked.
Already did some research and played with my web.config but nothing seems to work.
First thing I tried was to add:
<modules runAllManagedModulesForAllRequests="true" />
Second thing:
<add
name="AdfsMetadata"
path="sitemap.xml"
verb="GET"
type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
Can someone tell me how to acomplish this.
Do I have to write my own Handler for this?
Cheers,
Stefan
The reason that that route is not working is because by default .xml is handled by the "StaticFileHandler" in IIS so when the request comes in ASP.net is not invoked.
Option 1: Enable runAllManagedModulesForAllRequests - in your web .config add the following
<modules runAllManagedModulesForAllRequests="true" />
It goes inside of the system.webserver node.
option 2: Add a mapping for .xml to IIS and force that file extension into the ASP.net pipeline. See here
Please follow these steps:
1- Delete sitemap.xml from root of website directory (if exists)
2- Put MapRoute for sitemap.xml over other MapRoutes like this :
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Sitemap",
"sitemap.xml",
new { controller = "Home", action = "Sitemap" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
The reason of error is when sitemap RouteMap is under other rules , MVC checks the /sitemap.xml with above RouteMap , then throws error 404 for no matching controller/action.
I Know this is an old topic, but I have a solution that is better than "runAllManagedModulesForAllRequests".
Modules Preconditions:
The IIS core engine uses preconditions to determine when to enable a particular module. Performance reasons, for example, might determine that you only want to execute managed modules for requests that also go to a managed handler. The precondition in the following example (precondition="managedHandler") only enables the forms authentication module for requests that are also handled by a managed handler, such as requests to .aspx or .asmx files:
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" preCondition="managedHandler" />
If you remove the attribute precondition="managedHandler", Forms Authentication also applies to content that is not served by managed handlers, such as .html, .jpg, .doc, but also for classic ASP (.asp) or PHP (.php) extensions. See "How to Take Advantage of IIS Integrated Pipeline" for an example of enabling ASP.NET modules to run for all content.
You can also use a shortcut to enable all managed (ASP.NET) modules to run for all requests in your application, regardless of the "managedHandler" precondition.
To enable all managed modules to run for all requests without configuring each module entry to remove the "managedHandler" precondition, use the runAllManagedModulesForAllRequests property in the <modules> section:
<modules runAllManagedModulesForAllRequests="true" />
When you use this property, the "managedHandler" precondition has no effect and all managed modules run for all requests.
You can learn more from it's original topic: runAllManagedModulesForAllRequests=“true” Meaning
So, the better way to set a HTTP handler for a .XML url on MVC is the following:
<system.webServer>
<handlers>
<add name="Sitemap" path="sitemap.xml" type="System.Web.UI.PageHandlerFactory" verb="*" />
</handlers>
</system.webServer>

Custom Errors not working with MVC4 project?

I'm trying to follow the answer to this question:
How to make custom error pages work in ASP.NET MVC 4
I have the following in my Web.Release.config:
<system.web>
<customErrors mode="On" defaultRedirect="~/Error">
<error redirect="~/Error/NotFound" statusCode="404" />
</customErrors>
</system.web>
I'm running in Release mode. I've added the following controller:
public class ErrorController : Controller
{
public ViewResult Index()
{
return View("Error");
}
public ViewResult NotFound()
{
Response.StatusCode = 404; //you may want to set this to 200
return View("NotFound");
}
}
And views for the controller actions:
#model System.Web.Mvc.HandleErrorInfo
#{
Layout = "../Shared/_Layout.cshtml";
ViewBag.Title = "Error";
}
<div class="list-header clearfix">
<span>Error</span>
</div>
<div class="list-sfs-holder">
<div class="alert alert-error">
An unexpected error has occurred.
</div>
</div>
I can access these pages via manual navigation. If I navigate to some bogus URL though, I get the standard yellow error page with ugly diagnostics info.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its
dependencies) could have been removed, had its name changed, or is
temporarily unavailable. Please review the following URL and make
sure that it is spelled correctly.
Requested URL: /ss
What am I doing wrong?
If custom errors are enabled, as in your example, and you are using the HandleErrorAttribute, the ASP.NET MVC runtime looks for the Error.chtml file in the current requests folder or in the shared
views folder. In this setup, the defaultRedirect (to GenericErrorPage.htm) and status
code redirect URI ("~/Error/NotFound") are ignored.

Web.config urlMappings - works for local pages, not remote pages

I have a MVC4/.Net 4 website running on IIS 7.5. In my web.config file I have the following in my block:
<urlMappings enabled="true">
<add url="~/2013calendar" mappedUrl="~/CustomerService/RequestPocketCalendar" />
<add url="~/teachers" mappedUrl="http://www.somexternalsite.com/teachers/" />
</urlMappings>
The local redirects all work great, but anything that is redirecting off the site, such as the /teachers link in the above example return "http://www.somexternalsite.com/teachers" is not a valid virtual path.
What am I missing here?
If I'm not mistaken, the mappedUrl field is a path relative to the root of the application. As such, "http://www.somexternalsite.com/teachers/" is not valid.
If you'd like to configure this to redirect, I would just create a "Teachers" action in your root controller, then use the following:
return Redirect("http://www.somexternalsite.com/teachers");
Well I ended up creating a page to handle external redirects such as follows:
redirect.aspx
<%# Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
void Page_Load(object sender, EventArgs e)
{
var page = Request.QueryString["page"];
Response.Redirect("http://"+page);
}
</script>
So in my web.config I have external files referenced as such:
<add url="~/teachers" mappedUrl="~/redirect.aspx?page=www.somexternalsite.com/teachers/" />
Works great!

MVC RequireHttps entire site

I have read the previous posts about using the RequireHttpsAttribute to secure individual controllers:
ASP.NET MVC RequireHttps in Production Only
but is there a way to apply this to the entire site? Due to my host (discountasp.net) I cannot use the "RequireSSL IIS" setting.
Register the RequireHttpsAttribute as a global filter.
In global.asax:
protected void Application_Start()
{
GlobalFilters.Filters.Add(new RequireHttpsAttribute());
//... other stuff
}
I ended up using IIS URL Rewrite 2.0 to force the site to switch to HTTPS. This code in web.config does the trick:
<system.webServer>
<!-- This uses URL Rewrite 2.0 to force the entire site into SSL mode -->
<rewrite xdt:Transform="Insert">
<rules>
<rule name="Force HTTPS" enabled="true">
<match url="(.*)" ignoreCase="false" />
<conditions>
<add input="{HTTPS}" pattern="off" />
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" appendQueryString="true" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
</system.webServer>
You could always add a check at the application level in your global.asax
protected void Application_BeginRequest(Object sender, EventArgs e)
{
if (!HttpContext.Current.Request.IsSecureConnection)
{
Response.Redirect("https://" + Request.ServerVariables["HTTP_HOST"]
+ HttpContext.Current.Request.RawUrl);
}
}
Just to bring this answer upto date for MVC 3 and above use the following in your Filterconfig.cs file within the App_start folder
filters.Add(new RequireHttpsAttribute());
Obviously you will need your servers IIS configured to use a valid SSL certificate, cheap certs can be purchased here: https://www.namecheap.com/ i think the last time i purchased one it was $9 per domain per year.
In your FilterConfig.cs apply this:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
// only if Debug is not enabled, do not require https for local development
if (!HttpContext.Current.IsDebuggingEnabled)
filters.Add(new RequireHttpsAttribute());
//... any other filters
}
That should force your app to use https on every page.
This isn't using RequireHttps but I think it's a better solution because it catches the redirect sooner in the MVC Lifecycle.
public class RedirectModule : IHttpModule
{
private HttpApplication _context;
public void Init(HttpApplication context)
{
_context = context;
_context.PostResolveRequestCache += HttpRedirect;
}
public void HttpRedirect(Object src, EventArgs args)
{
if (_context.Request.Url.Scheme == Uri.UriSchemeHttp)
{
//Redirect to https
var scheme = Uri.UriSchemeHttps + "://";
var authority = _context.Request.Url.Authority;
var url = _context.Request.RawUrl;
var redirectTo = scheme + authority + url;
_context.Response.PermanentRedirect(redirectTo);
}
}
public void Dispose() { }
}
The idea came from this article.
You can register the module in your Web.config or inside the Global.asax. I'll show you in the web.cofig.
<system.webServer>
<modules>
<add name="ConfigModuleName" type="Your.Namespace.RedirectModule"/>
</modules>
</system.webServer>
MVC 6 (ASP.NET Core 1.0) works slightly different in it's way of registering filters:
Startup.cs - AddMvc with filter for RequireHttpsAttribute:
public void ConfigureServices(IServiceCollection services)
{
// TODO: Register other services
services.AddMvc(options =>
{
options.Filters.Add(typeof(RequireHttpsAttribute));
});
}
Design decisions explained:
Use filter in Startup.cs for global setup (since we want this to apply everywhere). Startup should be responsible for registering and setting up all global rules. If your company employ a new developer, she would expect to find global setup in Startup.cs.
Use RequireHttpsAttribute logic since it's proven (by Microsoft). Never use "magical" strings like "http://" and "https://" when it can be avoided by reusing a Microsoft component created to provide the same logic.
If you are running your MVC website in localhost without SSL:
http://localhost:1337/ (no SSL)
https://localhost:1337/ (SSL)
Consider looking at how to run without SSL in localhost while still requiring https it in production.
Note:
As an alternative, we could make a "class BaseController : Controller" and make all our controllers inherit from "BaseController" (instead of Controller). Then we only have to set the attribute 1 global place (and don't need to register filter in Startup.cs).
Some people prefer the attribute style.
Example of usage:
[RequireHttpsAttribute]
public class BaseController : Controller
{
// Maybe you have other shared controller logic..
}
public class HomeController : BaseController
{
// Add endpoints (GET / POST) for Home controller
}
In Global.asax.cs, use "RegisterGlobalFilters" to register global attributes.
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new RequireHttpsAttribute());
//e.g. filters.Add(new HandleErrorAttribute());
//e.g. filters.Add(new System.Web.Mvc.AuthorizeAttribute());
}
You could use a base class for all of your controllers, and decorate that with the require ssl attribute.

Resources