防止程序集被篡改,可以用两种不同但相互补充的方式对程序集进行签名:使用强名称或使用SignTool.exe(签名工具)
可以将强名称的数字签名和使用SignTool.exe(签名工具)的证书签名一起提供给程序集,或者您可以单独使用其中之一。这两个签名工具一次只能对一个文件进行签名,对于多文件程序集,您可以对包含程序集清单的文件进行签名 (CLR总是首先加载包含“清单”元素据表的文件,再根据这个“清单”来获取程序集中的其他文件的名称) 。
强名称签名的密钥【不必与】签名工具的微软代码签名证书密钥相同。
一、强名称程序集
1. 强名称程序集放篡改原理
强名称程序集图示如下:
检查:加载程序集的检查,系统对包含清单的那个文件的内容进行哈希处理,并将哈希值与PE文件中嵌入的RSA数字签名进行比较。系统还会对程序集的其他文件的内容进行哈希处理,并将哈希值与清单文件的FileDef表中存储的哈希值进行比较。
将一个强命名的程序集安装到GAC时,系统会执行一次检查,核实含有清单的那个文件没有被篡改。这个检查只在安装时执行一次。除此之外,为了增强性能,如果程序集被完全信任,并加载到一个完全信任的AppDomain,CLR不检查强命名的程序集是否被篡改。相反,从非GAC的一个目录加载强命名程序集时,CLR会校验程序集的清单文件,核实文件的内容未被篡改,造成该文件每次加载都会带来额外的性能开销。
2. 实践强名称签名验证
通过使用 Microsoft SDK 工具:ildasm.exe(IL反汇编工具)改变程序集内容。
a) 将程序集用 ildasm.exe 工具打开,执行“文件---转储”保存为 .il 文件(同时还会保存一个.res文件),用文本工具打开il文件改变文件内容(如多加一个程序集引用)。
b) 执行“运行---cmd”打开命令行程序,输入:ilasm /resource=*.res *.IL /dll
此时强名称程序集本身内容已被更改,在CLR执行程序集加载进行强名称签名检查时报如下错误(若为简单程序集不会检查报错):
3. 强名称程序集是否安全?
知道强名称签名验证后,我们来看看强名称程序集到底附加了什么信息,比如:强名称程序集A 引用强名称程序集B
-------强名称程序集B本身多出 .publickey 标识
-------强名称程序集A对B的引用处多出 .publickeytoken 标识
通过Microsoft SDK 工具:ildasm.exe(IL反汇编工具),我们已经知道可以对程序集内容进行篡改,并且篡改的内容会因为强名称验证而报错。但是:
a) 如果把如上强名称程序集A的 .publickey 内容删除,那么A
就不再是强名称程序集了,即在加载程序集A时不会进行强名称程序集A的篡改检查。那么这时候可以对A进行任意更改。
b) A引用B时因为有.publickeytoken强名称标识所以要求B是强名称且生成和A中记录的相同公钥标识。如果仅仅删除A的.publickeytoken那么会报如下错误:
因为找不到指定的强名称标识程序集( 《(5)CLR 运行时探测程序集引用的步骤》 ),所以我们必须将B的 .publickey内容一并删除。这样可以实现被引用的程序集任意更改。
为了解决这个问题,所以我们必须同时使用 SignTool.exe(签名工具)对程序集进行证书签名。
二、SignTool.exe(签名工具)签名
签名工具要求发行者向第三方证书颁发机构证实其标识并获取证书。然后此证书将嵌入到您的文件中,并且管理员能够使用该证书来决定是否相信这些代码的真实性。
执行如下命令
生成证书 makecert -r -pe -sv MyCert.pvk MyCert.cer
生成.pfx pvk2pfx.exe -pvk MyCert.pvk -spc MyCert.cer -pfx MyCert.pfx
证书签名 signtool sign /f MyCert.pfx D:\ClassLibrary1.dll
这样,在查看被签名的程序集属性时会有“数字签名”页签,
通过查看证书按钮可查看证书具体信息,确保所使用的文件是由指定产家提供,关于证书如何验证请参见 《数字签名|数字证书》
那么,既然有证书验证为什么还是需要强名称程序集?因为强名称程序集提供了诸如版本控制、能安装在GAC中等简单程序集不能提供的优点。
《反射机制》系列:
(1)程序集基础知识
(2)强名称程序集与数字证书
(3)程序集加载 Assembly类
(4)绑定程序集配置策略
(5)CLR 运行时探测程序集引用的步骤
(6)程序集加载上下文
(7)动态程序集加载Load()
(8)程序集反射 Type 类
(9)程序集的加载和反射
相关链接: 《数字签名|数字证书》
参考书籍:CLR via C#(第3版)