wake-up-neo.net

X-Frame-Optionen Zulassen mehrerer Domänen

Ich habe eine asp.net 4.0 IIS7.5-Site, die ich mit der Option x-frame header sichern muss

Ich muss auch meine Seiten von meiner Domain sowie von meiner Facebook-App aus umbenennen lassen.

Momentan habe ich meine Site mit einer Site mit folgendem Inhalt konfiguriert:

Response.Headers.Add("X-Frame-Options", "ALLOW-FROM SAMEDOMAIN, www.facebook.com/MyFBSite")

Wenn ich meine Facebook-Seite mit Chrome oder FireFox angesehen habe, werden die Seiten meiner Websites (die mit meiner Facebook-Seite umrahmt werden) in Ordnung angezeigt, aber unter IE9 wird der Fehler angezeigt 

"Diese Seite kann nicht angezeigt werden ..." (wegen X-Frame_Options-Einschränkung).

Wie kann ich festlegen, dass X-Frame-Options: ALLOW-FROM mehr als eine Domäne unterstützt?

X-FRAME-OPTION als neues Feature erscheint grundsätzlich fehlerhaft, wenn nur eine einzige Domäne definiert werden kann.

65
user1340663

X-Frame-Options ist veraltet. Von MDN :

Diese Funktion wurde aus den Webstandards entfernt. Obwohl einige Browser es möglicherweise noch unterstützen, wird es gerade gelöscht. Verwenden Sie es nicht in alten oder neuen Projekten. Seiten oder Web-Apps, die sie verwenden, können jederzeit beschädigt werden. </ S>

Die moderne Alternative ist der Header " Content-Security-Policy ", der zusammen mit vielen anderen Richtlinien eine Whitelist aufführt, welche URLs Ihre Seite in einem Frame hosten dürfen, indem Sie die Direktive frame-ancestors verwenden.
frame-ancestors unterstützt mehrere Domänen und sogar Platzhalterzeichen. Beispiel:

Content-Security-Policy: frame-ancestors 'self' example.com *.example.net ;

Leider unterstützt Internet Explorer die Content-Security-Policy nicht vollständig .

AKTUALISIEREN: MDN hat ihren Verfallskommentar entfernt. Hier ist ein ähnlicher Kommentar aus W3Cs Richtlinien zur Inhaltssicherheit

Die frame-ancestors-Direktive obsoletes verlegt den X-Frame-Options-Header. Wenn eine Ressource über beide Richtlinien verfügt, sollte die frame-ancestors-Richtlinie durchgesetzt werden und die X-Frame-Options-Richtlinie sollte ignoriert werden.

70
Kobi

Von RFC 7034 :

Platzhalter oder Listen zum Deklarieren mehrerer Domänen in einer ALLOW-FROM-Anweisung sind nicht zulässig

So,

Wie kann ich die X-Frame-Optionen: ALLOW-FROM so einstellen, dass mehr als eine Domäne unterstützt wird?

Du kannst nicht Als Problemumgehung können Sie verschiedene URLs für verschiedene Partner verwenden. Für jede URL können Sie ihren eigenen X-Frame-Options-Wert verwenden. Zum Beispiel:

partner   iframe URL       ALLOW-FROM
---------------------------------------
Facebook  fb.yoursite.com  facebook.com
VK.COM    vk.yoursite.com  vk.com

Für yousite.com können Sie einfach X-Frame-Options: deny verwenden.

BTW, vorerst Chrome (und alle Browser auf Webkit-Basis) unterstütztALLOW-FROM-Anweisungen überhaupt nicht.

29
vbo

Wie wäre es mit einem Ansatz, der nicht nur mehrere Domänen erlaubt, sondern auch dynamische Domänen.

Der Anwendungsfall betrifft hier einen Sharepoint-App-Teil, der unsere Site über einen iframe in Sharepoint lädt. Das Problem ist, dass Sharepoint dynamische Subdomains wie https://yoursite.sharepoint.com hat. Für den IE müssen wir also ALLOW-FROM https: //.sharepoint.com angeben

