2012-04-18 249 views
54

我有一個asp.net 4.0 IIS7.5網站,我需要使用x-幀頭選項X-框架 - 選項允許-來自多個域

我還需要使我的網站的網頁安全可以的iFrame從我的同一個域以及從我的Facebook應用程序。

目前,我已經配置了團長的網站我的網站:

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

當我看到我的Facebook頁面,Chrome或Firefox我的網站頁面(正的iframe有我的Facebook頁面)都顯示正常,但在IE9,我得到錯誤

「此頁面無法顯示......」(由於X-Frame_Options限制)。

如何將X-Frame-Options: ALLOW-FROM設置爲支持多個單個域?

X-FRAME-OPTION作爲一項新功能,如果只能定義一個域,似乎存在根本上的缺陷。

+2

這似乎是一個已知的限制: https://www.owasp.org/index.php/Clickjacking_Defense_Cheat_Sheet#Limitations – 2012-04-18 13:14:44

回答

23

RFC 7034

通配符或列表在一個聲明多個域,允許-from語句不允許

所以,

如何設置X-框架選項:允許FROM支持多個域名?

你不行。作爲解決方法,您可以爲不同的合作伙伴使用不同的URL。對於每個網址,您可以使用它自己的X-Frame-Options值。例如:

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

對於yousite.com你可以只使用X-Frame-Options: deny

BTW,現在Chrome(和所有基於webkit的瀏覽器)does not supportALLOW-FROM聲明。如上所述here

你只需要改變的「如果」語句來檢查您的允許域

+1

它看起來像webkit現在使用您提供的鏈接支持'ALLOW-FROM'。 – Jimi 2017-06-30 01:06:27

+0

@Jimi不,它不是 - 對有問題的鏈接的最後評論,說你需要使用CSP策略。該選項在Chrome中仍然無法使用。 – NickG 2017-12-20 13:17:12

-2

一個可能的解決方法是使用一個「框架斷路器」的劇本。

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; 
    } 

這個解決方法是安全的,我想。因爲在沒有啓用javascript的情況下,您將不會擔心惡意網站構成您的頁面。

+1

調用top.location時,由於相同的原始策略,這將不起作用。 – 2014-03-06 16:57:26

50

X-Frame-Options已棄用。 From MDN

此功能已從Web標準中刪除。儘管一些瀏覽器可能仍然支持它,但它正在被丟棄。不要在舊項目或新項目中使用它。使用它的頁面或Web應用程序可能會隨時中斷。

現代的替代方案是Content-Security-Policy頭,沿着許多其他政策能白名單允許哪些網址託管您的網頁在一個框架,使用frame-ancestors指令。
frame-ancestors支持多個域,甚至通配符,例如:

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

不幸的是,就目前而言,Internet Explorer does not fully support Content-Security-Policy

更新: MDN已刪除其棄用評論。下面是從W3C's Content Security Policy Level

frame-ancestors指令淘汰了X-Frame-Options頭一個類似的評論。如果某個資源同時擁有兩個策略,則應該執行frame-ancestors策略,並且應該忽略X-Frame-Options策略。

+12

MDN上的框架祖先被標記爲「實驗性API,不應用於生產代碼」。 + X框架選項不被棄用,但「非標準」,但「廣泛支持,並可與CSP結合使用」 – 2015-06-08 09:19:26

+1

@JonathanMuller - 「X-Frame-Options」的措詞改變了,並且不那麼嚴重現在。使用未定案的規範是很冒險的。謝謝! – Kobi 2015-06-08 10:26:09

+2

我無法再在MDN上找到已更正的警告。 Mozilla是否改變了他們的觀點? – thomaskonrad 2016-02-03 09:01:30

-3

是的。該方法允許多個域。

VB.NET

response.headers.add("X-Frame-Options", "ALLOW-FROM " & request.urlreferer.tostring()) 
+7

這似乎擊敗了X-Frame-Options的目的,因爲它允許任何網站進行構圖。 – 2015-06-19 08:35:42

