有没有办法避免 CEF Windows Chromium 桌面应用程序中的 X-Frame-Options?

Is there a way to avoid X-Frame-Options in a CEF Windows Chromium Desktop App?

我使用建议的 "app init" 创建了一个简单的应用程序,然后我将预编译的 ReactApp 放到了适当的位置。 该应用程序中有一个使用 IFrame 托管导航页面的浏览器,但在某些页面中,它会发出以下错误:

拒绝显示'https://www.theverge.com/' in a frame because it set 'X-Frame-Options' to 'sameorigin'.", source: http://localhost:5000/#/

https://content-security-policy.com/

上面的页面提供了一系列如何避免这种情况的方法,Chromium 有一个可以提供帮助的标志,它禁用安全性以及其他帖子和问题中建议的许多方法,这可能有助于解决这个问题。

除此之外,还有可能编写一个反向代理来解决这个问题。

无论哪种方式,我需要知道的是是否有一种方法可以通过 "app" 工具中的参数来实现,例如:

app --unsecure
app publish --unsecure
app publish-exe --unsecure

谢谢

我尝试了很多不同的选项,包括使用 Custom .NET Core Desktop Apps 添加了曾经有效的 disable-web-security 开关:

static int Main(string[] args)
{
    var host = new WebHostBuilder()
        .UseKestrel()
        .UseContentRoot(Directory.GetCurrentDirectory())
        .UseStartup<Startup>()
        .UseUrls("http://localhost:5000/")
        .Build();

    host.StartAsync();

    var config = new CefConfig(Debug)
    {
        Args = args,
        StartUrl = startUrl,
        HideConsoleWindow = false,
        OnBeforeCommandLineProcessing = (processType, commandLine) => {
            commandLine.AppendSwitch("disable-web-security");                    
        }
    };

    return CefPlatformWindows.Start(config);
}

但现在看来此安全限制已嵌入到 Blink 中。

使用代理删除 Headers

我可以开始工作的唯一解决方案是使用代理调用内部 .NET Core 服务器代理下游 URL 但忽略 X-Frame-Options header。

使用 ServiceStack 的 Proxy Feature where you can register a proxy to https://www.theverge.com 可以很容易地做到这一点,它使用以下方式剥离 X-Frame-Options header:

Plugins.Add(new ProxyFeature(
    matchingRequests: req => req.PathInfo.StartsWith("/theverge"),
    resolveUrl: req => $"https://www.theverge.com" + req.RawUrl.Replace("/theverge", "/")) {
    IgnoreResponseHeaders = {
        "X-Frame-Options"
    }
});

这样您就可以将 The Verge 嵌入到您的应用中:

<iframe src="/theverge" style="width:100%; height:800px;" frameborder="0"></iframe>

这将按预期在 iframe 中呈现 TheVerge:

工作演示

您可以在 ServiceStack.CefGlue.Win64.AspNetCore 中找到一个工作示例:

Startup.cs

public class Startup
{
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseServiceStack(new AppHost());

        app.Run(context =>
        {
            context.Response.Redirect("/metadata");
            return Task.FromResult(0);
        });
    }
}

public class AppHost : AppHostBase
{
    public AppHost() : base("MyApp", typeof(MyServices).Assembly) { }

    public override void Configure(Container container)
    {
        Plugins.Add(new SharpPagesFeature());

        Plugins.Add(new ProxyFeature(
            matchingRequests: req => req.PathInfo.StartsWith("/theverge"),
            resolveUrl: req => "https://www.theverge.com" + 
                                req.RawUrl.Replace("/theverge", "/")) {
            IgnoreResponseHeaders = {
                "X-Frame-Options"
            }
        });
    }
}

[Route("/hello")]
public class Hello : IReturn<HelloResponse>
{
    public string Name { get; set; }
}

public class HelloResponse
{
    public string Result { get; set; }
}

public class MyServices : Service
{
    public object Any(Hello request) => 
        new HelloResponse { Result = $"Hello, {request.Name}!" };
}

ServiceStack.CefGlue.Win64.AspNetCore.csproj

<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.*" />
<PackageReference Include="ServiceStack.CefGlue.Win64" Version="5.*" />
<PackageReference Include="ServiceStack" Version="5.*" />
<PackageReference Include="ServiceStack.CefGlue" Version="5.*" />
<PackageReference Include="ServiceStack.CefGlue.Win64" Version="5.*" />
<PackageReference Include="WinApi" Version="4.0.0" />

您还需要从 ServiceStack.CefGlue.Win64 NuGet 包中复制 CEF 二进制文件:

<ItemGroup>
    <Content Include="locales\*.*">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="swiftshader\*.*">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="*.pak">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="*.lib">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="*.dat">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="*.dll">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="*.bin">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="*.exe">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    </ItemGroup>

    <Target Name="CopyLinkedContentFiles" BeforeTargets="Build">
    <Copy SourceFiles="%(Content.Identity)"
            DestinationFiles="$(OutputPath)\%(Content.Link)"
            SkipUnchangedFiles="true"
            OverwriteReadOnlyFiles="true" />
</Target>

index.html

<!DOCTYPE html>
<html lang="en">
<body>
    <h1>X-Frame-Options Proxy Test</h1>
    <iframe src="/theverge" style="width:100%; height:800px;" frameborder="0"></iframe>
</body>
</html>