Ein heikles Geschäft, aber wir können es mit zwei Fakten erledigen:

  1. Wenn ein iframe geladen wird, werden nur die X-Frame-Optionen in der ersten Anforderung überprüft. Sobald der iframe geladen ist, können Sie innerhalb des iframe navigieren und der Header wird bei nachfolgenden Anforderungen nicht geprüft.

  2. Wenn ein iframe geladen wird, ist der HTTP-Verweis auch die übergeordnete iframe-URL.

Sie können diese beiden Fakten auf der Serverseite nutzen. In Ruby verwende ich den folgenden Code:

  uri = URI.parse(request.referer)
  if uri.Host.match(/\.sharepoint\.com$/)
    url = "https://#{uri.Host}"
    response.headers['X-Frame-Options'] = "ALLOW-FROM #{url}"
  end

Hier können wir dynamisch Domänen zulassen, die auf der übergeordneten Domäne basieren. In diesem Fall stellen wir sicher, dass der Host auf sharepoint.com endet, um unsere Website vor Clickjacking zu schützen.

Ich würde mich sehr über Feedback zu diesem Ansatz freuen.

7
Peter P.

Nekromanzierung. 
.__ Die Antworten sind unvollständig. 

Erstens können Sie, wie bereits gesagt, nicht mehrere zulässige Hosts hinzufügen. Dies wird nicht unterstützt. 
Zweitens müssen Sie diesen Wert dynamisch aus dem HTTP-Referrer extrahieren. Dies bedeutet, dass Sie den Wert nicht zu Web.config hinzufügen können, da er nicht immer denselben Wert hat. 

Die Browsererkennung muss erforderlich sein, um das Hinzufügen von Zulassungen von Chrome zu verhindern (dies verursacht einen Fehler in der Debug-Konsole, wodurch die Konsole schnell gefüllt oder die Anwendung langsam wird). Das bedeutet auch, dass Sie die ASP.NET-Browsererkennung ändern müssen, da Edge falsch als Chrome identifiziert wird. 

Dies kann in ASP.NET durch Schreiben eines HTTP-Moduls erfolgen, das bei jeder Anforderung ausgeführt wird und bei jeder Antwort einen HTTP-Header anhängt, abhängig vom Referrer der Anforderung. Für Chrome muss Content-Security-Policy hinzugefügt werden. 

// https://stackoverflow.com/questions/31870789/check-whether-browser-is-chrome-or-Edge
public class BrowserInfo
{

    public System.Web.HttpBrowserCapabilities Browser { get; set; }
    public string Name { get; set; }
    public string Version { get; set; }
    public string Platform { get; set; }
    public bool IsMobileDevice { get; set; }
    public string MobileBrand { get; set; }
    public string MobileModel { get; set; }


    public BrowserInfo(System.Web.HttpRequest request)
    {
        if (request.Browser != null)
        {
            if (request.UserAgent.Contains("Edge")
                && request.Browser.Browser != "Edge")
            {
                this.Name = "Edge";
            }
            else
            {
                this.Name = request.Browser.Browser;
                this.Version = request.Browser.MajorVersion.ToString();
            }
            this.Browser = request.Browser;
            this.Platform = request.Browser.Platform;
            this.IsMobileDevice = request.Browser.IsMobileDevice;
            if (IsMobileDevice)
            {
                this.Name = request.Browser.Browser;
            }
        }
    }


}


