您的位置:首页 > Web前端 > JavaScript

jsp页面安全问题

2013-04-25 15:33 357 查看
在做SSI架构的项目,其中有大量的jsp页面,关于jsp的安全性问题,主要体现在web工作目录的WEB-INF文件夹下,可以将页面保存在WEB-INF文件下,这样用户就不能访问该页面了。它为什么能体现安全性能,就好比小偷要偷东西,但是他根本看不到我有的东西,他肯定偷不成功。因此将jsp页面保存在WEB-INF文件下,可以提高页面的安全性。
但是放到该文件夹下后,可能会出现我们要访问的时候却也无法访问了,查了相关资料了解到,在Structs中每一个跳转都是通过一个action来处理的,处理完后forward到相对地址。如果想不通过action处理跳转,而是直接让WEB-INF/a.jsp跳转到WEB-INF/b.jsp页面,则使用相对地址/b.jsp,绝对地址/WEB-INF/b.jsp或者<%=request.getContext()=%>/WEB-INF/b.jsp,均跳转不成功,这是因为安全性在搞怪,放到WEB-INF文件下web容器是对外不可见的,我们看不到他的跳转路径,所以直接跳转不行,需要间接跳转,可要通过structs的action,他的跳转是一种间接跳转,其跳转地址是在web.xml里面配好的,访问的人看不到,具有安全性。如果没有structs难道就不能间接跳转,jsp页面就没有安全保障了吗?答案是否定的,因为structs的action的本质
还是一个servlet,所以可以通过servlet来做。
先在web.xml里面配置servlet和servlet mapping:
<servlet>
<servlet-name>goto</servlet-name>

<jsp-file>/WEB-INF/jsp/test.jsp</jsp-file>--要跳转到的页面

</servlet>

<servlet-mapping>

<servlet-name>goto</servlet-name>

<url-pattern>/test</url-pattern>

</servlet-mapping>

配置好了之后在jsp页面里用a就可以跳转了<a href="/工程名/test">测试页面跳转</a>--这里一定要“/工程名/test”

通过servlet跳转还是比较麻烦了,但是这样能保证JSP页面的安全性,想两全其美是比较难的了。

当然如果安全要求不高,那就可以做成很简单的了,直接把所有的jsp页面全部放在webRoot底下,在WebRoot下页面用户可以直接输入地址访问。

出了以上保证页面安全之外,jsp的安全隐患还有非置信用户输入。用户的输入可以通过多种途径到达服务端,有的甚至是伪装,为jsp用户提供的输入有:

请求URL参数部分
HTML表单通过post或get请求提交的数据 客户端临时保存的数据(cookie)
数据库查询 其他进程设置环境变量

这些输入问题的安全隐患在于,他们由服务器端的应用程序解释,攻击者可以修改输入的数据攻击服务器脆弱的部分,服务器的脆弱部分常常表现为一些数据访问点,这些数据由用户提供的限定词标识,或通过执行外部程序得到。

JSP能够调用保存在库里面的本地代码(通过JNI)以及执行外部命令。类Runtime提供了一个exec()方法。exec()方法把它的第一个参数视为一个需要在独立的进程中执行的命令行。如果这个命令字符串的某些部分必须从用户输入得到,则用户输入必须先进行过滤,确保系统所执行的命令和它们的参数都处于意料之内。即使命令字符串和用户输入没有任何关系,执行外部命令时仍旧必须进行必要的检查。在某些情况下,攻击者可能修改服务器的环境变量影响外部命令的执行。例如,修改path环境变量,让它指向一个恶意的程序,而这个恶意程序伪装成了exec()所调用程序的名字。为了避免这种危险,在进行任何外部调用之前显式地设置环境变量是一种较好的习惯。具体的设置方法是:在exec()调用中,把一个环境变量的数组作为第二个参数,数组中的元素必须是name=value格式。

当用户输入用来标识程序打开的任意类型的输入/输出流时,类似的问题也会出现。访问文件、数据库或其他网络连接时不应该依赖于未经检验的用户输入。另外,打开一个流之后,把用户输入直接发送给它是很不安全的。对于SQL查询来说这一点尤其突出。下面访问JDBC API的JSP代码片断很不安全,因为攻击者可以在他提交的输入中嵌入分隔命令的字符,从而达到执行危险命令的目的:

<%@ page import="java.sql.*" %> <!-- 这里加上一些打开SQL Server连接的代码 --> <% Statement stmt = connection.getStatement(); String query = "SELECT * FROM USER_RECORDS WHERE USER = " + request.getParameter("username"); ResultSet result = Statement.executeQuery(query); %>

