19.8 数据库代码组件

如今,Web应用程序已不仅仅使用数据库实现数据存储。今天的数据库包含丰富的编程接口,可在数据库层执行大量的业务逻辑。开发者频繁使用数据库代码组件(如存储过程、触发器和用户定义的函数)完成各种关键任务。因此,当审查一个Web应用程序的源代码时,必须将数据库中执行的所有逻辑包括在审查范围之内。

数据库代码组件中的编程错误可能会导致本章描述的各种安全漏洞。但现实操作中应当留意两种主要的漏洞。首先,数据库组件自身可能包含SQL注入漏洞;其次,用户输入可能会以危险的方式提交给潜在危险的函数。

19.8.1 SQL注入

第9章介绍了如何使用预处理语句代替动态SQL语句,以防止SQL注入攻击。然而,即使在整个Web应用程序代码中正确使用预处理语句,如果数据库代码组件以危险的方式使用用户提交的输入构造查询,SQL注入漏洞也依然存在。

下面以一个@name参数易于受到SQL注入的存储过程为例:

img569

即使应用程序将用户提交的name值安全传送给存储过程,该过程本身也会直接把这个值连接到一个动态查询中,因此它易于受到攻击。

不同的数据库平台使用不同的方法动态执行包含SQL语句的字符串,如下所示。

img002 MS-SQL:EXEC

img002 Oracle:EXECUTE IMMEDIATE

img002 Sybase:EXEC

img002 DB2:EXEC SQL

应对出现在数据库代码组件中的这些表达式进行仔细审查。如果将用户提交的输入用于构建SQL字符串,应用程序可能易于受到SQL注入攻击。

img001  注解  在Oracle中,存储过程默认在定义者权限而非调用者权限下运行(与UNIX中的SUID程序相同)。因此,如果应用程序使用一个低权限账户访问数据库,并且使用DBA账户建立存储过程,那么攻击者就可以利用某个过程中存在的SQL注入漏洞提升自己的权限,并执行任意数据库查询。

19.8.2 调用危险的函数

存储过程之类的定制代码组件常用于执行不常见的或功能强大的操作。如果以不安全的方式向一个潜在危险的函数传送用户提交的数据,那么根据该函数的功能,这样做可能会导致各种类型的漏洞。例如,下面的存储过程的@loadfile与@loaddir参数就易于受到命令注入攻击。

img570

如果以不安全的方式调用,下面的函数可能造成危险。

img002 MS-SQL与Sybase中功能强大的存储过程,使用它们可执行命令或访问注册表等。

img002 用于访问文件系统的函数。

img002 连接到数据库以外的库的用户定义的函数。

img002 可访问网络的函数;例如,通过MS-SQL中的OpenRowSet或Oracle中的数据库链接。