在下载时将用户特定的数据嵌入到Authenticode签名的安装程序中 [英] Embed user-specific data into an authenticode signed installer on download
问题描述
我有一个使用InnoSetup安装的Windows Forms应用程序,我的用户从我的网站下载了该应用程序。他们将这个软件安装到多台PC上。
I have a Windows Forms application installed using InnoSetup that my users download from my website. They install this software onto multiple PCs.
应用程序与Web API进行通信,该Web API必须能够识别用户。我正在创建一个Web应用程序,用户可以在其中登录并下载该应用程序。我想在安装程序中嵌入一个通用的唯一ID,以便安装后不必再次登录。我希望他们下载并运行setup.exe,并让应用程序自行处理。
The application talks to a Web API which must be able to identify the user. I am creating a web application where the user can log in and download the app. I would like to embed a universally unique ID into the installer so that they do not have to login again after installation. I want them to download and run setup.exe, and have the application take care of itself.
我正在考虑以下几种选择:
I am considering a couple of options:
- 将用户特定的UUID嵌入setup.exe,并在Web服务器上按需执行代码签名。
缺点:不确定如何执行此操作吗? - 将用户特定的UUID嵌入到安装程序文件的名称中(例如setup_08adfb12_2712_4f1e_8630_e202da352657.exe)
缺点:这不太漂亮,如果重命名安装程序会失败 - 将安装程序和包含UUID的设置文件包装到自解压的zip
如何嵌入用户特定的数据是否已存储到Web服务器上已签名的可执行文件中?
How can I embed user-specific data into a signed executable on the web server?
推荐答案
整个PE均未签名。通过将数据添加到签名表中,可以将其嵌入到签名的PE中。此方法是由Webex和其他工具来提供一键式会议实用程序。
The entire PE is not signed. You can embed data into a signed PE by adding it to the signature table. This method is used by Webex and other tools to provide the one-click meeting utilities.
从技术上讲,PKCS#7签名具有一列专门指定为未经身份验证的属性,可以如果没有完整的PE解析器,就无法简单地写入这些字段。幸运的是,我们已经有了 signtool
,并且在已经签名的文件中添加其他签名是使用未验证字段的非破坏性操作。
Technically, the PKCS#7 signature has a list of attributes that are specifically designated as unauthenticated which could be used, but I know of no easy way to write to these fields without a full PE parser. Luckily, we already have signtool
, and adding an additional signature to an already signed file is a non-destructive operation that uses the unauthenticated fields.
我整理了一个演示,该演示使用此技术从MVC传递数据网站到可下载的Windows窗体可执行文件。
I put together a demo which uses this technique to pass data from an MVC website to a downloadable windows forms executable.
过程是:
- 从标准进程产生的Authenticode签名并带有时间戳的exe开始(必须能够无依赖关系运行-ILMerge或类似的东西)
- 将未标记的exe复制到临时文件中 >
- 创建一个临时代码签名证书,其中包含辅助数据作为 X509扩展名
- 使用
signtool
将辅助签名添加到临时文件中 - 返回温度文件下载到客户端,下载完成后将其删除
- Start with the authenticode signed and timestamped exe produced by standard processes
(must be able to run without dependencies - ILMerge or similar) - Copy the unstamped exe to a temp file
- Create an ephemeral code signing certificate which includes the auxiliary data as an X509 extension
- Use
signtool
to add the auxiliary signature to the temp file - Return the temp file to the client, delete it after the download completes
在客户端,应用程序:
- 从当前正在执行的exe读取签名证书
- 使用已知主题名称查找证书
- 使用已知的OID查找扩展名
- 根据扩展名中包含的数据更改其行为
- Reads the signing certificates from the currently executing exe
- Finds the certificate with a known subject name
- Finds the extension with a known OID
- Alters its behavior based off of the data contained in the extension
该过程具有许多优点:
- PE布局没有麻烦
- 公共信任的代码签名证书可以保持脱机状态(甚至在HSM中),Web服务器上仅使用临时证书
- Web服务器不会产生出站流量(
- 快速(对于1MB exe,<50ms)
- 可以在IIS内运行 li>
- No monkeying with the PE layout
- The publicly trusted code signing certificate can stay offline (or even in an HSM), only ephemeral certificates are used on the web server
- No outbound traffic is generated from the web server (as would otherwise be required if timestamping were performed)
- Fast (<50ms for a 1MB exe)
- Can be run from within IIS
客户端数据检索(演示应用程序\MainForm.cs )
try
{
var thisPath = Assembly.GetExecutingAssembly().Location;
var stampData = StampReader.ReadStampFromFile(thisPath, StampConstants.StampSubject, StampConstants.StampOid);
var stampText = Encoding.UTF8.GetString(stampData);
lbStamped.Text = stampText;
}
catch (StampNotFoundException ex)
{
MessageBox.Show(this, $"Could not locate stamp\r\n\r\n{ex.Message}", Text);
}
服务器端标记(演示网站\控制器\HomeController.cs )
var stampText = $"Server time is currently {DateTime.Now} at time of stamping";
var stampData = Encoding.UTF8.GetBytes(stampText);
var sourceFile = Server.MapPath("~/Content/Demo Application.exe");
var signToolPath = Server.MapPath("~/App_Data/signtool.exe");
var tempFile = Path.GetTempFileName();
bool deleteStreamOpened = false;
try
{
IOFile.Copy(sourceFile, tempFile, true);
StampWriter.StampFile(tempFile, signToolPath, StampConstants.StampSubject, StampConstants.StampOid, stampData);
var deleteOnClose = new FileStream(tempFile, FileMode.Open, FileAccess.Read, FileShare.Read | FileShare.Delete, 4096, FileOptions.DeleteOnClose);
deleteStreamOpened = true;
return File(deleteOnClose, "application/octet-stream", "Demo Application.exe");
}
finally
{
if (!deleteStreamOpened)
{
try
{
IOFile.Delete(tempFile);
}
catch
{
// no-op, opportunistic cleanup
Debug.WriteLine("Failed to cleanup file");
}
}
}
这篇关于在下载时将用户特定的数据嵌入到Authenticode签名的安装程序中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!