Web应用程序对其数据采用几种不同的编码方案。在早期阶段,HTTP协议和HTML语言都是基于文本的,于是人们设计出不同的编码方案,确保这些机制能够安全处理不常见的字符和二进制数据。攻击Web应用程序通常需要使用相关方案对数据进行编码,确保应用程序按照想要的方式对其进行处理。而且,在许多情况下,攻击者甚至能够控制应用程序所使用的编码方案,造成其设计人员无法预料的行为。
URL只允许使用US-ASCII字符集中的可打印字符(也就是ASCII代码在0x20 ~ 0x7e范围内的字符)。而且,由于其在URL方案或HTTP协议内具有特殊含义,这个范围内的一些字符也不能用在URL中。
URL编码方案主要用于对扩展ASCII字符集中的任何有问题的字符进行编码,使其可通过HTTP安全传输。任何URL编码的字符都以%为前缀,其后是这个字符的两位十六进制ASCII代码。以下是一些常见的URL编码字符:
%3d代表=;
%25代表%;
%20代表空格;
%0a代表新行;
%00代表空字节。
另一个值得注意的编码字符是加号(+),它代表URL编码的空格(除%20代表空格外)。
注解
当攻击Web应用程序时,如果需要将以下字符当做数据插入HTTP请求中,渗透测试员必须对它们进行URL编码。
空格 % ? & = ; + #
(当然,当修改请求时,往往需要使用这些字符的特殊含义,例如,给查询字符串添加另外一个请求参数。这时应使用这些字符的字面量形式。)
Unicode是一种为支持全世界所使用的各种编写系统而设计的字符编码标准,它采用各种编码方案,其中一些可用于表示Web应用程序中的不常见字符。
16位Unicode编码的工作原理与URL编码类似。为通过HTTP进行传输,16位Unicode编码的字符以%u为前缀,其后是这个字符的十六进制Unicode码点。例如:
%u2215代表/;
%u00e9代表é。
UTF-8是一种长度可变的编码标准,它使用一个或几个字节表示每个字符。为通过HTTP进行传输,UTF-8编码的多字节字符以%为前缀,其后用十六进制表示每个字节。例如:
%c2%a9代表©;
%e2%89%a0代表≠。
攻击Web应用程序时之所以要用到Unicode编码,主要在于有时可用它来破坏输入确认机制。如果输入过滤阻止了某些恶意表达式,但随后处理输入的组件识别Unicode编码,就可以使用各种标准与畸形Unicode编码避开过滤。
HTML编码是一种用于表示问题字符以将其安全并入HTML文档的方案。有许多字符具有特殊的含义(如HTML内的元字符),并被用于定义文档结构而非其内容。为了安全使用这些字符并将其用在文档内容中,就必须对其进行HTML编码。
HTML编码定义了大量HTML实体来表示特殊的字面量字符,例如:
"代表”;
'代表’;
&代表&;
代表<;
代表>。
此外,任何字符都可以使用它的十进制ASCII码进行HTML编码,例如:
#39;代表’。
或者使用十六进制的ASCII码(以x为前缀),例如:
"代表”;
'代表’。
当攻击Web应用程序时,HTML编码主要在探查跨站点脚本漏洞时发挥作用。如果应用程序在响应中返回未被修改的用户输入,那么它可能易于受到攻击;但是,如果它对危险字符进行HTML编码,也许比较安全。请参阅第12章了解有关这些漏洞的更多详情。
Base64编码仅用一个可打印的ASCII字符就可安全转换任何二进制数据,它常用于对电子邮件附件进行编码,使其通过SMTP安全传输。它还可用于在基本HTTP验证机制中对用户证书进行编码。
Base64编码将输入数据转换成3个字节块。每个块被划分为4段,每段6个数据位。这6个数据位有64种不同的排列组合,因此每个段可使用一组64个字符表示。Base64编码使用以下字符集,其中只包含可打印的ASCII字符:
如果最后的输入数据块不能构成3段输出数据,就用一个或两个等号(=)补足输出。
例如,The Web Application Hacker’s Hand book 的Base64编码为:
许多Web应用程序利用Base64编码在cookie与其他参数中传送二进制数据,甚至用它打乱敏感数据以防止即使是细微的修改。应该总是留意并解码发送到客户端的任何Base64数据。由于这些数据使用特殊的字符集,而且有时会在字符串末尾添加补足字符(=),因此可以轻易辨别出Base64编码的字符串。
许多应用程序在传送二进制数据时直接使用十六进制编码,用ASCII字符表示十六进制数据块。例如,对cookie中的用户名daf进行十六进制编码,会得到以下结果:
646166
和Base64编码的数据一样,十六进制编码的数据通常也很容易辨认。为了解十六进制编码的功能应当对服务器发送到客户端的任何十六进制数据进行解码。
近些年出现了各种用于创建用户界面的框架,这些框架中的客户端代码可以远程访问服务器 端实施的编程API。利用这些框架,开发者可以在一定程度上忽略Web应用程序的分布式本质,而以与开发传统桌面应用程序类似的方式编写代码。这些框架通常提供客户端上使用的存根API。它们还能够自动处理以下两个任务:通过这些API远程调用相关服务器端功能,对传送给上述功能的任何数据进行序列化。
这类远程和序列化框架包括:
Flex和AMF;
Silverlight和WCF;
Java序列化对象。
我们将在第4章和第5章讨论使用这些框架的技巧以及由此引发的安全问题。