9.1 注入解释型语言

解释型语言(interpreted language)是一种在运行时由一个运行时组件(runtime component)解释语言代码并执行其中包含的指令的语言。与之相对,编译型语言(compiled language)是这样一种语言:它的代码在生成时转换成机器指令,然后在运行时直接由使用该语言的计算机处理器执行这些指令。

从理论上说,任何语言都可使用编译器或解释器来执行,这种区别并不是语言本身的内在特性。但是,通常大多数语言仅通过上述其中一种方式执行,开发Web应用程序使用的许多核心语言使用解释器执行,包括SQL、LDAP、Perl和PHP。

基于解释型语言的执行方式,产生了一系列叫做代码注入(code injection)的漏洞。任何有实际用途的应用程序都会收到用户提交的数据,对其进行处理并执行相应的操作。因此,由解释器处理的数据实际上是由程序员编写的代码和用户提交的数据共同组成的。有些时候,攻击者可 以提交专门设计的输入,通常提交某个在应用程序中使用解释型语言语法的具有特殊意义的句法,向应用程序实施攻击。结果,这个输入的一部分被解释成程序指令执行,好像它们是由最初的程序员编写的代码一样。因此,如果这种攻击取得成功,它将完全攻破目标应用程序的组件。

另一方面,在编译型语言中实施旨在执行任意命令的攻击往往非常困难。这时,注入代码的方法通常并不利用开发目标程序所使用语言的任何语法特性,注入的有效载荷为机器代码,而不是用那种语言编写的指令。请参阅第16章了解各种针对编译软件的常见攻击。

避开登录

无论访问操作是由普通用户还是应用程序管理员触发,应用程序访问数据存储区的过程都大致相同。Web应用程序对数据存储区实施自主访问控制,构造查询基于用户的账户和类型来检索、添加或修改数据存储区中的数据。修改查询(不只是查询中的数据)的成功注入攻击可以避开应用程序的自主访问控制并获取未授权访问。

如果需要安全保护的应用程序逻辑由查询结果控制,攻击者就可以通过修改查询来更改应用程序的逻辑。举一个典型的例子——在后端数据存储区的用户表中查询与用户提供的证书匹配的记录。许多实施基于表单的登录功能的应用程序使用数据库来存储用户证书,并执行简单的SQL查询来确认每次登录尝试。以下是一个典型的示例:

img232a

这个查询要求数据库检查用户表中的每一行,提取出每条username列值为marcus、password列值为secret的记录。如果应用程序收到一名用户的资料,登录尝试将取得成功,应用程序将为该用户建立一个通过验证的会话。

在这种情况下,攻击者可注入用户名或密码字段,以修改应用程序执行的查询,从而破坏它的逻辑。例如,如果攻击者知道应用程序管理员的用户名为admin,那么他就可以通过提交以下用户名和任意密码,以管理员身份登录:

img232b

应用程序将执行以下查询:

img232c

因为其中使用了注释符号(--),上面的查询等同于:

img232d

于是这个查询完全避开了密码检查。