由于生成令牌的过程不安全,攻击者能够确定发布给其他用户的令牌,致使会话管理机制易于受到攻击。
注解
许多时候,应用程序的安全取决于它所生成的令牌的不可预测性,以下是一些示例:
发送到用户注册的电子邮件地址的密码恢复令牌;
隐藏表单字段中用于防止跨站点请求伪造攻击(请参阅第13章)的令牌;
用于一次性访问受保护的资源的令牌;
“记住我”功能使用的永久令牌;
未使用验证的购物应用程序的消费者用于检索现有订单的当前状态的令牌。
在本章中,我们主要讨论适用于上述所有情形的与令牌生成有关的缺陷。实际上,由于当前的许多应用程序都采用成熟的平台机制来生成会话令牌,因此,往往会在这些功能区域发现有关令牌生成的可利用缺陷。
一些会话令牌通过用户的用户名或电子邮件地址转换而来,或者使用与其相关的其他信息创建。这些信息可以某种方式进行编码或模糊处理,也可与其他数据结合在一起。
例如,初看起来,下面的令牌由一长串随机字符组成:
但是,仔细分析后发现,其中仅包含十六进制字符。猜想这个字符串可能是一个经过十六进制编码的ASCII字符串,我们使用解码器对其解码,发现它实际是:
攻击者可以利用这个会话令牌的含义猜测其他应用程序用户的当前会话。使用一组枚举出的用户名或常见用户名,就能够迅速生成大量可能有效的令牌,并进行测试以确定它们是否有效。
包含有含义数据的令牌通常表现出某种结构。也就是说,它们由几种成分组成,通常以分隔符隔开,攻击者可分别提取并分析这些成分,以了解它们的功能和生成方法。结构化令牌的组成成分包括以下几项。
账户用户名。
应用程序用来区分账户的数字标识符。
用户姓名中的名/姓。
用户的电子邮件地址。
用户在应用程序中所属的组或扮演的角色。
日期/时间戳。
一个递增或可预测的数字。
客户端的IP地址。
为特意对其内容进行模糊处理,或者只是为了确保二进制数据能通过HTTP安全传输,应用程序会对结构化令牌中的每个不同成分或整个令牌以不同方式进行编码。常用的编码方案包括XOR、Base64和使用ASCII字符的十六进制表示法(请参阅第3章了解相关内容)。为将其恢复到原始状态,可能有必要对结构化令牌的每一个成分使用各种不同的解码方法。
注解
当处理包含结构化令牌的请求时,应用程序可能不会处理令牌中的每一个成分或每个成分中的所有数据。在前面的示例中,应用程序可能会对令牌进行Base64解码,然后只处理其中的“用户”(user)和“日期”(date)成分。如果令牌中包含一个二进制巨对象,那么这些数据中的大部分为填充数据,只有一小部分数据与服务器在令牌上执行的确认有关。减少令牌中确实必需的成分的数量通常可显著降低令牌的复杂程度。