Allow frame from different domain with MVC5 - c#

I am trying to load google maps into an iframe using MVC5 but I am getting blocked with the error
Refused to display 'https://www.google.com/maps?cid=XXXXX' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'.
So after much searching, I have tried the following:
Adding AntiForgeryConfig.SuppressXFrameOptionsHeader = true; to the Application_Start in global.ascx
Creating an attribute (have tried this with and without the setting in global.ascx):
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext != null)
{
filterContext.HttpContext.Response.Headers["X-Frame-Options"] = "ALLOW-FROM https://www.google.com";
base.OnActionExecuted(filterContext);
}
}
trying the attribute OnResultExecuted(ResultExecutedContext filterContext) instead of OnActionExecuted
remove it in the web.config:
<httpProtocol>
<customHeaders>
<remove name="X-Frame-Options" />
</customHeaders>
</httpProtocol>
Is there something I'm missing? how do I get rid of this http header (or at least change it to allow maps)?
Update
I have just checked the headers being sent and they are correct in that they either say
X-Frame-Options: ALLOW-FROM https://www.google.com
Or aren't there at all if I remove the attribute but keep the global.ascx update
Yet when I run the page and see these headers, it is still giving me the SAMEORIGIN error.

As it turns out I have been completely stupid and misunderstood how x-frame-options work. It is to stop your site page being shown on another site through an iframe.
So the x-frame-options http header that I was getting for SAMEORIGIN was actually coming from google. I thought that as the url was returned from their places api I could just use it, but apparently you can only link to it.
Creating a new map api key and enabling the maps embed api, I was able to use the place_id instead and call the following url into the iframe:
https://www.google.com/maps/embed/v1/place?key=YOUR_API_KEY&q=place_id:PLACE_ID
And this would show without me getting the header (or doing anything extra to my headers).
I'll leave this here just in case anyone is as daft as I am

Related

ASP NET MVC 5: Session ends suddenly

right now i work on an already existing ASP.NET MVC Project, which has the problem that the session sometimes suddenly ends and the user gets redirected to the login page. Today i noticed something, the login page is always loaded in the background:
I don't have much Experience with ASP.NET MVC so i wanted to ask, what could be the reason this always gets loaded. The code is not documented so i could not find a reason for it. I use IIS 8 for deploying.
Update:
I have now tracked with Fiddler and i saw something, at first i thought that the session cookies gets dropped or replaced turns out it doesnt. Its there even on the login page.
Update 2:
I have now validated that the cookie is still in place and the login info is still stored after this forced logout. Is there a common issue in ASP NET which can cause that a session is still saved but not recognized anymore? Turns out it could be this ActionFilter:
namespace backend.Models.ActionFilter
{
public class HasUserId : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Session.GetInt32("UserId") == null)
{
System.Diagnostics.Debug.WriteLine("Session is not there anymore");
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { action = "Login", controller = "Account" }));
}
}
}
}
Update 3:
I think I have found the problem, the session state gets stored 'In-process' i have now changed it to 'State Service'. I hope this will solve my problem. Is it normal that the login still works even when the 'ASP NET State Service' is halted? This is my config:
<system.web>
<sessionState
mode="StateServer"
stateConnectionString="tcpip=127.0.0.1:42424"
stateNetworkTimeout="20"
timeout="240">
</sessionState>
</system.web>
This problem occurs if the login page is as the start page. You can change this by modifying the filter file and specifically in routes.MapRoute.
For more information you can view here
If you want to change redirection via IIS, you can not do that.
The answer for my problem was to change the handling of the session state from 'In-process' to 'Out-of-process'.

How to allow CORS for ASP.NET WebForms endpoint?

