加密这些系统密码没有额外的安全优势,但是,如果您坚持实现密码加密解决方案,那么这是一个使用 SPI 实现此目标的示例。 我们几乎每天都会在科技和主流媒体上看到计算机系统被攻击的事件,这些系统的密码被盗,然后被攻击者利用。媒体常常指出,这些密码数据可被检索的一个原因是 “它们未加密”。在这种情形下,一定要
认识到所谈论的密码是用户密码,用于登录和访问系统,而不是与系统进程和二进制程序有关联的密码。这是一个极其重要的区别。因此,在这里我想证明的是,前提 “未加密的密码不好”(没有额外的上下文)在技术上是不准确且有误导性的。
考虑到这些">媒体报道,或许 WebSphere 安全顾问、我们的技术销售人员和 WebSphere 安全开发架构师获得的最常见评论都与希望加密其 IBM WebSphere Application Server 系统中的密码的客户有关。重申一下,我们获得的消息是 “WebSphere 几乎实现了它的默认安全主张,但一些密码存储在经过简单编码而不是加密的文件系统中。” 该消息常常还会附带一条说明 “我们的安全审核未通过,因为它们没有被加密。”
首先,IBM WebSphere 软件服务部 和 IBM WebSphere 开发部门的立场是,从安全角度讲,系统密码的编码不存在攻击风险。具有这些主张的审核人员没有理解他们所声称的首选解决方案的安全影响。我稍后会证明这一立场。
但是,因为一些客户坚持认为加密 WebSphere Application Server 使用的系统密码比编码更好,所以 WebSphere Application Server 自 6.0.2 版开始提供了一个系统编程接口 (SPI),可利用该接口来实现客户可能希望实现的密码 “隐藏” 解决方案。使用此 SPI,IBM WebSphere 软件服务部为一些客户实现了这类解决方案。我首先将定义一些基本安全概念,然后介绍这个自定义解决方案中的设计考虑因素。
基础:编码与加密
编码和加密之间有何区别?我们使用词汇编码来表示一种模式,该模式通过公式或算法隐藏了一些内容。考虑您希望 “隐藏” 的一个秘密密码的示例。出于演示用途,假设我有一个确实非常弱的密码:SecretMonkey。可使用一种可逆的算法对此短语编码,以便 “隐藏” 其真实值。
Julius Caesar 使用了一种称为旋转密码或 ROT 密码的编码模式,它将字母表中的字母位置位移一定数量。历史上将这种模式称为凯撒密码。ROT3 密码向右变换 3 个字符位置。ROT3 的变换规则(对于英文字母表)是:
Plain: ABCDEFGHIJKLMNOPQRSTUVWXYZ
Cipher: DEFGHIJKLMNOPQRSTUVWXYZABC
上面的密码经过 ROT3 加密后会变成:
Plain: SecretMonkey
Cipher: VhfuhwPrqnhb
看到此加密字符串后,专业密码专家会快速猜到编码算法并使用逆向算法 (ROT-3) 进行解码。编码强度是该算法的密钥。一定要记住,攻击者擅长逆向工程算法。一旦知道该算法,数据就会失去保护。
与编码相反,加密的安全性不以所使用的算法为基础,而基于难以猜测的密钥的强度。但加密仍然会使用一些算法,只是这些算法(通常)是大家所熟知和理解的。加密算法与编码算法的区别在于,它们接受两种输入:文本和秘密密钥。依据大体相同的方式,一个 4 位借记卡 PIN 使用一个有 1/10,000 的可能性 (104) 被选中的秘密密钥,加密密钥使用一个需要花很大精力才能暴力破解的秘密密钥。
有两种加密类型,二者都基于复杂的数学原理。第一种加密类型涉及到单个密钥,称为共享密钥、秘密密钥或对称密钥加密。请考虑以下两个函数:
cipherText = Encrypt(plainText, secretKey);
以及它的逆函数:
plainText = Decrypt(cipherText, secretKey);
为了保护我的数据,我从一个非常大的密钥集选择了一个密钥(例如一个 256 位的密钥,它是 2256 个可能数字的一个集合,这是一个巨大的数字;使用十进制表示为 1.15x1077:115 后跟 75 个 0)。可以想象,人们调用 Decrypt 函数来迭代所有可能的密钥需要很长的时间。
第二种加密类型使用两个不同的密钥,或者称为非对称密钥。这种类型的加密称为公钥加密或非对称加密。这两个密钥在一种复杂的数学关系中彼此相关。撇开数学原理,加密一段文本的函数调用为:
cipherText = Encrypt(plainText, KeyA);
它的非对称逆函数为:
plainText = Decrypt(cipherText, KeyB);
这里非常重要的一点是,两种加密类型的强度都依赖于猜测该解密函数所需的密钥参数的难度,无论是用于使用对称加密算法加密的数据的共享 “secretKey”,还是用于非对称加密的 “KeyB”。
密码哈希算法
我想在这里更多地讨论一下 “理论”,介绍一种称为单向哈希函数的概念。再次说明,我不会探讨数学知识,因为细节实际上对我的观点并不重要。单向哈希函数(同样)使用了一种大家熟知和理解的算法:
digest = hash(inputString);
其中 inputString 会被转换为一个称为摘要的输出,该过程的逆过程在计算上是不可行的(因此称为 “单向”)。每次提供相同的 inputString,您都会获得完全相同的摘要。对于特定的哈希函数,该摘要通常具有固定的长度。哈希函数还有一个额外的属性,那就是如果更改输入中的任何内容,都会获得差别巨大的摘要输出。
一个平凡的哈希函数可能生成一个 8 位摘要。每个输入 “字符串” 将生成 28 个摘要中的一个。如果输入中的某个位发生更改,则会生成一个不同的摘要。如果继续分析,您会发现有无限多个输入字符串可生成相同的摘要。但我们知道,从一个给定摘要不可能猜测出 inputString。当摘要的大小变得足够大(例如 2256 位)时,另一个随机输入生成相同摘要的几率就会变得无穷小。
攻击者认识到,对于一个给定的算法,可以预先生成所有可能的输入,然后计算它们自己的摘要。这些数据称为 “彩虹” 表。在实际中,实现者会更改哈希函数行为,将所有输入字符串与一个秘密密钥/称为 “盐 (salt)” 的不同前缀串联在一起。所以首选的用法是:
digest = hash(inputString||salt);
攻击者必须使用所有可能的盐字符串来构建彩虹表。
您可能会问,为什么我在漫无目的地闲谈,而不直奔主题?这些关于被盗密码数据库的媒体报道谈论的是这样的一个系统,在该系统中,可在一个数据库中查找用户的密码,而且不幸的是该数据库中的数据未受到适当保护。在 IT 领域,不应将这些密码存储在明文中是一个常识,密码中应包含带有 “盐” 的密码的摘要。换句话说,一个密码 “存储库” 不应包含我的密码字符串 “SecretMonkey”。在验证我的密码时,系统应该将密码串联为字符串使用的特定的 “盐”,然后计算该串联字符串的哈希值,将它与保存的密码摘要对比。如果这两个摘要匹配,那么 inputString – “SecretMonkey” – 很可能就是我的密码。
对我的字符串和不同的盐执行哈希运算的一个虚构示例可能是:
SecretMonkey(不含盐)> !GHD&@DB&!DJD SecretMonkey||(salt=1111) > UCHAKJ$HDJS SecretMonkey||(salt=2222) > njurnasiurrjfdd
您的安全审核应确保这些密码以哈希值格式存储,这至关重要。请注意我没有说加密。我希望您理解它们的细微区别(一个是可逆的,另一个不是)。
但我还未完成所有的操作。毫无疑问,我支持任何表明最终用户密码必须存储为 “加盐的”、经过哈希运算的摘要的人。但最终用户密码和系统密码之间存在巨大的差别。
用户密码不是系统密码
当 WebSphere 系统因系统密码不 “安全” 而 “未通过” 审核时,审核人员没有看到 “用户” 密码。这些密码与运行 WebSphere Application Server 的操作系统用户 ID 或 WebSphere Application Server 应用程序用于连接其他系统的密码有关联。例如,当我登录到 “Financial” 应用程序时,可以想象会发生以下事情:
我对 LDAP 进行了身份验证。在一个 LDAP 绑定操作中,我使用了我的用户 ID 和密码。该 LDAP 服务器对密码(以及它惟一的 “盐”)执行哈希运算,然后将得到的摘要与我保存的摘要对比,以确认或拒绝我的身份声明。 经过身份验证后,Web 应用程序连接到一些后端数据库来查找新的 “通知” 和 “网络请求”。这可能是一个类似 “select notifications where userid=Lansche” 的 SQL 命令。为了预防网络中的任何计算机访问此数据,“Financial” 应用程序使用 “FinancialApp” 凭据连接到该数据库。我们假设这些凭据是一个用户 ID 和密码。
应用服务器需要密码来执行 LDAP 搜索,连接到数据库、队列管理器、Web 服务和其他应用程序,以及用作应用程序的 runAs 身份。当应用程序服务器使用一个用户 ID 和密码对其他系统进行身份验证时,该密码需要以 “适用的” 格式发送:密码的明文版本。正如我的同事 T. Rob Wyatt 在他的 博客 中所解释的:
发件人:存储并转发:在配置文件中加密密码 - 安全与否?
最终,归结起来是这样的:任何必须无人值守地引导到可操作状态的系统都必须能够访问适用的身份验证凭据,“无人值守” 表示系统必须在没有人力干预下经历从通电到完全正常运行的过程。重新引导一个服务器后,所有应用程序将会启动一个命令提示符,等待人类用户输入所有密码,此操作是否可接受?人们通常无法接受此操作。绝对无法接受。在某些情况下适合这么做,但我无法对这些系统执行安全调查,既然我做不到,我就没有发言权。对于其他所有人而言,我们需要的是能够自动恢复且无需人类干预的系统。基本上讲,“无人值守” 表示凭据必须存储在应用程序可在运行时访问的地方,通常位于文件系统中。
换句话说,在 “Financial” 应用程序启动时,您有两个选择:
等待操作员在控制台上键入 “FinancialApp” 用户 ID(以及需要的其他每个系统帐户)的密码,或者 应用程序从文件系统上的某处
获取密码。
我相信实际的应用程序会采用第二种模型。大部分非军方/国家安全系统会采用第二种模型。
PCI-DSS 和系统密码
那么,您的审核人员会说,这些系统密码必须是加密的。PCI-DSS 不包含这项特定的需求。事实上,他们与系统密码相关的惟一言论是,“不要为系统密码和其他安全参数使用供应商提供的默认值”。
图 1. 来自 PCI DSS 的表 - 需求和安全评估规程 2.0 版
规范中肯定还有其他地方提到过 “密码” - 但这些显然与用户密码相关。例如,需求 8 要求您 “向每个具有计算机访问权的人分配一个惟一 ID,”作为该需求的一部分,第 8.4 节要求 “在使用强密码术的所有系统组件上,密码在传输和存储过程中必须是不可读的”。这至关重要,用户密码不应以未执行哈希运算的形式存储在任何地方;正如我上面所说的,惟一的存储应是一个 “加盐的” 单向哈希值!但是,这显然指的是用户密码,而不是系统密码。