19.3 Java 平台

本节主要介绍在Java平台上获取用户提交的输入的方法、与用户会话交互的方式、存在的潜在危险的API以及与安全相关的配置选项。

19.3.1 确定用户提交的数据

Java应用程序通过javax.servlet.http.HttpServletRequest接口获取用户提交的输入,该接口对javax.servlet.ServletRequest接口进行了扩展。这两个接口中包含了大量 Web应用程序用于访问用户提交的数据的API。表19-1列出的API可用于获取用户请求中的数据。

表19-1 Java平台中用于获取用户提交的数据的API

API 描 述
getParameter
getParameterNames
getParameterValues
getParameterMap
以String名称与String值之间映射的形式保存URL查询字符串与
POST请求主体中的参数,使用这些API可以访问该映射
getQueryString 返回请求中的整个查询字符串,可以它代替getParameter API
getHeader
getHeaders
getHeaderNames
以String名称与String值之间映射的形式保存请求中的HTTP消息头,使用这些API可以访问该映射
getRequestURI
getRequestURL
这些API返回请求中的URL,包括查询字符串
getCookies 返回Cookie对象的一个数组,其中包含请求所收到的cookie信息,包括
它们的名称与值
getRequestedSessionId 在某些情况下用来替代getCookies,返回在请求中提交的会话ID值
getInputStream
getReader
这些API返回客户端送出的原始请求的不同表示形式,因此可用于访问其
他所有API获得的任何信息
getMethod 返回HTTP请求所使用的方法
getProtocol 返回HTTP请求所使用的协议
getServerName 返回HTTP Host消息头的值
getRemoteUser
getUserPrincipal
如果当前用户通过验证,这些API返回用户的信息,包括登录名。如果用
户可以在自我注册过程中选择自己的用户名,这种做法可能会在应用程
序的处理过程中引入恶意输入

19.3.2 会话交互

Java平台应用程序使用javax.servlet.http.HttpSession接口保存和检索当前会话中的信息。每会话存储(per-session storage)是字符串名称与对象值之间的一个映射。表19-2列出的API用于保存和检索会话中的数据。

表19-2 Java平台中用于与用户会话交互的API

API 描 述
setAttribute
putValue
用于保存当前会话中的数据
getAttribute
getValue
getAttributeNames
getValueNames
用于查询保存在当前会话中的数据

19.3.3 潜在危险的API

这一节介绍一些常见的Java API。以危险的方式使用这些API可能会造成安全漏洞。

1.文件访问

在Java中,用于访问文件与目录的主要的类为java.io.File。从安全的角度看,这个类的最重要的用法是调用它的构造函数,该构造函数接受一个父目录和文件名,或者仅为一个路径名。

无论以哪种方式使用构造函数,如果未检查其中是否包含点-点-斜线序列就将用户可控制的数据作为文件名参数提交,那么可能会造成路径遍历漏洞。例如,下面的代码将打开Windows C:\驱动器根目录下的一个文件:

img549a

在Java中,常用于读取与写入文件内容的类包括:

img002 java.io.FileInputStream

img002 java.io.FileOutputStream

img002 java.io.FileReader

img002 java.io.FileWriter

这些类从它们的构造函数中提取File对象,或者通过文件名字符串打开文件。如果用户可控制的数据作为这个参数提交,同样可能会引入路径遍历漏洞。例如:

img549b

2.数据库访问

下面这些是常用于以SQL查询执行任何一个字符串的API:

img002 java.sql.Connection.createStatement

img002 java.sql.Statement.execute

img002 java.sql.Statement.executeQuery

如果用户提交的数据属于以查询执行的字符串的一部分,那么它可能易于受到SQL注入攻击。例如:

img549c

它执行不良查询:

img549d

下面的API更加稳定可靠,能够替代前面描述的API,允许应用程序创建一个预先编译的SQL语句,并以可靠且类型安全的方式指定它的参数占位符的值:

img002 java.sql.Connection.prepareStatement

img002 java.sql.PreparedStatement.setString

img002 java.sql.PreparedStatement.setInt

img002 java.sql.PreparedStatement.setBoolean

img002 java.sql.PreparedStatement.setObject

img002 java.sql.PreparedStatement.execute

img002 java.sql.PreparedStatement.executeQuery

当然还有许多,此处不一一列出。

