在我从业的这么多年时间里,我为各种小型初创企业、大型银行以及电信运营商进行过无数次的代码安全审计,而且在闲暇时间我也阅读过stackoverflow.com上数百篇的安全文章。至此,我总结出了目前开发人员最容易犯的十大加密错误。本系列分上下集,希望大家能够从中得到一些加密方面的启示。
不幸的是,错误使用加密方法的情况比比皆是,而且错误使用的情况远远要比正确使用的情况出现得更加频繁。不过,很多问题是由于加密API本身的复杂性(开发文档描述不清)和不安全性(默认配置不安全)所导致的,也并非错误都处在开发人员的身上。Java可以算得上是目前存在问题最为严重的开发语言之一,而也许Java应该从它的“敌人” .Net身上学到一些东西,例如如何开发出更加方便使用的加密API,或者降低安全问题出现的可能性等等。
导致目前情况不容乐观的另外一个原因也许是很多安全问题往往需要我们对代码进行人工分析才可以发现,而只有经过专业培训的安全专家才能够完成这项任务。根据我的从业经验来看,很多热门的静态分析工具在寻找加密方面的问题时效率和成功率都不高,而且黑盒渗透测试几乎无法发现这种问题。
因此,我希望这篇文章中的内容可以帮助那些代码审计人员以及开发者们提高对软件加密方面的认知。
文章结构如下:
1. 硬编码密钥
2. 初始化向量选择不当
3. ECB操作模式
4. MD5死而不僵,SHA1仍苟存于世
5. 误用加密原语(用于密码存储)
6. 密码未加密
7. 通过加密保证信息完整性
8. 非对称密钥长度不足
9. 不安全的随机性
10. 加密鸡汤
接下来,让我给大家细细道来。
一、 硬编码密钥
这种情况非常的常见,硬编码密钥往往意味着能够访问软件的人手中都有可以解密数据的密钥(对于那些想说“代码混淆”的开发人员,我已经为你准备好了第十条)。理想情况下,我们并不希望加密密钥能够对人类可见,但这毕竟是理想状态。因此,我们只能退而求其次地去限制密钥的访问,并且只允许安全团队访问这个密钥,而开发人员不允许访问产品密钥,尤其是那些本不应该出现在源代码库中的密钥。
硬编码密钥也表现出了开发人员对密钥管理方面的问题思考不足。密钥管理是一个非常复杂的话题,并且超出了本文所要讨论的范围。但我想表达的是,如果密钥被攻击了,那么我们只有发布新版本的软件才能替换掉原先已被攻击的硬编码密钥,而在发布新版本之前往往需要大量的时间和成本来进行测试,但是在密钥已被破解的情况下这种成本是必须要承担的。
安全专家可以轻松地告诉开发人员那些是不应该做的,但事实却总是不尽如人意,因为出于某种原因,我们想让他们做到的往往在实践过程中是不可行的。因此,开发人员通常需要采取一些折中措施。
因此我认为,使用一个配置文件可能会是更好的选择,虽然这并不是完美的解决方案,但这至少要比使用硬编码密钥要好得多。虽然某些框架提供了加密配置选项,但开发人员真正需要的是一个用于测试环境和开发环境的测试密钥,而安全技术团队可以在真正将产品投放市场时用真正的密钥来替换掉测试密钥。
上面的这个建议是我在一个真实的案例中所总结出来的。当时,有一个研发团队在产品中错误地存放了一个RSA公钥,而这个密钥是无法进行解密的,因为他们手中并没有并没有相对应的私钥。而我认为,软件需要一种测试方法来确保其中的密钥可以正常加密/解密,或者至少开发过程中需要有一个环节来确保程序能够按照预期运行。
二、 初始化向量(IV)选择不当
IV指的是初始化向量。这种情况往往出现在CBC加密模式的使用过程中,而且通常存在于硬编码IV中。有时开发人员会使用密钥或SALT值,但最终的结果仍是每一次使用的都是相同的IV。我所见过的最糟糕的情况,就是将密钥当作IV来使用。我在Crypto101的7.6章讨论了这种行为的危险性,感兴趣的同学可以自行点击查阅。【传送门】
当你在使用CBC加密模式时,你需要使用随机的或不可预测的IV。在Java中,使用SecureRandom;在.Net中,使用GenerateIV。而且你这一次选择出的IV只能使用一次,你不可以在其他加密过程中再一次使用这个IV。对于每一次加密,你都要生成一个新的IV。如果你没有选择出何时的IV,那么加密的安全性就得不到保障了,一个最好的例子就是SSL/TLS的实现,其中牵扯到大量选择不当的IV。
如果你想了解更多关于初始化向量(IV)和随机数的操作模式,请参考这篇文章。【传送门】
三、 ECB模式
当你在使用AES这样的分组密码进行加密时,你应该选择一种满足你需要的操作模式。而你最不应该选择的就是ECB(电码本)模式。
无论你使用的是哪一种分组密码,但如果你使用了ECB模式,那就是非常不安全的,因为它会泄漏明文信息,尤其是当重复的明文变成重复的密文时。如果你认为这不重要,那么请你看一看下面这张图片:
你可以看到,采用ECB模式加密后的结果保密性非常差,而采用类似CBC和CTR这样的安全加密模式则安全性会有大幅提升。需要注意的是,像Java这样的编程语言所提供的API默认使用的是ECB模式。
简而言之,不要使用ECB模式。如果你想了解更多有关安全加密模式的内容,请参考这篇文章。【传送门】四、 MD5死而不僵,SHA1仍苟存于世
实际上,MD5早在10年前就已经被破解了,而安全人员更加在20年前就已经开始警告不要再去使用MD5了。但是我发现,现在有很多人仍在使用它。
而理论上SHA1也早已被破解,但外界真正见到的首次攻击是近期才被曝光的。这一点Google就做得非常好,他们在研究人员正式宣布SHA1被破解之前就已经放弃在证书中使用SHA1了,但由于历史遗留问题,很多开发源码中仍然有SHA1的存在。
每当我在开发者的代码中看到加密哈希函数的身影时,我都会非常担心,因为这些人通常都不知道自己将要面对的是什么。在密码学领域中,消息认证代码、数字签名算法、以及各种伪随机数生成器使用的通常都是哈希函数,但如果让开发人员直接使用哈希函数的话,就像是把一支机关枪交到了一名八岁小孩的手上一样,鬼知道会发生什么。各位开发者们,你们确定这些函数真的是你需要的吗?
总结
接下来,我们会在本系列文章的下集中跟大家详细讨论剩下的六大开发者可能会遇到的加密问题,感兴趣的同学可以关注黑吧安全网的最新动态。
|