I am trying to add some [WebMethod] annotated endpoint functions to a Webforms style web app (.aspx and .asmx).
I'd like to annotate those endpoints with [EnableCors] and thereby get all the good ajax-preflight functionality.
VS2013 accepts the annotation, but still the endpoints don't play nice with CORS. (They work fine when used same-origin but not cross-origin).
I can't even get them to function cross-origin with the down and dirty
HttpContext.Current.Response.AppendHeader("Access-Control-Allow-Origin", "*");
approach -- my browsers reject the responses, and the cross-origin response headers don't appear.
How can I get CORS functionality in these [WebMethod] endpoints?
I recommend double-checking you have performed all steps on this page: CORS on ASP.NET
In addition to:
Response.AppendHeader("Access-Control-Allow-Origin", "*");
Also try:
Response.AppendHeader("Access-Control-Allow-Methods","*");
Try adding directly in web config:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Methods" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
</customHeaders>
</httpProtocol>
</system.webServer>
Failing that, you need to ensure you have control over both domains.
FYI, enable CORS in classic webform. In Global.asax
void Application_Start(object sender, EventArgs e)
{
GlobalConfiguration.Configuration.EnableCors();
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional }
);
If you need the preflight request, e.g. so you can send authenticated requests, you are not able to set Access-Control-Allow-Origin: *. It must be a specific Origin domain.
Also you must set the Access-Control-Allow-Methods and Access-Control-Allow-Headers response headers, if you are using anything besides the defaults.
(Note these constraints are just how CORS itself works - this is how it is defined.)
So, it's not enough to just throw on the [EnableCors] attribute, you have to set values to the parameters:
[EnableCors(origins: "https://www.olliejones.com", headers: "X-Custom-Header", methods: "PUT", SupportsCredentials = true)]
Or if you want to do things manually and explicitly:
HttpContext.Current.Response.AppendHeader("Access-Control-Allow-Origin", "https://www.olliejones.com");
HttpContext.Current.Response.AppendHeader("Access-Control-Allow-Headers", "X-Custom-Header");
HttpContext.Current.Response.AppendHeader("Access-Control-Allow-Methods", "PUT");
HttpContext.Current.Response.AppendHeader("Access-Control-Allow-Credentials", "true");
One last thing - you do have to call .EnableCors() on initiation. In e.g. MVC or WebAPI, you would call this on HttpConfiguration, when registering the config and such - however I have no idea how it works with WebForms.
If you use the AppendHeader method to send cache-specific headers and at the same time use the cache object model (Cache) to set cache policy, HTTP response headers that pertain to caching might be deleted when the cache object model is used. This behavior enables ASP.NET to maintain the most restrictive settings. For example, consider a page that includes user controls. If those controls have conflicting cache policies, the most restrictive cache policy will be used. If one user control sets the header "Cache-Control: Public" and another user control sets the more restrictive header "Cache-Control: Private" via calls to SetCacheability, then the "Cache-Control: Private" header will be sent with the response.
You can create a httpProtocol in web config for customHeaders.
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Methods" values="*" />
</customHeaders>
<httpProtocol>
I think your code looks good, but IIS does not send the header entity alone with response expectedly. Please check whether IIS is configured properly.
Configuring IIS6
Configuring IIS7
If CORS doesn't work for your particularity problem, maybe jsonp is another possible way.
For the web form, you can use
Response.AddHeader("Access-Control-Allow-Origin", "*");
instead of
Response.AppendHeader("Access-Control-Allow-Origin", "*");
The first one works for old version of ASP.Net Web Form.
You can do like this in MVC
[EnableCors(origins: "*", headers: "*", methods: "*")]
public ActionResult test()
{
Response.AppendHeader("Access-Control-Allow-Origin", "*");
return View();
}

Removing X-Frame-Options being added automatically only in Login page

I am developing an ASP.NET MVC application which needs to be loaded inside an iframe in another website. But the login page just won't appear inside the iframe because an Header is being sent in the response X-Frame-Options which is set to SAMEORIGIN. Browser is not displaying the page in iframe because of this. I already Googled and tried multiple things but nothing worked.
I am using ASP.NET forms authentication. May be in this case IIS adds this header in login page for added security. But I need to get rid of this in my use case.
I tried adding a custom header
<httpProtocol>
<customHeaders>
<add name="X-Frame-Options" value="ALLOW" />
</customHeaders>
</httpProtocol>
But the SAMEORGIN is still being added in the header with comma.
I also tried adding Header value from C# using Response.Headers["X-Frame-Options"] = "ALLOW". It cause two headers with the same name.
I also tried this in web.config
<customHeaders>
<remove name="X-Frame-Options" />
</customHeaders>
It also didn't worked.
MVC 5 automatically adds an X-Frame-Options Header, so go to your Global.asax file and add this to the Application_Start() method:
System.Web.Helpers.AntiForgeryConfig.SuppressXFrameOptionsHeader = true;
Please note that especially for a login page it is bad practice to remove this header, because it opens up your site for login credentials phishing attacks. So if this site of yours is publicly accessable I strongly recommend to keep this header.
Old question, but for other people searching for similar question, you can remove the X-Frame-Options in specific actions using the following solution:
First, add this code to method Application_Start in Global.asax.cs (as #Florian Haider said):
System.Web.Helpers.AntiForgeryConfig.SuppressXFrameOptionsHeader = true;
This will suppress the header in all actions. Add a new file named NoIframeAttribute.cs containing the following code:
using System.Web.Mvc;
namespace MyApplication
{
public class NoIframeAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.HttpContext.Response.Headers.Set("X-Frame-Options", "SAMEORIGIN");
}
}
}
Add the following line to RegisterGlobalFilters method in FilterConfig.cs:
filters.Add(new NoIframeAttribute());
Now, we have the header added to all actions again. But now we can remove it when needed. Just add the following line wherever needed:
Response.Headers.Remove("X-Frame-Options");