如果按正常的方式使用,这些API就不易受到SQL注入攻击。例如:

img550a

它生成的查询等同于:

img550b

3.动态代码执行

Java 语言本身并不包含任何动态评估Java源代码的机制,尽管一些应用(主要在数据库产品中)提供了评估方法。如果所审查的应用程序动态构建任何Java代码,就应该了解应用程序如何构建这些代码,并决定用户可控制的数据是否以危险的方式使用。

4.OS命令执行

下面的API用于在Java应用程序中执行外部操作系统命令:

img002 java.lang.runtime.Runtime.getRuntime

img002 java.lang.runtime.Runtime.exec

如果提交给exec的字符串参数完全可由用户控制,那么几乎可以肯定应用程序易于受到任何命令执行攻击。例如,下面的代码将运行Windows calc程序:

img550c

然而,如果用户仅能够控制提交给exec的部分字符串,那么应用程序可能不易于受到攻击。在下面的示例中,用户可控制的数据以命令行参数的形式提交给记事本进程,引起它尝试加载| calc文档:

img550d

exec API本身并不解释&与|等shell元字符,因此这个攻击失败。

有时,仅控制部分字符串提交给exec仍然足以执行任意命令;例如下面这个稍微不同的示例(注意notepad后面缺少一个空格):

img551

通常,在这种情况下,应用程序将易于受到除代码执行以外的攻击。例如,如果应用程序以用户可控制的参数作为目标URL执行wget程序,那么攻击者就可以向wget进程传递危险的命令行参数,例如,致使它下载一个文档,并将该文档保存在文件系统中的任何位置。

5.URL重定向

下面的API用于在Java中发布HTTP重定向:

img002 javax.servlet.http.HttpServletResponse.sendRedirect

img002 javax.servlet.http.HttpServletResponse.setStatus

img002 javax.servlet.http.HttpServletResponse.addHeader

通常,使用sendRedirect方法可以引起一个重定向响应,该方法接受一个包含相对或绝对URL的字符串。如果这个字符串的值由用户控制,那么应用程序可能易于受到钓鱼攻击。

还应该审查setStatus与addHeader API的所有用法。如果某个重定向包含一个含有HTTP Location消息头的3xx响应,应用程序就可能使用这些API执行重定向。

6.套接字

java.net.Socket类从它的构造函数中提取与目标主机和端口有关的各种信息,如果用户能够以某种方式控制这些信息,攻击者就可以利用应用程序与任意主机建立网络连接,无论这些主机位于因特网上、私有DMZ中还是在应用程序上运行的内部网络内。

19.3.4 配置Java环境

web.xml文件包含Java平台环境的配置设置,同时它还控制着应用程序的行为。如果应用程序使用容器安全管理,那么验证与授权将在web.xml文件中,根据被保护的每一个资源或资源集,于应用程序代码以外声明。可在web.xml文件中设置的配置选项如表19-3所示。

表19-3 Java环境中与安全有关的配置设置

设 置 描 述
login-config login-config 元素配置验证细节
两类验证分别为forms-based (页面由form-login-page 元素指定)与在
auth-method元素中指定的Basic Auth或Client-Cert
如果使用基于表单的验证,指定的表单必须将操作定义为j_security_check,并必
须提交j_username与j_password参数。Java应用程序将把它当做一个登录请求处理
security-constraint 如果定义了login-config元素,就可以使用security-constraint元素限定资
源。这个元素可用于定义受保护的资源
在security-constraint元素中,可以使用url-pattern元素定义资源集。例如:
<url-pattern>/admin/*</url-pattern>
分别在role-name与principal-name元素中定义的角色与主要用户可以访问这些
资源
session-config session-timeout元素配置会话超时(单位:分钟)
error-page error-page元素定义应用程序如何处理错误。通过error-code与exceptiontype
元素可单独处理HTTP错误代码与Java异常
init-param init-param元素配置各种初始化参数。其中包括与安全有关的设置:

img002 listings应设置为false


img002 debug应设置为0

Servlet可以使用HttpServletRequest.isUserInRole访问Servlet代码中的相同角色信息,实施编程检查。映射项security-role-ref将内置的角色检查与对应的容器角色连接起来。

除web.xml文件外,不同应用程序服务器还可能使用包含其他安全相关设置的次要部署文件(如weblogic.xml文件),当分析环境配置时,应检查这些设置。