如果username包含一个分号,例如:
http://server/db.jsp? username=joe;SELECT%20*%20FROM%20SYSTEM_RECORDS

一些版本的SQL Server会忽略整个查询,但还有一些版本的SQL Server将执行两个命令。如果是后者,攻击者就可以访问原本没有资格访问的数据库资源(假定Web服务器具有访问权限)。

进行适当的输入检验可以防止这类问题出现。

输入带来的安全隐患

进行输入检验,输入检验包括对来自外部数据源(非置信数据源,参见前面说明)的数据进行语法检查,有时还要进行语义检查。依赖于应用的关键程度和其他因素,作为输入检验结果而采取的动作可能是下面的一种或者多种:

忽略语法上不安全的成分
用安全的代码替换不安全的部分 中止使用受影响的代码
报告错误 激活一个入侵监测系统。

输入检验可以按照以下两种模式之一进行:列举不安全的字符并拒绝它们;定义一组安全的字符,然后排除和拒绝不安全的字符。这两种模式分别称为正向和反向输入过滤。一般地,正向输入过滤更简单和安全一些,因为许多时候,要列举出服务器端应用、客户端浏览器、Web服务器和操作系统可能误解的字符并不是一件容易的事情。

注意get请求和cookie中的敏感数据

就象CGI协议所定义的,把请求数据从客户端传输到服务器端最简单的方法是GET请求方法。使用GET请求方法时,输入数据附加到请求URL之后,格式如下:

URL[?name=value[&name=value[&...]]]

显然,对于传输敏感数据来说,这种编码方式是不合适的,因为通常情况下,整个URL和请求字符串都以明文方式通过通信通道。所有路由设备都可以和服务器一样记录这些信息。如果要在客户请求中传输敏感数据,我们应该使用POST方法,再加上一种合适的加密机制(例如,通过SSL连接)。从JSP引擎的角度来看,在很大程度上,使用哪种传输方法无关紧要,因为两者的处理方式一样。

在WWW的发展过程中,Netscape引入了Cookie的概念。Cookie是服务器保存到客户端的少量信息,服务器提取这些信息以维持会话状态或跟踪客户端浏览器的活动。JSP提供了一个response隐含对象的addCookie()方法,用来在客户端设置Cookie;提供了一个request()对象的getCookie()方法,用来提取Cookie的内容。Cookie是javax.servlet.http.Cookie类的实例。由于两个原因,如果把敏感数据保存到Cookie,安全受到了威胁:第一,Cookie的全部内容对客户端来说都是可见的;第二,虽然浏览器一般不提供伪造Cookie的能力,但没有任何东西能够阻止用户用完全伪造的Cookie应答服务器。

一般而言,任何客户端浏览器提交的信息都不可以假定为绝对安全。

通过嵌入标记实现的攻击

CERT Advisory CA-2000-02描述了客户在请求中嵌入恶意HTML标记的问题。这个问题一般被称为“cross site scripting”问题,但它的名字有些用词不当,因为它不仅仅和脚本有关,同时,它和“跨越网站”(cross site)也没有什么特别的关系。不过,这个名字出现时,问题还没有被人们广泛了解。

这种攻击通常包含一个由用户提交的病态脚本,或者包含恶意的HTML(或XML)标记,JSP引擎会把这些内容引入到动态生成的页面。这种攻击可能针对其他用户进行,也可能针对服务器,但后者不太常见。“cross site scripting”攻击的典型例子可以在论坛服务器上看到,因为这些服务器允许用户在自己提交的文章中嵌入格式化标记。通常,被滥用的标记是那些能够把代码嵌入到页面的标记,比如<SCRIPT>、<OBJECT>、<APPLET>和<EMBED>。另外还有一些标记也会带来危险,特别地,<FORM>可能被用于欺骗浏览者暴露敏感信息。下面是一个包含恶意标记的请求字符串的例子:
http://server/jsp_script.jsp?poster=evilhacker& message=<SCRIPT>evil_code</SCRIPT>

要防止出现这种问题当然要靠输入检查和输出过滤。这类检查必须在服务器端进行,不应依赖于客户端脚本(比如JavaScript),因为没有任何东西能够阻止用户逃避客户端检验过程。

下面的代码片断示范了如何在服务器端检查嵌入的标记:

