我正在尝试了解Maven 3的[密码加密功能。我发现此功能的文档记录不佳且令人困惑。例如,功能文档和功能作者的博客文章在几个方面相互矛盾。
这个问题比 maven --encrypt-master-password 如何工作更广泛,并且没有包含在 Maven 加密主密码选择密码的良好实践中。
具体来说,我正在尝试回答文档未涵盖的以下问题。我把我迄今为止能够收集到的信息放在斜体字的每个问题下面。
- 加密的主密码是否仅仅通过存在于只有一个用户可以访问的文件夹中(
~/.m2
)存在于settings-security.xml
中来提供安全性?如果是这样,为什么要费心加密"主密码"(为什么不直接使用一些随机值)?"主密码"真的只是加密函数的熵输入吗?称其为密码令人困惑 - 我希望Maven在解密任何加密的服务器密码之前提示我输入此密码,但事实并非如此。
我的理解是,是的,这仅通过存在于受操作系统保护的文件中来提供安全性。我相信Maven允许您加密主密码,以便如果您丢失了settings-security.xml
文件,则可以重新生成它。这是对的吗?
- 主密码和服务器密码是否使用相同的加密过程/密码?服务器密码基于主密码,因此算法必须存在一些差异。它的源代码在哪里?
Marcelo Morales关于maven如何--encrypt-master-password工作方式的回答链接到GitHub上的plexus-cihper项目。目前尚不清楚这是否只是密码,还是提供密码功能的实际Maven插件。
- 我观察到相同的主密码或多次加密的服务器密码会产生不同的哈希值。根据Marcelo Morales关于maven --encrypt-master-password如何工作的回答,这是因为在加密之前,"特定于JVM配置(通常SHA1PRNG)的64位随机盐"被添加到密码中。Maven 在编译时使用存储的密码时解密存储的密码。这不意味着盐必须储存在某个地方吗?
我不知道。
- 我还观察到,如果主密码重新加密并存储在
settings-security.xml
文件中,则使用一个加密的主密码加密的常规密码仍然有效,即使加密的主密码密文现在不同。有人可以解释一下这是如何工作的吗?
我不知道。在我看来,Maven 正在做一些可疑的事情或在某处存储明文。
- 我的理解是,加密的密码只能与
settings.xml
文件中<server />
标签一起使用。 这是真的吗?在哪里可以使用settings.xml
中定义的服务器?
我的理解是,<server />
定义可以用于<repositories />
和<distributionManagement />
,但不能用于<scm />
。有人可以验证这一点吗?
- 对于这样一个关键功能(构建系统安全性),在我看来,存在很多混乱和糟糕的文档。有人可以指出Maven 3网站上的文档是如何工作的吗?是否有某个 wiki 链接可以让我尝试改进文档?
我不知道
很抱歉文字墙,并感谢您的任何答案。
我的答案是基于阅读Maven源代码并进行一些研究。
- 加密的主密码是否仅通过存在于只有一个用户可以的文件夹中的
settings-security.xml
中来提供安全性 访问 (~/.m2
)?如果是这样,为什么要费心加密"主节点" 密码'(为什么不直接使用一些随机值)?难道"主人"不是 密码'真的只是加密函数的熵输入吗? 称其为密码令人困惑 - 我希望 Maven 会提示我 此密码在解密任何加密的服务器密码之前,但是 它没有。
主密码是加密函数的输入,用于加密/解密服务器密码。如果有人拥有您的个人加密服务器密码,除非他们也拥有您的主密码,否则他们将无法解密它们。这意味着您可以与他人自由共享您的maven设置.xml文件,而他们无法解密您的服务器密码。这也是主密码保存在单独文件中的原因。
加密指南中对此基本原理进行了一些解释
- 主密码和服务器密码是否使用相同的加密过程/密码?服务器密码基于主密码, 所以算法上一定有一些差异。源头在哪里 这个定位的代码?
据我所知,主密码使用与服务器密码相同的密码进行加密。解密服务器密码时,主密码(未加密形式)是输入;解密主密码时,魔术字符串"Settings.security"用作附加输入。
您可以看到源代码PBECipher和MavenCli.java。
- 我观察到相同的主密码或多次加密的服务器密码会产生不同的哈希值。根据马塞洛的说法 莫拉莱斯关于 maven 如何加密主密码的回答 工作,这是因为'一个 特定于 JVM 配置(通常SHA1PRNG)的 64 位随机盐是 在加密之前添加到密码中。Maven 解密存储 编译时使用的密码。这不意味着 盐必须储存在某个地方?
处理盐的传统方法是将随机盐与加密文本一起存储。请参阅维基百科文章。
根据上面链接的源代码,盐似乎存储为 Base64 解码字节的前 8 个字节,就在加密密码之前。
- 我还观察到,如果主密码是 重新加密并存储在
settings-security.xml
文件中,甚至 尽管加密的主密码密文现在有所不同。 有人可以解释一下这是如何工作的吗?
这是因为使用的是主密码的解密形式,而不是加密的"密文"。因此,重新加密它不会影响服务器密码加密/解密。
我不知道你最后两个(5和6)问题的答案。
我需要知道bnd(tools)的这个,这样我才能分享一些更深入的分析。
"加密"密码的语法为:
output ::= '{' base64(packet) '}'
packet ::= salt[8] padlen[1] encrypted[?] padding[padlen]
salt ::= <random>
padlen ::= <length of padding >
padding ::= <random to make packet length a multiple of 16>
使用的密码是 AES/CBC/PKCS5Padding
。密钥和初始化向量的计算方法如下:
sha = sha256( X + salt[8] )
key = sha[0..16]
iv = sha[16..32]
对于主密码X是"security.settings"。由于这是一个众所周知的常量,因此主密码未加密,而只是被掩盖。对于服务器密码,X 是解码的主密码。
为什么填充生成的数据包似乎是浪费字节,因为数据包格式使得剥离变得微不足道,并且它们从来都不是加密/解密的一部分。 他们只是在 base64 字符串中添加一些随机字符。
唯一有用的方法是使用搬迁设施。例如,如果将设置安全挂载.xml挂载在构建服务器上的专用挂载上。然后,您可以在公共存储库中自由共享settings.xml
文件。但是,这也是一个糟糕的解决方案,因为您需要为所有用户和 CI 构建服务器挂载相同的挂载点。
请注意,任何插件都可以解码您的所有服务器密码,因此切勿为服务器使用真实密码。Nexus可以创建代理密码。
这是示例代码,显示了如何从
~/.m2/security-settings.xml
以及来自的服务器密码
~/.m2/settings.xml
MavenPasswordDecryptor.java
来源
import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;
public class MavenPasswordDecryptor {
public static void main(String[] args) throws Exception {
if (args.length < 1 || args.length > 2 ) {
System.out.println("Usage: java -jar maven-password-decryptor.jar <encrypted-password>");
System.out.println("Usage: java -jar maven-password-decryptor.jar <encrypted-password> <master-password>");
return;
}
DefaultPlexusCipher cipher = new DefaultPlexusCipher();
String encryptedPassword = args[0];
String passPhrase = (args.length == 2 && args[1] != null && !args[1].isEmpty()) ? args[1] : "settings.security";
String result = cipher.decryptDecorated(encryptedPassword, passPhrase);
System.out.println(result);
}
}
GitHub上还有一个示例项目:
https://github.com/uweguenther/maven-password-decryptor