+4

這個答案看起來像它可能是一個很好的解決方案,但它需要額外的邏輯,以便它只在request.urlreferer.tostring()是你希望允許的起源之一時才執行這個代碼。 – Zergleb 2015-10-09 19:28:58

+0

如果你這樣做,爲什麼你甚至使用X-Frame-Options Header ...只是忽略它 – vs4vijay 2016-12-26 07:46:18

5

怎麼樣的方法,它不僅允許多個域,但允許動態域。

這裏的用例是一個Sharepoint應用程序部分,它通過iframe將我們的網站加載到Sharepoint內部。問題是,共享點具有動態子域名,例如https://yoursite.sharepoint.com。因此,對於IE瀏覽器,我們需要指定allow-從https://.sharepoint.com

棘手的事,但我們可以把它做知道兩個事實:

  1. 當一個iframe負載,它只驗證第一個請求中的X-Frame-Options。加載iframe後,您可以在iframe中導航,並且不會在隨後的請求中檢查標題。

  2. 此外,加載iframe時,HTTP引用者是父級iframe url。

你可以利用這兩個事實服務器端。在紅寶石中,我使用下面的代碼:

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

在這裏,我們可以動態地允許基於父域的域。在這種情況下,我們確保主機在sharepoint.com結束,以確保我們的網站免受點擊劫持。

我很想聽聽有關這種方法的反饋。

+1

小心:如果主機是「fakesharepoint.com」,這會中斷。正則表達式應該是:'/ \ sharepoint \ .com $ /' – nitsas 2015-12-11 13:48:07

+0

感謝@nitsas我更新以上 – 2015-12-14 18:35:41

+0

這對Chrome來說不起作用,因爲它不支持ALLOW-FROM ... – 2017-04-10 12:09:03

0

不完全一樣,但可以爲某些情況下工作:還有另一種選擇ALLOWALL這將有效地去除限制,這可能是測試/預生產環境

4

Necromancing一件很好的事。
提供的答案不完整。

首先,如前所述,您不能添加多個允許來自主機,這是不受支持的。
其次,您需要從HTTP引用來動態提取該值,這意味着您無法將值添加到Web.config,因爲它不總是相同的值。

當瀏覽器爲Chrome時(它在調試控制檯上產生錯誤,可能會快速填充控制檯或使應用程序變慢),需要執行瀏覽器檢測以避免添加允許。這也意味着您需要修改ASP.NET瀏覽器檢測,因爲它錯誤地將Edge標識爲Chrome。

這可以通過編寫一個在每個請求上運行的HTTP模塊來完成,該模塊爲每個響應添加一個http頭,具體取決於請求的引用者。對於Chrome,它需要添加內容安全策略。

// 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 

您需要在HTTP模塊Init函數中註冊context_EndRequest函數。

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 


} 

接下來,您需要將模塊添加到您的應用程序中。

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) 
     { 

     } 


    } 


} 

,或者你可以添加條目,如果你沒有自己的應用程序源代碼到Web.config中: 您可以通過編程方式在Global.asax中通過重寫的HttpApplication的初始化函數,這樣做:

 <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> 

在system.webServer的條目是IIS7 +中的System.Web另一種是IIS 6
請注意,您需要runAllManagedModulesForAllRequests設置爲true,爲它工作正常。

類型中的字符串格式爲"Namespace.Class, Assembly"。 請注意,如果你寫你的VB.NET,而不是C#彙編,VB爲每個項目創建一個默認的命名空間,所以你的字符串像

"[DefaultNameSpace.Namespace].Class, Assembly" 

如果你想避免這個問題,寫的DLL在C#中。

0

根據MDN SpecificationsX-Frame-Options: ALLOW-FROM在Chrome中不受支持,支持在Edge和Opera中未知。

Content-Security-Policy: frame-ancestors覆蓋X-Frame-Options(根據this W3 spec),但frame-ancestors具有有限的兼容性。根據這些MDN Specs,它在IE或Edge中不受支持。