ClickOnce 在使用自签名证书更新期间绕过 SmartScreenFilter

ClickOnce bypass SmartScreenFilter during updates with self-signed certificates

我正在开发自己的 .NET 应用程序供私人企业使用,通过 ClickOnce over HTTP 进行分发。我遇到的困难之一是 SmartScreenFilter(内置于 Win 8/10 中)干扰更新。每次更新后,首次 运行 更新后的应用程序需要管理员权限(密码)。

参考这些链接 - Link1, Link2 - 经过反复试验,我能够绕过 SmartScreenFilter。

本质上,我必须创建自签名的可信证书来签署我的应用程序,然后首先在 运行 上安装这些证书。现在无法摆脱它,但是由于自签名证书,新机器将需要管理员权限(实际上您需要输入密码 3 次)。但对于企业用途,"you" 自己设置机器并安装应用程序,这没问题。

详情在回答中:

第 1 步:创建 self-signed 证书

1) 我们需要两个。第一个是证书颁发机构,第二个是用于签署应用程序的实际证书。有关详细信息,请参阅 Link2。我使用了以下命令:

(以管理员身份打开 Visual Studio 开发人员命令提示符)

makecert -sv c:\users\Marko\Desktop\CA.pvk -pe -r -n "CN=My Certificate Authority" -sky signature -a sha512 -e 12/31/2099 -cy authority -ss My -sr LocalMachine c:\users\Marko\Desktop\CA.cer

makecert -sv c:\users\Marko\Desktop\cert.pvk -ss My -sr Localmachine -pe -n "CN=MyPublisherName" -eku "1.3.6.1.5.5.7.3.3,1.3.6.1.4.1.311.10.3.13" -sky signature -a sha512 -e 12/31/2099 -in "My Certificate Authority" -is My -ir LocalMachine c:\users\Marko\Desktop\cert.cer

cert2spc c:\Users\Marko\Desktop\cert.cer c:\Users\Marko\Desktop\cert.spc

pvk2pfx -pvk c:\Users\Marko\Desktop\cert.pvk -pi mypassword -spc c:\users\Marko\Desktop\cert.spc -pfx c:\users\Marko\Desktop\cert.pfx -po mypassword

确保对所有密码提示使用相同的 mypassword。还要在这些命令中相应地修改文件夹路径。

第 2 步:签署您的应用程序程序集、清单和 .exe

在Visual Studio、import/addcert.pfx文件中给你解决方案。转到 Project 属性 -> Signing 选项卡。勾选 Sign the ClickOnce manifests 复选框并使用 cert.pfx 文件进行签名(Select from file 按钮)。然后勾选 Sign the assembly 复选框和 select 组合框中的 cert.pfx 文件。

参考Link1,添加一个Post-Build任务来签署.exe。我选择 Post-Build 选项,因为它是最简单的,而且我对 here 描述的 'signature hash not matching manifest' 没有任何问题。我在 Visual Studio Project 属性 -> Build Events 选项卡 -> Post-build 中使用了以下命令 节:

"C:\Program Files (x86)\Windows Kits\bin\x64\signtool.exe" sign /f "$(ProjectDir)cert.pfx" /p mypassword /v "$(ProjectDir)obj$(ConfigurationName)$(TargetFileName)"

步骤 3:首先通过导入证书绕过 SmartScreenFilter 运行

这是关键部分。我们需要将证书导入 Local Machine\RootLocal Machine\TrustedPublisher 商店。首先,将 CA.cercert.cer 文件添加到解决方案中。将他们的 Build Action 设置为 Content 并将 Copy to Output Directory 设置为 Copy if newer。然后在 Project 属性下 -> Pulish 选项卡 -> Application files 按钮 -> (勾选 Show all files) 将 .cer 文件设置为 Publish Status = Data File

对于实际导入,我在 Window_Loaded() 事件处理程序中调用了 PowerShell:

if (MyApp.Properties.Settings.Default.FirstRun) // I used a custom project setting called 'FirstRun'
{
    try
    {
        using (System.Diagnostics.Process prcs = new System.Diagnostics.Process()) // import certificates
        {
            var dir = (ApplicationDeployment.IsNetworkDeployed ? ApplicationDeployment.CurrentDeployment.DataDirectory :
                System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location));

            var filePath = System.IO.Path.Combine(dir, "CA.cer");
            var filePath2 = System.IO.Path.Combine(dir, "cert.cer");

            prcs.StartInfo.Verb = "runas";
            prcs.StartInfo.FileName = "powershell.exe";
            prcs.StartInfo.Arguments = "Import-Certificate -Filepath '" + filePath + "' -CertStoreLocation cert:\LocalMachine\Root;" +
                "Import-Certificate -Filepath '" + filePath + "' -CertStoreLocation cert:\LocalMachine\TrustedPublisher;" +
                "Import-Certificate -Filepath '" + filePath2 + "' -CertStoreLocation cert:\LocalMachine\Root;" +
                "Import-Certificate -Filepath '" + filePath2 + "' -CertStoreLocation cert:\LocalMachine\TrustedPublisher";
            prcs.Start();
            prcs.WaitForExit();
        }

        MyApp.Properties.Settings.Default.FirstRun = false;
        MyApp.Properties.Settings.Default.Save();
    }
    catch (Exception ex) // if you cancel the UAC dialog for instance
    {
        MessageBox.Show(ex.ToString());
        this.Close();
    }
}

最终结果:

在 Win 10 下,标准本地用户帐户。
如果我转到我的应用程序 (http://somedomain.com/MyApp) 的已发布 URL,请单击“安装”按钮,Setup.exe 将被下载。 Edge 当然会警告,这个文件不常被下载 = 运行 无论如何。

第一个密码提示 = 运行宁 setup.exe(SmartScreenFilter 干扰)
第二个密码提示 = 运行正在安装的应用程序(SmartScreenFilter 干扰)
第三个密码提示 = 运行ning PowerShell 作为管理员。

但是,如果我现在发布我的应用程序的新版本,则不再提示密码,应用程序得到更新并且 运行 没有 SmartScreenFilter 干扰:)

最后的注释:

尽管 cert.cer 现在受到信任,但简单地导入 CA.cer 并没有帮助。但是导入 CA.cer 和 cert.cer 都可以。