void context_EndRequest(object sender, System.EventArgs e)
{
    if (System.Web.HttpContext.Current != null && System.Web.HttpContext.Current.Response != null)
    {
        System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;

        try
        {
            // response.Headers["P3P"] = "CP=\\\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\\\"":
            // response.Headers.Set("P3P", "CP=\\\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\\\"");
            // response.AddHeader("P3P", "CP=\\\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\\\"");
            response.AppendHeader("P3P", "CP=\\\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\\\"");

            // response.AppendHeader("X-Frame-Options", "DENY");
            // response.AppendHeader("X-Frame-Options", "SAMEORIGIN");
            // response.AppendHeader("X-Frame-Options", "AllowAll");

            if (System.Web.HttpContext.Current.Request.UrlReferrer != null)
            {
                // "X-Frame-Options": "ALLOW-FROM " Not recognized in Chrome 
                string Host = System.Web.HttpContext.Current.Request.UrlReferrer.Scheme + System.Uri.SchemeDelimiter
                            + System.Web.HttpContext.Current.Request.UrlReferrer.Authority
                ;

                string selfAuth = System.Web.HttpContext.Current.Request.Url.Authority;
                string refAuth = System.Web.HttpContext.Current.Request.UrlReferrer.Authority;

                // SQL.Log(System.Web.HttpContext.Current.Request.RawUrl, System.Web.HttpContext.Current.Request.UrlReferrer.OriginalString, refAuth);

                if (IsHostAllowed(refAuth))
                {
                    BrowserInfo bi = new BrowserInfo(System.Web.HttpContext.Current.Request);

                    // bi.Name = Firefox
                    // bi.Name = InternetExplorer
                    // bi.Name = Chrome

                    // Chrome wants entire path... 
                    if (!System.StringComparer.OrdinalIgnoreCase.Equals(bi.Name, "Chrome"))
                        response.AppendHeader("X-Frame-Options", "ALLOW-FROM " + Host);    

                    // unsafe-eval: invalid JSON https://github.com/keen/keen-js/issues/394
                    // unsafe-inline: styles
                    // data: url(data:image/png:...)

                    // https://www.owasp.org/index.php/Clickjacking_Defense_Cheat_Sheet
                    // https://www.ietf.org/rfc/rfc7034.txt
                    // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
                    // https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP

                    // https://stackoverflow.com/questions/10205192/x-frame-options-allow-from-multiple-domains
                    // https://content-security-policy.com/
                    // http://rehansaeed.com/content-security-policy-for-asp-net-mvc/

                    // This is for Chrome:
                    // response.AppendHeader("Content-Security-Policy", "default-src 'self' 'unsafe-inline' 'unsafe-eval' data: *.msecnd.net vortex.data.Microsoft.com " + selfAuth + " " + refAuth);


                    System.Collections.Generic.List<string> ls = new System.Collections.Generic.List<string>();
                    ls.Add("default-src");
                    ls.Add("'self'");
                    ls.Add("'unsafe-inline'");
                    ls.Add("'unsafe-eval'");
                    ls.Add("data:");

                    // http://az416426.vo.msecnd.net/scripts/a/ai.0.js

                    // ls.Add("*.msecnd.net");
                    // ls.Add("vortex.data.Microsoft.com");

                    ls.Add(selfAuth);
                    ls.Add(refAuth);

                    string contentSecurityPolicy = string.Join(" ", ls.ToArray());
                    response.AppendHeader("Content-Security-Policy", contentSecurityPolicy);
                }
                else
                {
                    response.AppendHeader("X-Frame-Options", "SAMEORIGIN");
                }

            }
            else
                response.AppendHeader("X-Frame-Options", "SAMEORIGIN");
        }
        catch (System.Exception ex)
        {
            // WTF ? 
            System.Console.WriteLine(ex.Message); // Suppress warning
        }

    } // End if (System.Web.HttpContext.Current != null && System.Web.HttpContext.Current.Response != null)

} // End Using context_EndRequest


private static string[] s_allowedHosts = new string[] 
{
     "localhost:49533"
    ,"localhost:52257"
    ,"vmswisslife"
    ,"vmraiffeisen"
    ,"vmpost"
    ,"example.com"
};


public static bool IsHostAllowed(string Host)
{
    return Contains(s_allowedHosts, Host);
} // End Function IsHostAllowed 


public static bool Contains(string[] allowed, string current)
{
    for (int i = 0; i < allowed.Length; ++i)
    {
        if (System.StringComparer.OrdinalIgnoreCase.Equals(allowed[i], current))
            return true;
    } // Next i 

    return false;
} // End Function Contains 

Sie müssen die Funktion context_EndRequest in der Init-Funktion des HTTP-Moduls registrieren. 

public class RequestLanguageChanger : System.Web.IHttpModule
{


    void System.Web.IHttpModule.Dispose()
    {
        // throw new NotImplementedException();
    }


    void System.Web.IHttpModule.Init(System.Web.HttpApplication context)
    {
        // https://stackoverflow.com/questions/441421/httpmodule-event-execution-order
        context.EndRequest += new System.EventHandler(context_EndRequest);
    }

    // context_EndRequest Code from above comes here


}

Als Nächstes müssen Sie das Modul zu Ihrer Anwendung hinzufügen. Sie können dies programmgesteuert in Global.asax durchführen, indem Sie die Init-Funktion der HttpApplication wie folgt überschreiben:

namespace ChangeRequestLanguage
{


    public class Global : System.Web.HttpApplication
    {

        System.Web.IHttpModule mod = new libRequestLanguageChanger.RequestLanguageChanger();

        public override void Init()
        {
            mod.Init(this);
            base.Init();
        }



        protected void Application_Start(object sender, System.EventArgs e)
        {

        }

        protected void Session_Start(object sender, System.EventArgs e)
        {

        }

        protected void Application_BeginRequest(object sender, System.EventArgs e)
        {

        }

        protected void Application_AuthenticateRequest(object sender, System.EventArgs e)
        {

        }

        protected void Application_Error(object sender, System.EventArgs e)
        {

        }

        protected void Session_End(object sender, System.EventArgs e)
        {

        }

        protected void Application_End(object sender, System.EventArgs e)
        {

        }


    }


}

oder Sie können Web.config Einträge hinzufügen, wenn Sie nicht den Quellcode der Anwendung besitzen:

      <httpModules>
        <add name="RequestLanguageChanger" type= "libRequestLanguageChanger.RequestLanguageChanger, libRequestLanguageChanger" />
      </httpModules>
    </system.web>

  <system.webServer>
    <validation validateIntegratedModeConfiguration="false"/>

    <modules runAllManagedModulesForAllRequests="true">
      <add name="RequestLanguageChanger" type="libRequestLanguageChanger.RequestLanguageChanger, libRequestLanguageChanger" />
    </modules>
  </system.webServer>
</configuration>

Der Eintrag in system.webServer ist für IIS7 +, der andere in system.web ist für IIS 6. 
Beachten Sie, dass Sie runAllManagedModulesForAllRequests auf true setzen müssen, damit es ordnungsgemäß funktioniert. 

Die Zeichenfolge in type hat das Format "Namespace.Class, Assembly". Wenn Sie Ihre Assembly in VB.NET anstelle von C # schreiben, erstellt VB einen Standard-Namespace für jedes Projekt, sodass Ihre Zeichenfolge so aussieht

"[DefaultNameSpace.Namespace].Class, Assembly"

Wenn Sie dieses Problem vermeiden möchten, schreiben Sie die DLL in C #.

5
Stefan Steiger

Gemäß den MDN-Spezifikationen wird X-Frame-Options: ALLOW-FROM in Chrome nicht unterstützt und die Unterstützung ist in Edge und Opera nicht bekannt.

Content-Security-Policy: frame-ancestors überschreibt X-Frame-Options (gemäß dieser W3-Spezifikation ), aber frame-ancestors ist nur eingeschränkt kompatibel. Gemäß diesen MDN Specs wird es in IE oder Edge nicht unterstützt.

0
Andrew

Ich musste X-Frame-Optionen für IE und Content-Security-Policy für andere Browser hinzufügen .. __ So tat ich etwas wie folgt.

if allowed_domains.present?
  request_Host = URI.parse(request.referer)
  _domain = allowed_domains.split(" ").include?(request_Host.host) ? "#{request_Host.scheme}://#{request_Host.host}" : app_Host
  response.headers['Content-Security-Policy'] = "frame-ancestors #{_domain}"
  response.headers['X-Frame-Options'] = "ALLOW-FROM #{_domain}"
else
  response.headers.except! 'X-Frame-Options'
end
0
jbmyid

Nicht genau das Gleiche, könnte aber in einigen Fällen funktionieren: Es gibt eine andere Option, ALLOWALL, die die Einschränkung effektiv aufhebt, was für Test-/Pre-Production-Umgebungen eine schöne Sache sein kann

0
Willyfrog