X-Frame-Options Permettent-à Partir de multiples domaines

j'ai un asp.net 4,0 IIS7.5 site que j'ai besoin de sécuriser en utilisant les en-têtes X-frame option

je dois aussi permettre à mes pages de site d'être iframed à partir de mon même domaine ainsi que de mon application facebook.

actuellement, j'ai mon site configuré avec un site intitulé de:

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

quand j'ai vu ma page Facebook avec Chrome ou FireFox mes pages de sites (étant iframed avec ma page facebook) sont affichés ok, mais sous IE9, Je reçois le message d'erreur

"cette page ne peut pas être affichée..." (en raison de la restriction X-Frame_Options ).

comment définir le X-Frame-Options: ALLOW-FROM pour prendre en charge plus d'un domaine?

X-FRAME-OPTION être une nouvelle caractéristique semble fondamentalement défectueux Si seulement un seul domaine peut être défini.

61
demandé sur Raptor 2012-04-18 11:53:47

9 réponses

X-Frame-Options est déprécié. De MDN :

cette fonctionnalité a été supprimée des normes Web. Bien que certains navigateurs puissent encore le supporter, il est en train d'être abandonné. Ne l'utilisez pas dans des projets anciens ou nouveaux. Les Pages ou les applications Web qui l'utilisent peuvent se casser à tout moment.

l'alternative moderne est le Content-Security-Policy " en-tête, qui avec beaucoup d'autres politiques peut énumérer en blanc ce que les URLs sont autorisés à héberger votre page dans un cadre, en utilisant la directive frame-ancestors ".

frame-ancestors prend en charge plusieurs domaines et même des caractères génériques, par exemple:

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

malheureusement, pour l'instant, Internet Explorer ne supporte pas entièrement Content-Security-Policy .

UPDATE: MDN a supprimé leur commentaire de dépréciation. Voici un commentaire similaire de niveau de la Politique de sécurité du contenu du W3C

Le frame-ancestors directive obsoletes le X-Frame-Options en-tête. Si une ressource a les deux politiques, la Politique frame-ancestors devrait être appliquée et la Politique X-Frame-Options devrait être ignorée.

64
répondu Kobi 2017-01-12 16:58:36

From RFC 7034 :

les caractères génériques ou les listes pour déclarer plusieurs domaines dans une seule déclaration ALLOW-FROM ne sont pas autorisés

,

comment définir X-Frame-Options: ALLOW-FROM pour prendre en charge plus d'un domaine?

vous ne pouvez pas. Comme solution de contournement, vous pouvez utiliser des URLs différentes pour différents partenaires. Pour chaque URL vous pouvez utiliser sa propre valeur X-Frame-Options . Par exemple:

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

Pour yousite.com vous pouvez utiliser X-Frame-Options: deny .

BTW , pour le moment Chrome (et tous les navigateurs webkit) ne supporte pas ALLOW-FROM déclarations à tous.

26
répondu vbo 2017-03-22 04:44:37

Que Diriez-vous d'une approche qui non seulement permet des domaines multiples, mais permet des domaines dynamiques.

le cas d'utilisation ici est avec une partie SharePoint app qui charge notre site à L'intérieur de Sharepoint via une iframe. Le problème est que sharepoint a des sous-domaines dynamiques tels que https://yoursite.sharepoint.com . Donc pour IE, nous avons besoin de spécifier ALLOW-FROM https://.sharepoint.com

affaire délicate, mais nous pouvons y arriver en sachant deux faits:

  1. Lorsqu'une iframe est chargée, elle ne valide les Options X-Frame que sur la première demande. Une fois l'iframe chargée, vous pouvez naviguer dans l'iframe et l'en-tête n'est pas coché sur les requêtes suivantes.

  2. aussi, lorsqu'une iframe est chargée, le référent HTTP est l'url parent iframe.

vous pouvez utiliser ces deux données côté serveur. Dans ruby, j'utilise le code suivant:

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

ici, nous pouvons autoriser dynamiquement les domaines basés sur le domaine parent. Dans ce cas, nous nous assurons que l'hôte sharepoint.com garder notre site à l'abri de clickjacking.

