X-frame headersオプションを使用して保護する必要があるasp.net 4.0 IIS7.5サイトがあります
また、同じドメインとFacebookアプリからサイトページをiframできるようにする必要もあります。
現在、次のサイトにサイトを設定しています:
Response.Headers.Add("X-Frame-Options", "ALLOW-FROM SAMEDOMAIN, www.facebook.com/MyFBSite")
ChromeまたはFireFoxでFacebookページを表示すると、サイトページ(facebookページでiframingされている)は正常に表示されますが、IE9ではエラーが発生します
「このページは表示できません…」(
X-Frame_Options
制限のため)。
複数のドメインをサポートするようにX-Frame-Options: ALLOW-FROM
を設定するにはどうすればよいですか?
X-FRAME-OPTION
は、1つのドメインしか定義できない場合、基本的に新しい機能に欠陥があるようです。
X-Frame-Options
は非推奨です。 MDN から:
この機能は、Web標準から削除されました。一部のブラウザではまだサポートされている場合がありますが、削除される過程にあります。古いプロジェクトや新しいプロジェクトでは使用しないでください。これを使用するページまたはWebアプリはいつでも壊れる可能性があります。
最新の代替手段は Content-Security-Policy
ヘッダーです。これは、他の多くのポリシーに沿って、 frame-ancestors
ディレクティブを使用して、フレーム内でページをホストできるURLをホワイトリストに登録できます。frame-ancestors
は、複数のドメインとワイルドカードをサポートします。例:
Content-Security-Policy: frame-ancestors 'self' example.com *.example.net ;
残念ながら、今のところ、 Internet ExplorerはContent-Security-Policyを完全にはサポートしていません 。
更新: MDNは非推奨コメントを削除しました。 W3Cのコンテンツセキュリティポリシーレベル からの同様のコメントを次に示します。
frame-ancestors
ディレクティブはX-Frame-Options
ヘッダーを廃止します。リソースに両方のポリシーがある場合、frame-ancestors
ポリシーを適用する必要があり(SHOULD)、X-Frame-Options
ポリシーを無視する必要があります。
RFC 7034 から:
1つのALLOW-FROMステートメントで複数のドメインを宣言するためのワイルドカードまたはリストは許可されていません
そう、
X-Frame-Options:ALLOW-FROMを設定して、複数のドメインをサポートするにはどうすればよいですか?
できません。回避策として、パートナーごとに異なるURLを使用できます。各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ベースのブラウザ) サポートしていませんALLOW-FROM
ステートメント。
複数のドメインを許可するだけでなく、動的ドメインを許可するアプローチはどうでしょうか。
ここでの使用例は、iframeを介してSharepoint内にサイトをロードするSharepointアプリパーツを使用する場合です。問題は、sharepointに https://yoursite.sharepoint.com などの動的サブドメインがあることです。 IEの場合、ALLOW-FROM https://.sharepoint.comを指定する必要があります
トリッキーなビジネスですが、次の2つの事実がわかっていれば完了できます。
Iframeがロードされると、最初のリクエストでX-Frame-Optionsのみが検証されます。 iframeがロードされると、iframe内をナビゲートでき、以降のリクエストでヘッダーはチェックされません。
また、iframeが読み込まれると、HTTPリファラーは親iframeのURLになります。
これら2つのファクトサーバー側を活用できます。 Rubyでは、次のコードを使用しています。
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で終了し、クリックジャックからサイトを安全に保ちます。
このアプローチについてのフィードバックをお待ちしています。
ネクロマンシング。
提供された回答は不完全です。
まず、既に述べたように、複数の許可元ホストを追加することはできません。これはサポートされていません。
第二に、HTTPリファラーからその値を動的に抽出する必要があります。つまり、Web.configに値を追加することはできません。常に同じ値ではないためです。
ブラウザーがChromeの場合に許可元の追加を避けるためにブラウザー検出を行う必要があります(デバッグでエラーが発生します-コンソール。すぐにコンソールがいっぱいになるか、アプリケーションが遅くなる可能性があります) )。また、ASP.NETブラウザーの検出を変更する必要があります。これは、EdgeをChromeとして誤って識別するためです。
これは、ASP.NETで、リクエストのリファラーに応じて、すべてのリクエストで実行されるHTTPモジュールを記述し、すべてのレスポンスにhttp-headerを追加することで実行できます。 Chromeの場合、Content-Security-Policyを追加する必要があります。
// 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モジュールの初期化関数に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
}
次に、モジュールをアプリケーションに追加する必要があります。次のように、HttpApplicationのInit関数をオーバーライドすることにより、Global.asaxでプログラムでこれを行うことができます。
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にエントリを追加できます。
<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に設定する必要があることに注意してください。正しく機能するためです。
Typeの文字列は"Namespace.Class, Assembly"
形式です。 C#ではなくVB.NETでアセンブリを記述する場合、VBは各プロジェクトのデフォルトの名前空間を作成するため、文字列は次のようになります。
"[DefaultNameSpace.Namespace].Class, Assembly"
この問題を回避するには、C#でDLLを記述します。
IEにはX-Frame-Optionsを、他のブラウザーにはContent-Security-Policyを追加する必要がありました。だから私は次のようなことをした。
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
まったく同じではありませんが、場合によっては動作する可能性があります。制限を効果的に削除する別のオプションALLOWALL
があります。これは、テスト/運用前環境に適している場合があります