<!-- HTML代码结束 --><% String message = request.getParameter("message"); message = message.replace (′<′,′_′); message = message.replace (′>′,′_′); message = message.replace (′"′,′_′); message = message.replace (′′′,′_′); message = message.replace (′%′,′_′); message
= message.replace (′;′,′_′); message = message.replace (′(′,′_′); message = message.replace (′)′,′_′); message = message.replace (′&′,′_′); message = message.replace (′+′,′_′); %><p>你提交的消息是:<hr/><tt><%= message %></tt><hr/></p><!-- 下面加上其他HTML代码 -->

由于要列举出所有不合法的字符比较困难,所以更安全的方法是进行正向过滤,即除了那些确实允许出现的字符之外(例如[A-Za-z0-9]),丢弃(或者转换)所有其他字符。

关于JavaBean的说明

JSP按照JavaBean规范描述的一系列约定,在JSP页面中快速、方便地访问可重用的组件(Java对象)。每个JavaBean组件封装了一些可以不依赖于调用环境而独立使用的数据和功能。Bean包含数据成员(属性),并通过Get和Set方法实现访问这些属性的标准API。

为快速初始化指定Bean的所有属性,JSP提供了一种快捷方式,即在查询字符串中提供name=value对,并让它匹配目标属性的名字。考虑下面这个使用Bean的例子(以XML格式显示):

<jsp:useBean id="myBasket" class="BasketBean"> <jsp:setProperty name="myBasket" property="*"/> <jsp:useBean> <html> <head><title>你的购物篮</title></head> <body> <p> 你已经把商品: <jsp::getProperty name="myBasket" property="newItem"/> 加入到购物篮 <br/> 金额是$ <jsp::getProperty
name="myBasket" property="balance"/> 准备 <a href="checkout.jsp">付款</a>

注意在setProperty方法调用中使用的通配符号“*”。这个符号指示JSP设置查询字符串中指定的所有属性的值。按照本意,这个脚本的调用方式如下:
http://server/addToBasket.jsp?newItem=ITEM0105342

正常情况下,HTML表单构造的查询字符串就是这种形式。但问题在于,没有任何东西能够防止用户设置balance属性:
http://server/addToBasket.jsp? newItem=ITEM0105342&balance=0

处理页面的<jsp:setProperty>标记时,JSP容器会把这个参数映射到Bean中具有同样名字的balance属性,并尝试把该属性设置为0。

为避免出现这种问题,JSP开发者必须在Bean的Set和Get方法中实现某种安全措施(Bean必须对属性进行强制的访问控制),同时,在使用<jsp:setProperty>的通配符时也应该小心谨慎。


实现上的漏洞与源代码安全

无论是哪一种JSP实现,在一定的阶段,它们的某些版本都会出现给系统带来危险的安全隐患,即使JSP开发者遵从了安全编程惯例也无济于事。例如,在Allaire的JRun的一个版本中,如果请求URL包含字符串“.jsp%00”作为JSP脚本扩展名的一部分,服务器不会忽略null字节,它会把页面视为一个静态的非JSP页面之类的东西。这样,服务器会请求操作系统打开该页面,而这时null字节却被忽略,结果提供给用户的是JSP页面的源代码而不是页面的执行结果。

类似地,Tomcat的一个版本也有一个安全隐患。只要请求类如下面的格式,它会让攻击者看到JSP页面的源代码:
http://server/page.js%2570

这里的骗局在于,%25是URL编码的“%”,而70是“p”的十六进制值。Web服务器不会调用JSP处理器(因为URL没有以“.jsp”结尾),但静态文件处理器会设法把URL映射到正确的文件名字(再一次解码URL)。

另外,许多Web服务器和JSP实现都带有示范脚本,这些示范脚本常常包含安全隐患。在把服务器部署到一个不无恶意的环境(即Internet)之前,禁止对所有这些脚本的访问有利于安全。

简而言之,JSP开发者应该清楚:在自己正在开发的平台上,当前有哪些安全隐患。订阅BUGTRAQ和所有供应商提供的邮件列表是跟踪这类信息的好方法。

JSP和任何其他强大的技术一样。如果要保证被部署系统的安全和可靠,应用JSP时必须小心谨慎。我们简要地讨论了JSP脚本中常常出现的代码和配置级安全问题,提出了降低由此带来的安全风险的建议。

参考博客:http://blog.csdn.net/csgoahead/article/details/5391549

http://wenku.baidu.com/view/4a7d9ff5f61fb7360b4c65be.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: