.NET开源项目和强名称程序集?

27

我目前正在考虑开源我的一个项目,并正准备将源代码和项目结构发布给公众。现在我有一个问题:我应该如何处理我的程序集的签名密钥?我应该为开源版本创建一个新的密钥,并将其与其他文件一起发布到SVN存储库中吗?还是应该留下密钥,让每个想要编译代码的人生成自己的密钥?

您是如何处理这个问题的?我感到公开一个签名密钥有点不安。


5
将签名密钥公开发布可能会让你感到不舒服。 - Cheeso
我的关注点在于LGPL要求某人能够使用修改后的LGPL库。如果我不发布我用来签署原始LGPL构建库的密钥,用户就无法直接替换该库,这将违反LGPL... - Martin C.
相关:https://dev59.com/2mgu5IYBdhLWcg3wAiYi - Mark Seemann
4个回答

24

对于Protocol Buffers,我释放了密钥。是的,这意味着人们实际上不能相信它是原始二进制文件 - 但对于想要修改代码并重新构建它,并仍然能够从另一个已签名程序集中使用它的任何人来说,这使他们的生活变得更加轻松。

如果有人真的想要一个可以放心信赖的Protocol Buffers版本,确保它是使用GitHub中的代码构建的正版,他们可以轻松地从他们信任的源代码自行构建。

不过我肯定可以理解两面性。我认为,如果我正在编写一个围绕安全展开的开源项目,那就可能是另一回事了。


1
释放密钥似乎是一个非常糟糕的想法。谁来经纪版本号?如果BigCorp X部门的Joe下载ProtocolBuffers.sln,修改它,分配版本2.1.0.0。然后BigCorp Y部门的Shirley也这样做了。两者都是签名的、强命名的程序集,但它们是不同的。这些人用自己的密钥签署修改后的程序集有多难? - Cheeso
4
如果BigCorp决定搞砸事情,那么他们确实会让自己的生活更加困难。如果不释放钥匙,这将使所有人的生活更加困难。我宁愿让大多数人的生活变得更容易,并允许人们偶尔自己给自己惹麻烦,也不愿意让所有人的生活变得更加困难。 - Jon Skeet
2
他们创建一对密钥来签名程序有多难?这只是命令行上的一个额外步骤!而且它只需要做一次。这对于ProtoBufs可能无关紧要,但对于更广泛使用的东西,比如XML库,它会导致灭亡。Java的Xerces lib周围的Jar-H3LL是一个很好的教训。到处都有版本。你可能有依赖于多个OSS项目的应用程序,它们每个都依赖于不同版本的Xerces。强名称(Java缺乏)可以解决这个问题。但只有带完整性的强名称。 - Cheeso
3
对于Noda Time,我认为我们将拥有一个任何人都可以构建的密钥,以及只有少数提交者才能访问的私人密钥。这样,每个人默认会获得一个已签名程序集,但预构建的二进制文件可验证为“我们自己的”。我认为这是两全其美的最佳选择。如果您所描述的问题(保护他人免受自己的影响)是次要问题,那么您应该说明主要的实际问题。 - Jon Skeet
1
这是一个非常好的想法,发布签名密钥!一些非常棒的开源库已经准备好用于企业,但却没有签名,这真是太痛苦了(也很遗憾)。如果需要,只需不到一分钟就可以使用密钥重新构建修改后的源代码,否则可以使用打包库(例如来自NuGet)。希望像Jon Skeet这样的先知能够推动这个想法,例如ServiceStack作者... - V.B.
显示剩余8条评论

19

不要发布密钥。

将签名密钥公开发布会让你感到不安。 这不是项目的签名,而是你的签名。 只有保密密钥才能维护二进制文件上签名的完整性。 公开发布密钥会破坏有关组件签名和强名称的意义和目的,从而引入新的错误可能性,并因此使每个系统 less reliable。 不要发布密钥

