内容提要:通过介绍常见的具有JSP服务的操作系统的漏洞和JSP程序的漏洞,详细的阐述了JSP应用存在的安全性问题, 给出了相应的解决办法和建议。最后介绍了自己设计的基于JSP的在线图书管理系统所采取的安全措施。
关键词:JSP(Jackson Structured Programming,杰克逊结构程序设计技术) Java Servlet(是Java技术对CGI编程的回答) JavaBean(是描述Java的软件组件模型,有点类似于Microsoft的COM组件概念)
Research on the Security of JSP Applications Author name (Dep. Address+zip ) Abstracts: This article describes the problems of JSP Applications security in detail, by introducing the operation system providing the JSP service and JSP program, and gives the corresponding resolvents and advices . Last, this article shows the security methods in books database management system which author has designed. Subject words: JSP 、Java Servlet、JavaBean
JSP编程语言以其运行效率高、与平台无关、可扩展好、面向对象等特性得到了越来越广泛的应用,并迅速成为系统集成平台的主流技术之一。许多商家都开发出了各种各样的支持平台,如IBM(International Business Machines美国商用机器公司)公司的WebSphere、BEA公司的Web Logic等等,也有越来越多的网站开始将自己的平台架构在JSP 环境中。但是随之而来的也引发了一系列的安全漏洞问题,如源代码暴露、远程任意命令执行等。随着JSP 应用推广和普及,安全问题也会越来越多了。,目前已知并公开的关于JSP 的漏洞问题多达二、三十条。随着电子商务的出现,尤其是涉及资金支付和认证方面的电子商务,安全是第一要考虑的问题。下面对JSP的安全问题进行讨论。 第一章JSP的执行过程及其机制
JSP是Java Servlet 的扩展。它将Java(一种由Sun公司提出的,从C++发展而来的程序设计语言)脚本编写的动态部分嵌入到普通的HTML(Hypertext Markup Language, 超文本链接标示语言)或XML(Extensible Markup Language也是一种置标语言)网页中。一个完整的Web应用由三层构成:Web服务器,Servlet引擎和Jsp引擎。当Web应用程序服务器第一次收到JSP页面时,先由JSP引擎预处理并转换成Java Servlet,这个Servlet(Servlet为Web开发员提供了一个简单、一致的机制,来扩展Web服务器的功能,并且和已有的业务系统交互。)经过配置,可以处理对JSP页面的请求。虽然JSP和Servlet在功能上是等价的,但是,JSP的动态内容生成方法与Servlet的恰好相反。JSP是把Java代码嵌入到文档之中,而不是把文档嵌入到Java应用之中。 JSP在网络安全方面的优点: (1) JSP源程序不大可能被下载,特别是JavaBean程序完全可以放到不对外的目录中。 (2) 基于Java的,具有Java 的一切安全特性。
第二章JSP中存在的安全漏洞和解决方法
JSP把Java代码嵌入到HTML文档之中,为访问外部功能和可重用对象,JSP提供了一些用来和JavaBean组件交互的额外标记。特别地,为了便于动态生成内容和格式,JSP允许在标记之内嵌入其他标记,这些标记的语法和HTML标记相似。HTML语法属于JSP语法的一个子集(一个纯HTML文档是一个合法的JSP页面),但反过来不一定正确。特别地,为了便于动态生成内容和格式,JSP允许在标记之内嵌入其他标记。这些结构都增加了安全问题的复杂性。另外,JSP的体系结构相当复杂,其中包含许多相互协作的子系统。这些子系统之间的交互也是安全隐患的根源。 由于完全开放了对服务器资源的访问,从JSP页面转换得到的不安全的Servlet可能给服务器、服务器所在的网络和访问页面的客户机之中的任意一个或全体带来威胁,甚至通过Dodos或蠕虫分布式攻击,还可能影响到整个Internet(Interactive Network Analysis 交互式网络分析)。人们往往认为,Java作为一种强类型安全的、具有垃圾收集能力的、具有沙箱(Sandbox)机制的语言,它能够奇迹般地保证软件安全。而且事实上,许多在其他语言中存在的低层次安全问题,比如缓冲或堆溢出,很少给Java程序带来危害。然而,这并不意味着人们很难写出不安全的Java程序,特别是对编写Servlet来说。验证输入和控制对资源的访问是始终必须关注的问题。另外,JSP的体系结构相当复杂,其中包含许多相互协作的子系统。这些子系统之间的交互常常是安全隐患的根源。除此之外,虽然现在所有的JSP实现都围绕着Java,但JSP规范允许几乎所有其他语言扮演这个角色。这样,这些替代语言的安全问题也必须加以考虑。总之,在JSP系统中有很多产生安全漏洞的机会。下面将讨论最常见的一部分。
2.1 源代码及文件路径暴露 2.1.1 在HTTP请求中添加特殊字符后缀导致JSP源代码文件暴露 Unify eWave ServletExec 是Java/Java Servlet 引擎插件,主要用于 WEB 服务器.当一个 HTTP(Hypertext Transfer Protocol,超文本传输协议) 请求中添加下列字符之一,ServletExec 将返回 JSP 源代码文件。 %2E + %2B / %5C %20 %00。例如输入形如http://target/ jsp/file.jsp%2E的请求就会导致JSP源代码暴露。 受影响的系统有: Unify eWave ServletExec 3.0c、 Sun Solaris 8.0、Microsoft Windows 98、Microsoft Windows NT 4.0、 Microsoft Windows NT 2000、Linux kernel 2.3.x、IBM AIX 4.3.2、HP HP-UX 11.4 解决办法:可以配置一个默认的 servlet,并将它们映射到一个默认的 servlet。这样当收到一个未映射到某servlet 的 URL(Uniform Resource Locator,网页地址,是因特网上标准的资源的地址) 时,这个默认的servlet 就会被调用。用它来对请求进行处理。
2.1.2路径权限引起的文件JSP源代码暴露 大部分的JSP应用程序在当前目录下有一个WEB-INF目录,这个目录通常存放JavaBean编译后的class 文件,如果不给这个目录设置正常的权限, class文件有可能会暴露。如Apache1.3.中,如果程序在http://site.running.websphere/login.jsp,只要修改一下http://site.running.websphere/WEB-INF/,所有这个目录下以及其子目录中的class 文件就可以看到,还可下载到本机。因为Apache1.3.12默认的设置是可以读取目录的。这种class文件经过反编译以后,就能看见源文件了。 解决方法:将一些比较重要的目录如WEB-INF、classes等设置上访问的权限,不允许读取只允许执行。以Apache 下为例,可以在httpd.conf文件中添加一个目录WEB-INF并设置Deny from all等属性。 2.1.3 IE缓存JSP文件导致源代码暴露
如果浏览器设置“浏览网页时首先查看本地缓冲里的页面”,这对合法用户可加快浏览Web页面的速度,而对非法用户则提供了一个越权浏览的机会。因此对于重要的Web页面,必须禁止页面缓存,强制浏览器每次向Web服务器请求新页面。可使用下面脚本解决: <% response.setHeader(Pragma,No-cache); response.setHeader(Cache-Control,no-cache); response.setDateHeader(Expires, 0); String userName = (String) session.getAttribute(User); if (null == userName) { request.setAttribute(Error, Session has ended. Please login.); RequestDispatcher rd = request.getRequestDispatcher(login.jsp); rd.forward(request, response); } %> 或者 <HEAD> <META HTTP-EQUIV=Pragma CONTENT=no-cache> <META HTTP-EQUIV=Cache-Control CONTENT=no-cache> <META HTTP-EQUIV=Expires CONTENT=0> </HEAD> 上面代码的意思是:通过设置头信息和检查HttpSession中的用户名确保了浏览器不缓存页面。同时,如果用户没有登录,受保护的JSP页面将不会发送到浏览器,取而代之的将是登录页面login.jsp。实际应用中,如果要求特别高,还可以记录最后登录时间,即记录每个用户的最后登录时间。对于采用关系型数据库安全域来说,可以通过在某个表中加上lastLogin等字段轻松实现。此外,为了使代码更简练有效,一些冗余的代码可以剔除掉。比如把这些加强安全的代码写到一个单独的JSP页中,通过<jsp:include>标签在其他页面也可以引用。这样问题就可以比较简单地解决了。
2.1.4文件不存在引起的绝对路径暴露问题 微软IIS (Internet Information Server的缩写,微软公司的Web服务器)中有比较多的类似问题,如微软IIS5.0中的*.idc暴露绝对路径漏洞。同样的这些问题现在也出现在JSP环境中,这个漏洞暴露了web程序的绝对硬盘地址,再和其他漏洞结合就具有比较大的危害性了。由于负责JSP执行的相应的Servlet在处理异常的时候没有过滤掉这种情况。解决办法如下: 就是找到服务器软件的JSP执行映射Servlet文件(class 后缀的),将它用JAD软件反编译,得到源代码,在源代码中找到处理Exception的方法,将方法中的处理部分全部注释掉,将请求导向到一个自定义的出错页面中。
2. 2 程序脚本的安全漏洞和解决办法
2.2.1用户输入的命令参数引起的安全漏洞 类Runtime提供了一个exec()方法。exec()方法把它的第一个参数视为一个需要在独立的进程中执行的命令行。如果这个命令字符串的某些部分必须从用户输入得到,在某些情况下,攻击者可能会利用命令参数修改服务器的环境变量影响外部命令的执行。如 path环境变量。所以用户输入必须先进行过滤,在进行任何外部调用之前最好显式地设置环境变量。具体的设置方法是:在exec()调用中,把一个环境变量的数组作为第二个参数,数组中的元素必须是name=&#118alue格式。当用户输入用来标识程序打开的任意类型的输入/输出流时,类似的问题也会出现。访问文件、数据库或其他网络连接时都不应该依赖于未经检验的用户输入。输入检验可以按照以下两种模式之一进行:列举不安全的字符并拒绝它们;定义一组安全的字符,然后排除和拒绝不安全的字符。这两种模式分别称为正向和反向输入过滤。一般地,正向输入过滤更简单和安全一些,因为许多时候,要列举出服务器端应用、客户端浏览器、Web服务器和操作系统可能误解的字符并不是一件容易的事情。要在服务器端对用户输入进行正向过滤。
2.2.2关于JavaBean 的漏洞 JavaBeans包含数据成员(属性),通过Get和Set方法实现访问这些属性的标准API。 为快速初始化指定Bean的所有属性,JSP提供了一种快捷方式,即在查询字符串中提供name=&#118alue对,并让它匹配目标属性的名字。看下面使用Bean的例子 <jsp:useBean id=Basket class=BasketBean/> <jsp:setProperty name=Basket property=*/> 商品: <jsp:getProperty name=Basket property=newItem/> 加入到购物篮 <br/> 金额是$ <jsp:getProperty name=Basket property=balance/> 准备 <a href=checkout.jsp>付款</a> 注意在setProperty方法调用中使用的通配符号“*”。这个符号指示JSP设置查询字符串中指定的所有属性的值。根据本意,这个脚本的调用方式如: http://target/addToBasket.jsp?newItem=ITEM0105342 正常情况下,HTML表单构造的查询字符串就是这种形式。但是如果用户设置balance属性: http://target/addToBasket.jsp? newItem=ITEM0105342&balance=0 处理<jsp:setProperty>标记时,JSP容器会把这个参数映射到Bean中具有同样名字的balance属性,并尝试把它设置为0。所以JSP开发者必须在Bean中对属性进行强制的访问控制,同时,在使用<jsp:setProperty>的通配符时也应该谨慎。
2.2.3 GET请求和Cookie中的敏感数据 使用GET请求方法时,输入数据附加到请求URL之后,格式如下: URL[?name=&#118alue[&name=&#118alue[&...]]] 显然,对于传输敏感数据来说,这种编码方式是不合适的,因为通常情况下,整个URL和请求字符串都以明文方式通过通信通道。所有路由设备都可以和服务器一样记录这些信息。如果要在客户请求中传输敏感数据,应该使用POST方法,再加上一种合适的加密机制(例如,通过SSL连接)。同ASP( Acitve Server Pages活动服务器页面)一样,JSP也提供了Cookie的用法,它也能够带来安全问题,所以对一些重要的页面慎用Cookie。
2.2.4 嵌入标记引起的安全问题 客户在请求中嵌入恶意HTML标记,这种攻击通常包含一个由用户提交的病态脚本,或者包含恶意的HTML(或XML)标记,JSP引擎会把这些内容引入到动态生成的页面。这种攻击可能针对其他用户进行,也可能针对服务器。通常,被滥用的标记是那些能够把代码嵌入到页面的标记,比如<SCRIPT>、<OBJECT>、<APPLET>和<EMBED>等。特别,<FORM>可能被用于欺骗浏览者暴露敏感信息。下面是一个包含恶意标记的请求字符串 例:http://server/jsp_script.jsp?poster=evilhacker&message=<SCRIPT>evil_code</SCRIPT> 要防止出现这种问题要靠输入检查和输出过滤。这类检查必须在服务器端进行。下面的代码片断示范了如何在服务器端检查嵌入的标记: <% 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 ('+','_'); %>
2.3 因SQL(seque,是一种结构化数据库查询语言)语句引起的安全问题 在ASP存在“a or 1=1”的问题,在JSP中也有。解决的办法和ASP中相同,针对这种情况,如果数据库里存在一个名叫“Boy”的用户,那么在不知道密码的情况下至少有下面几种方法可以登录: 用户名:Boy 密码:' or 'a'='a 用户名:Tom 密码:' or 1=1/* 用户名:Tom' or 1=1/* 密码:(任意) 滤去空格和特殊字符即可解决。
2.4 session对象引起的安全问题 在JSP中提供session对象的用法, session对象是保存在服务器端的,session对象有生命周期,在这个时间间隔内,若用户离开了,tomcat并不能急时关闭该用户相关的sesssion对象。这样下一个用户可能不用登陆就能访问该系统了。解决办法:提供用户注销session对象的功能。
第三章 基于JSP的在线图书管理系统的安全措施
该在线图书管理系统分为前台和后台两大部分。前台提供在线查询、在线预借、在线续借、在线阅读,采用的是B/S模式,后台提供了图书管理的功能。包括工作人员信息管理,读者信息管理,图书信息管理、图书卡办理,图书的借、还等功能,采用C/S模式。该系统不仅面向在校的学生,还面向校外人员。对所有的用户都提供在线图书查询的功能,但是如果要预借、续借、阅读图书必须是该系统的读者才行。用户要成为该系统的读者必须办理图书卡。可以通过网上办理图书卡,也可以直接到图书馆去办理。下面介绍该图书系统采用的安全措施。 该系统采用的WEB服务器是j2sdk +Apache 1.3.27+tomcat 4.1 。数据库是SQL 7.0。因为tomcat版本较高所以没有上面的源代码路径暴露问题。我们主要从如下几个方面来保证系统的安全性。 (1) 用户授权认证:只有授权的用户才能访问系统。用户授权通过pass这个bean 进行验证,用户在输入用户名和密码进入系统后,就会得到一个session对象,而他在该次登录后的所有访问都与该session有关。所有的session对象由系统随机生成,记录有用户登录的IP(Internet Protocol, 网际协议)地址,进行的操作等。为安全起见,该系统还提供了用户注销session 的功能。为了防止用户绕过登陆页面,系统在重要的页面还检查用户是否登陆过并检验用户的操作权限,如果没有登陆或没有操作权限,将用户重定向到登陆页面。系统的后台数据库日志记录了所有登陆用户的用户名、IP地址,登陆时间,操作信息,权限,是否成功以及未成功登陆的密码等。该Bean还可以有效的阻止用户多次尝试登陆。见下面给出验证的流程和部分程序代码:
此主题相关图片如下:
screen.width-333)this.width=screen.width-333 border=0>
//过滤用户输入的部分代码 int j=0 for(int i=0; i<username.length()-1;i++) { //对用户输入的用户名正向过滤,只保留大小写英文字母、数字和“_” char tempchar[20],ch; ch=username.charAt(i); if(ch<’Z’&& ch>’A’|| ch<’z’&& ch>’a’|| ch<’9’&& ch>’0’||ch=’_’) tempchar[j++]=ch; } username=username.copy&#118alue(tempchar,0,j); //将过滤后的字符串赋给username
//登陆页面的部分代码 String Username=request.getParameter(Username).trim(); // 截去用户名前后的空格 String Passwd=request.getParameter(Password).trim(); // 截去密码前后的空格 s_psBean.setPass(Username,Passwd,(request.getRemoteAddr()).toString()) if(s_psBean.getPass()==1) //登陆成功 { %> <jsp:forward page=index.jsp/> <% } if(s_psBean.getNum()>=3) //超过登陆次数 { s_psBean.errorIp(); //记录不合法的IP out.println(<script language=&#106avascript>alert('您输入的密码超过三次,系统关闭!');</script>); out.close(); } //为防止用户绕过登陆页面而访问系统资源,在重要的页面进行验证 <jsp:useBean id=s_psBean class=permission.pass scope=session/> <%!static final private String AUTHSPEC=jsgl;%>//权限关键字 if(s_psBean.getPass()= =1&&s_psBean.getAuth(AUTHSPEC)= =1) //用户登陆过并且有该网页的操作权限 {…… // 用户注销代码 session.invalidate(); s_psBean.logout(); (2) 采用双系统,前台对外发布,使用B/S模式;后台主要对图书系统进行管理,为了安全,不将它挂在Internet上,采用C/S模式。 (3) 在本机上采用JDBC_ODBC桥和数据库连接。 (4) 安装防火墙,并且屏蔽数据库端口1433,有效的阻止了来自Internet上对数据的攻击。 (5) 防止IE(Internet Explorer微软公司出品的WEB浏览器)缓冲登陆页面在登陆页面设置方法如前文安全漏洞的第(4)条。 (6) 设置WEB_INF目录的访问权限,使之只能执行不能读和写。 【转自世纪安全网 http://www.21safe.com】
|