j'aimerais entendre des commentaires sur cette approche.

6
répondu Peter P. 2015-12-14 18:35:27

Nécromancie.

Les réponses sont incomplètes.

tout d'abord, comme déjà dit, vous ne pouvez pas ajouter plusieurs allow-from hosts, Cela n'est pas supporté.

Deuxièmement, vous devez extraire dynamiquement cette valeur à partir du referrer HTTP, ce qui signifie que vous ne pouvez pas ajouter la valeur à Web.config, car il n'est pas toujours la même valeur.

il sera nécessaire de faire la détection de navigateur pour éviter d'ajouter autoriser-à partir du moment où le navigateur est Chrome (il produit une erreur sur le débogueur - console, qui peut rapidement remplir la console, ou de rendre l'application lente). Cela signifie également que vous devez modifier la ASP.NET détection de navigateur, car il identifie à tort Edge comme Chrome.

cela peut être fait en ASP.NET en écrivant un module HTTP qui s'exécute sur chaque requête, qui ajoute un en-tête http pour chaque réponse, en fonction du referrer de la requête. Pour Chrome, il faut ajouter Contenu De La Politique De Sécurité.

// /q/check-whether-browser-is-chrome-or-edge-24805/"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

                    // /q/x-frame-options-allow-from-multiple-domains-16660/"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 

vous devez enregistrer la fonction context_EndRequest dans la fonction init du module HTTP.

public class RequestLanguageChanger : System.Web.IHttpModule
{


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


    void System.Web.IHttpModule.Init(System.Web.HttpApplication context)
    {
        // /q/httpmodule-event-execution-order-6853/"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>

L'entrée dans le système.webServer est pour IIS7+, l'autre dans le système.le web est pour IIS 6.

Notez que vous devez définir runAllManagedModulesForAllRequests à true, pour que cela fonctionne correctement.

la chaîne de caractères est au format "Namespace.Class, Assembly" . Notez que si vous écrivez votre assemblée VB.NET au lieu de C#, VB crée un Namespace par défaut pour chaque projet, donc votre chaîne ressemblera à

"[DefaultNameSpace.Namespace].Class, Assembly"

si vous voulez éviter ce problème, écrivez la DLL en C#.

4
répondu Stefan Steiger 2017-04-10 12:42:26

pas exactement le même, mais pourrait fonctionner dans certains cas: il ya une autre option ALLOWALL qui va effectivement supprimer la restriction, ce qui pourrait être une bonne chose pour les environnements de test / pré-production

0
répondu Willyfrog 2017-01-04 09:59:50

selon les spécifications MDN , X-Frame-Options: ALLOW-FROM N'est pas supporté dans Chrome et le support est inconnu dans Edge et Opera.

Content-Security-Policy: frame-ancestors remplace X-Frame-Options (comme pour cette W3 spec ), mais frame-ancestors a limité la compatibilité. Selon ces Spécifications MDN , il n'est pas pris en charge dans IE ou Edge.

0
répondu Andrew 2017-08-24 23:40:45

j'ai dû ajouter X-Frame-Options pour IE et Content-Security-politique pour les autres navigateurs. Donc j'ai fait quelque chose comme suivre.

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
répondu jbmyid 2018-10-01 10:39:46

une solution possible serait d'utiliser un script "frame-breaker" comme décrit ici

vous avez juste besoin de modifier la déclaration" si " pour vérifier vos domaines autorisés.

   if (self === top) {
       var antiClickjack = document.getElementById("antiClickjack");
       antiClickjack.parentNode.removeChild(antiClickjack);
   } else {
       //your domain check goes here
       if(top.location.host != "allowed.domain1.com" && top.location.host == "allowed.domain2.com")
         top.location = self.location;
   }

cette solution serait sûre, je pense. parce que javascript n'est pas activé, vous n'aurez aucun problème de sécurité avec un site Web malveillant cadrant votre page.

-2
répondu SinaX 2014-02-20 06:54:43

Oui. Cette méthode permettait plusieurs domaines.

VB.NET

response.headers.add("X-Frame-Options", "ALLOW-FROM " & request.urlreferer.tostring())
-3
répondu user4778040 2015-04-11 20:34:10