对于DotNetZip,我不会发布密钥。 但是这里有一个关键点:这个密钥不属于项目;它是我的密钥。 许多人要求密钥以便重新构建已签名的二进制文件,但这毫无意义。 我使用密钥来签署比DotNetZip更多的代码。 使用我的密钥签名的任何二进制文件都是由我签名的。 使用相同的密钥生成具有相同强名称的任何两个二进制文件都保证是相同的。 发布密钥会消除这些保证,破坏强名称的整个目的以及与其相关的安全性。

想象一下开发人员选择自己的版本号,并使用我的密钥重新签名修改后的二进制文件。 现在,世界上有两个具有相同强名称但内容不同的组件。

想象一下如果我能够使用你的密钥签署任何组件。 如果你发布了密钥,我可以添加任何代码 - 即使是恶意代码 - 然后签名并偷偷地用“坏”的组件替换任何“好”的已签名二进制文件。 没有人能够区别它们之间的区别。

这是错误的。 自由共享密钥消除了使用签名组件的任何优势。

如果人们想修改项目中的代码,然后将修改版本重新用强命名组件重用,他们可以使用自己的密钥对修改的版本进行签名。 这并不困难。


你如何处理替换掉原有库的需求(例如LGPL所要求的)?除非使用相同的密钥签名,否则修改过的库版本将无法从已签名程序集中加载。 - Martin C.
我不理解这个问题。我认为你在问我,如何使别人能够使用一个不同的库来替换我的库。而对于这个问题的答案是,我不会这样做。我不会允许这种情况发生。 - Cheeso
2
非常抱歉这么晚才跟进:LGPL 要求 您使某人能够放置另一个版本的LGPL库。如果(我假设的)LGPL库无法被替换,那么它就违反了LGPL。 - Martin C.
FYI,我的库不是LGPL。在我看来,LGPL很奇怪。维基百科说LGPL中的条款特别涉及C语言链接问题,并且需要修订才能处理LISP代码。真的吗?那太奇怪了。这是一个非常糟糕的许可证。 - Cheeso

11

我不会公开发布密钥。签名程序集的整个目的在于人们可以相信只有你接触了二进制文件,因此如果添加了任何非法代码,则签名将失效,人们知道不要信任该程序集。

签名程序集可保护你免受其他人添加“坏”代码并将其假冒为合法版本的影响。


虽然我同意你的观点,但我不确定如何在开源环境中处理这个问题。那么每个项目的二进制分发者都应该使用自己的代码吗?由于它可以作为库使用,这也意味着没有其他人可以创建组件的即插即用替代品。 - Martin C.
2
每个重新分发项目的方当应该(a)重新分发未经修改的二进制版本,签名后生产;或者(b)重新分发已修改的二进制版本,使用不同的密钥进行签名 - 他们自己的密钥;或者(c)重新分发源代码。这些选项并不是互斥的。但是重要的是,密钥必须属于签署方,而不是项目。否则,签名的意义和价值将被破坏,正如卡梅伦所指出的那样。 - Cheeso
我完全同意,但如果我的许可证解释是正确的,它将违反/使使用LGPL库变得不可能。 - Martin C.

0
一般来说,.Net只关心公钥标记而不是实际的密钥和签名(除了在InternalsVisibleTo的情况下需要完整的公钥)。如果要为全新的程序集签名以获得特定的公钥标记(当然还需要公钥),则需要访问原始密钥。但是,可以直接修改原始程序集的IL(或使用诸如Fody之类的IL编织器或dnSpy工具),.Net将会愉快地加载它。
事实上,似乎IgnoresAccessChecksToGenerator工具就是这样做的。

因此,我认为保持私有性并没有太多价值,而且我发现许多流行的开源项目,例如GitHub for Visual StudioLog 4 Net实际上是公开的。

另外请注意,Microsoft建议在开源项目中检查.snk文件:

如果您是开源开发人员,并且希望使用强名称程序集获得更好的.NET Framework兼容性的身份验证功能,请考虑将与程序集关联的私钥检入到您的源代码控制系统中。

他们还澄清道:

警告

不要依赖强名称进行安全性。它们仅提供唯一的标识。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接