我们最近进行了安全审核,并暴露了此处系统中的一些弱点。由此产生的任务之一是我们需要更新我们的合作伙伴凭证系统以使其更安全。
“旧的”处理方式是生成(坏)密码,将其提供给具有ID的伙伴,然后他们将使用其所有XML发送该ID和该密码的Base 64编码副本通过https请求。然后我们解码它们并验证它们。
这些密码不会改变(因为那时我们的合作伙伴必须进行编码/配置更改才能更改它们,并与多个环境的数百个合作伙伴协调密码到期将是一场噩梦)并且不必输入由人或人可读。如果我们的合作伙伴有更好但仍然相对简单的实施,我愿意改变这一点。
基本上它归结为两件事:我需要一个更安全的Java密码生成系统,并确保它们以安全的方式传输。
我找到了一些手动密码生成器,但没有什么真正脱颖而出作为标准方法来做到这一点(也许是有充分理由的)。传输它们可能比通过https进行简单的Base 64编码更安全。
您会对密码生成器做些什么,您认为现有的传输方法是否足够安全?
编辑:XML出现在SOAP消息中,凭据位于标头中,而不在XML本身中。此外,由于在我们设置密码时,密码是每个合作伙伴的一次性操作,我们并不太担心发电机的效率。
答案 0 :(得分:6)
就编码传输密码而言,唯一真正增加安全性的编码就是加密。使用Base-64或十六进制不是为了安全,而是为了能够以XML等文本格式包含它。
熵用于衡量密码质量。因此,选择每个位随机“硬币翻转”将为您提供最优质的密码。您希望密码与其他加密密钥一样强,因此我建议至少使用128位熵。
有两种简单的方法,具体取决于您希望如何将密码编码为文本(从安全角度来看,这无关紧要)。
对于Base-64,请使用以下内容:
SecureRandom rnd = new SecureRandom();
/* Byte array length is multiple of LCM(log2(64), 8) / 8 = 3. */
byte[] password = new byte[18];
rnd.nextBytes(password);
String encoded = Base64.encode(password);
以下内容不要求您提供Base-64编码器。结果编码不是那么紧凑(26个字符而不是24个),密码没有那么多的熵。 (但是130位已经很多了,相当于人类选择的至少30个字符的密码。)
SecureRandom rnd = new SecureRandom();
/* Bit length is multiple of log2(32) = 5. */
String encoded = new BigInteger(130, rnd).toString(32);
创建新的SecureRandom对象的计算成本很高,因此如果您要经常生成密码,您可能需要创建一个实例并保留它。
将密码嵌入XML本身似乎是个错误。
首先,在处理发送给您的任何文档之前,您似乎想要验证发件人。假设我讨厌你的胆量,并开始向你发送巨大的XML文件来执行拒绝服务攻击。您是否只想解析XML以发现我不是合法的合作伙伴?如果servlet刚刚拒绝了来自未经身份验证的用户的请求,那会不会更好?
其次,合法合作伙伴的密码在通过HTTPS传输时受到保护,但现在它们很可能存储在您系统的“明确”位置。那是不好的安全。
更好的方法是在合作伙伴向您发送带有HTTP请求标头中的凭据的文档时对其进行身份验证。如果您只允许HTTPS,则可以完全取出文档中的密码,并将其放入HTTP "Basic" authentication标题中。它在传输过程中由SSL保护,并且不以明文形式存储在您的系统上(您只存储单向哈希以进行身份验证)。
HTTP基本身份验证非常简单,受到广泛支持,并且您和您的合作伙伴将比SSL客户端证书更容易实现。
如果文档本身的内容是敏感的,它们确实应该由发件人加密,并以加密形式存储。最好的方法是使用公钥加密,但这将是另一个问题的主题。
答案 1 :(得分:1)
您是否无法使用SSL密钥进行身份验证?
答案 2 :(得分:0)
我不清楚为什么通过SSL传输密码 - 通过HTTPS - 被审计小组视为“不安全”。因此,当你要求两件事时,似乎第二件事 - 确保密码以安全的方式传输 - 已经处理得很好。
首先,我们必须知道审计将您的密码暴露为不安全...
答案 3 :(得分:0)
我放弃了整个密码方法并开始使用客户端证书,允许双方认证的SSL连接。
您必须为每个客户生成和签署单独的证书。在SSL握手中,您请求客户端的证书并进行验证。如果失败,则连接以401状态代码结束。
证书可以随时撤销,可以轻松断开以前的客户。
由于所有这些都发生在通信之前的握手中,因此无法使服务器充满数据。