ASP.NET Web API CORS not working with AngularJS

I have an ASP.NET Web API running locally on some port and I have an angularjs app running on 8080. I want to access the api from the client.
I can successfully login and register my application because in my OAuthAuthorizationProvider explicitly sets the repsonse headers in the /Token endpoint.
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
That's good. However, my other API methods do not seem to work. In my WebApiCongig.Register, I enable CORS and I add the EnableCors Attribute to my controllers to allow all origins, all headers, and all methods. I can set a break point in my get method on the controller and it gets hit just fine. Here is what I found watching the Network tab in chrome.
2 requests are are sent to the same api method. One method type OPTIONS and one with method type GET. The OPTIONS request header includes these two lines
Access-Control-Request-Headers:accept, authorization
Access-Control-Request-Method:GET
And the response includes these lines
Access-Control-Allow-Headers:authorization
Access-Control-Allow-Origin:*
However, the GET method request looks quite different. It returns ok with a status code of 200, but it does not inlcude and access control headers in the request or response. And like I said, it hits the API just fine. I can even do a POST and save to the database, but the client complains about the response!!
I've looked at every single SO question and tried every combination of enabling cors. I'm using Microsoft.AspNet.Cors version 5.2.2. I'm' using AngularJS version 1.3.8. I'm also using the $resource service instead of $http which doesn't seem to make a difference either.
If I can provide more information, please let me know.
BTW, I can access the Web API using Fiddler and/or Postman by simply including the Bearer token.
You don't seem to be handling the preflight Options requests.
Web API needs to respond to the Options request in order to confirm that it is indeed configured to support CORS.
To handle this, all you need to do is send an empty response back. You can do this inside your actions, or you can do it globally like this:
protected void Application_BeginRequest()
{
if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
{
Response.Flush();
}
}
This extra check was added to ensure that old APIs that were designed to accept only GET and POST requests will not be exploited. Imagine sending a DELETE request to an API designed when this verb didn't exist. The outcome is unpredictable and the results might be dangerous.
Also I suggest enabling Cors by web.config instead of config.EnableCors(cors);
This can be done by adding some custom headers inside the <system.webServer> node.
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
Please note that the Methods are all individually specified, instead of using *. This is because there is a bug occurring when using *.
This ended up being a simple fix. Simple, but it still doesn't take away from the bruises on my forehead. It seems like the more simple, the more frustrating.
I created my own custom cors policy provider attribute.
public class CorsPolicyProvider : Attribute, ICorsPolicyProvider
{
private CorsPolicy _policy;
public CorsPolicyProvider()
{
// Create a CORS policy.
_policy = new CorsPolicy
{
AllowAnyMethod = true,
AllowAnyHeader = true,
AllowAnyOrigin = true
};
// Magic line right here
_policy.Origins.Add("*");
}
public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return Task.FromResult(_policy);
}
}
I played around with this for hours. Everything should work right?? I mean the EnableCors attribute should work too?? But it didn't. So I finally added the line above to explicitly add the origin to the policy. BAM!! It worked like magic. To use this just add the attribute to your api class or method you want to allow.
[Authorize]
[RoutePrefix("api/LicenseFiles")]
[CorsPolicyProvider]
//[EnableCors(origins: "*", headers: "*", methods: "*")] does not work!!!!! at least I couldn't get it to work
public class MyController : ApiController
{
in my case, after I changed the Identity option of my AppPool under IIS from ApplicationPoolIdentity to NetworkService, CORS stopped working in my app.

Server.Transfer causing Session exception

In my global I have the following code to handle when an error occurs
//[..] code goes here
Server.Transfer("~/Error.aspx?ErrorID=" + errorId);
It used to be a Response.Redirect which worked perfectly except that it changed the url (which is why I want to use Server.Transfer)
Unfortunately, now when it tries to load the Error page, it crashes on the Masterpage when it tries to refer to the Session
HttpException:
Session state can only be used when enableSessionState is set to true,
either in a configuration file or in the Page directive. Please also
make sure that System.Web.SessionStateModule or a custom session state
module is included in the \\
section in the application configuration.
I do have enableSessionState in both my config and my page.
I also found some links which suggest using Context.RewritePath - that just causes a blank page to load for me.
Using Response.Redirect works perfectly and as expected, so I assume Server.Transfer is the issue here. What is it?
EDIT Code:
protected void Application_Error(object sender, EventArgs e)
{
lock (_lockMe)
{
Exception ex = Server.GetLastError();
if (ex != null)
{
if (ex.InnerException != null)
ex = ex.InnerException;
ErrorLoggingManager.AddError(ex, new MembershipData(), ...); //etc
}
Server.ClearError();
//Some other database code for cleaning up some stuff when an error happens
}
try
{
if (Response != null)
{
//Get the last error logged
MyDataContext db = new MyDataContext();
int errorId = db.LoggedErrors.OrderByDescending(le => le.ErrorId).Select(le => le.ErrorId).FirstOrDefault();
Server.Transfer("~/Error.aspx?ErrorID=" + errorId);
}
}
catch (Exception)
{
}
}
As you have not posted much code. So without seeing the actual implementation you have done. I could suggest you below points.
Point 1. First of all, you need to check if SessionState is enabled for pages. You could set them globally in web.config file. Try the snippet given below in web.config
<configuration>
<system.web>
<pages enableSessionState="true" />
</system.web>
</configuration>
Point 2. And put your Redirection in Application_Error in Global.asax.
public void Application_Error(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
app.Server.Transfer("~/Error.aspx?ErrorID=" + errorId,true);
}
Point 3. Also check if your SessionStateis set properly in IIS too.
Details are on MSDN to enable sessionstate
Hope this helps..!!!
From what I understand, Server.Transfer sends the content of another page to the client rather than the requested content. If that is the case, then I am wondering if it does not have something to do with applying a master page to the error page? I had a similar error years ago with earlier technology and it turned out that the master page did not like what I was trying to do.
I hope this helps at least point to a solution.
Here's what the problem is:
If there is a page render exception (ex. "File Not Found") then Server.Transfer screws up the session. This has something to do with it being called during the page render.
As long as you are not appending headers before the error occurs, Response.Redirect will work just fine; if you are, however, using Response.AppendHeader then Response.Redirect will not work during a page render.
Try using HttpContext.Current.RewritePath instead. That should fix all these problems. For whatever reason, RewritePath() does not care that the page hasn't finished rendering.
why not just use customErrors in web.config to do the redirect?
<customErrors mode="Off" defaultRedirect="~/Common/Error.aspx">
<error statusCode="403" redirect="~/SM_AccessDenied.aspx" />
<error statusCode="404" redirect="~/Common/FileNotFound.aspx" />
</customErrors>
I had the same problem in a different context a while ago. I don't know if it is your case, but if you're using IIS7 on Windows 2008, in addition to setting enableSessionState=true in your web.config, you have to put your modules inside the <system.webServer> section, instead of <system.web>. Changing this little thing solved it for me.
Why don't you try like this:
The Server.Transfer method also has a second parameter—"preserveForm". If you set this to True, using a statement such as Server.Transfer("WebForm2.aspx", True), the existing query string and any form variables will still be available to the page you are transferring to.
So I think doing like this your session will not expire.
Server.Transfer("~/Error.aspx?ErrorID=" + errorId,True);
The error you are encountering is because you are using a query string parameter. Per the msdn docs
However, the path parameter must not contain a query string, or ASP returns an error.
http://msdn.microsoft.com/en-us/library/ms525800%28v=vs.90%29.aspx
Its about 3/4 of the way down the page just above Requirements.
Even though the docs here are mentioning asp. and not asp.net, keep in mind the session state is a feature of IIS and is handled before asp.net is ever called.
#user2110845 : I had faced similar problem few months ago. the problem was with having an underscore in the website name. We were deploying a website in IIS with two different host names(adding two entries through the 'Edit Bindings' option on the website). The host names provided were abc_ts, abc_is. When the underscore was removed then the session problem got resolved.
It seems there are certain characters not allowed in a website host name. Check if that is your problem.
I found the answer here : link (check 'update 2' in the article)
You don't mention what version of ASP.NET you are using, but there were some changes between 2.0 and 3.5 in how unhandled exceptions bubbled their way up through an ASP.NET web app and then IIS.
Among some other possibles, while you are clearing the error you are not setting Context.Response.TrySkipIisCustomErrors = true; While this particular flag could have nothing to do with your issue (and is only available for 3.5+), it also could help deal with what is potentially two error pages behind the scenes that are obscuring the real issue. Regardless, it'll save you a lot of grief (at least if you are running 3.5+) with other potential issues. Check out two posts I wrote several years back that may be helpful: while they don't cover session handling, they do cover the multiple song-and-dance routines I had to follow to get proper 500 and 404 handling in various versions of ASP.NET. It's possible you will run into something that will get you further ahead, if not all the way there.
http://www.andornot.com/blog/post/Errors-Sending-the-Right-Message-(Redux-Covering-ASPNET-3540).aspx
http://www.andornot.com/blog/post/Errors-Sending-the-Right-Message.aspx

Categories

Resources