JSP安全开发之XSS漏洞详解

前言

大家好,好男人就是我,我就是好男人,我就是-0nise。在各大漏洞举报平台,我们时常会看到XSS漏洞。那么问题来了,为何会出现这种漏洞?出现这种漏洞应该怎么修复?

正文

1.XSS?XSS?XSS是什么鬼?

XSS又叫跨站脚本攻击(Cross Site Scripting),我不会告诉他原本是叫CSS的,但是为了不和我们所用的层叠样式表(Cascading Style Sheets)CSS搞混。CSS(跨站脚本攻击),CSS(层叠样式表)傻傻分不清。所以就叫XSS咯。

2.XSS的危害是什么?

实验一:

0x00构造代码

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
 <head>
 <base href="<%=basePath%>">
 <title>My JSP 'index.jsp' starting page</title>
  <meta http-equiv="pragma" content="no-cache">
  <meta http-equiv="cache-control" content="no-cache">
  <meta http-equiv="expires" content="0">
  <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
  <meta http-equiv="description" content="This is my page">
 </head>
 <body>
 <div style="margin: 0 auto">
 <%
//设置编码
   request.setCharacterEncoding("UTF-8");
//接收用户传入值
   String tmp = request.getParameter("opr");
   //减速传入值是否为空
   if(tmp == null){
     out.print("111");
   }else{
     //转码
     String opr = new String(tmp.getBytes("ISO-8859-1"),"utf-8");
     out.print(opr);
   }
 %>
   我是内容
 </div>
 </body>
</html>

0x01环境布局

0x02漏洞演练

我们访问:http://localhost:8080/XSS/index.jsp?opr=i%E6%98%A5%E7%A7%8B

然后访问:http://localhost:8080/XSS/index.jsp?opr=0nise

最后我们发现了一个“伟大的规律”:

opr参数等于什么页面就打印什么。(好像是废话)

我们接着来加载一个图片看看

访问:http://localhost:8080/XSS/index.jsp?opr=%3Cimg%20src=%221.png%22%3E%3C/img%3E

既然图片都可以加载,那么我们JS文件是不是也阔以加载呢?

访问:http://localhost:8080/XSS/index.jsp?opr=%3Cscript%3Ealert(/i%E6%98%A5%E7%A7%8B%E7%A4%BE%E5%8C%BA%E6%AC%A2%E8%BF%8E%E5%A4%A7%E5%AE%B6/)%3C/script%3E

Js?Js?那么是不是可以来改变跳转后地址?

访问:http://localhost:8080/XSS/index.jsp?opr=%3Cscript%3Elocation.href=%27http://bbs.ichunqiu.com%27%3C/script%3E

既然xss都可以加载js,那么,我们是不是通过js来打开本地的某些东西?

提前放了一个MD5.exe文件

访问:http://localhost:8080/XSS/index.jsp?opr=<script> var objShell = new ActiveXObject("wscript.shell");objShell.Run("G:/work/XSS/WebRoot/Md5.exe");</script>

既然连本地文件都可以打开那么远程文件木马?来个电脑恶搞?这个自己慢慢象限。我可没说啊。。。。。

文件都可以打开,那么写一些文件呢?

访问:http://localhost:8080/XSS/index.jsp?opr=%3Cscript%3Evar%20fso,tf;fso%20=%20new%20ActiveXObject(%22Scripting.FileSystemObject%22);tf%20=%20fso.CreateTextFile(%22d:\\test.txt%22,true);tf.WriteLine(%22i%E6%98%A5%E7%A7%8B%E7%A4%BE%E5%8C%BA%E6%AC%A2%E8%BF%8E%E6%82%A8%22);tf.Close();alert(%22%E6%96%87%E4%BB%B6%E5%86%99%E5%85%A5%E6%88%90%E5%8A%9F%EF%BC%81%22);%3C/script%3E

通过以上实验我们可以看出opr参数赋值操作。如果opr参数没有值的话,就无法执行执行,被攻击者必须访问攻击者提前设计好的才能攻击。这种XSS攻击方式叫做:存储型XSS

如果你想看到更给力的实验,请接着往下看。

实验二:

前言:

大部分网站都会和数据打交道那么,XSS漏洞出现这些网站是什么样子的?

0x00构造代码

数据库部分

BaseDao.java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class BaseDAO {
  //打开连接
  public Connection getConn(){
    Connection conn = null;
    try {
      Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
      conn = DriverManager.getConnection("jdbc:sqlserver://localhost:1433;databaseName=SQLTMP","sa","sa");
    } catch (ClassNotFoundException e) {
      e.printStackTrace();
    } catch (SQLException e) {
      e.printStackTrace();
    }

    return conn;
  }

  //关闭链接的方法
  public void closeAll(Connection conn,Statement stat,ResultSet rs){
    try {
      if(rs != null)
        rs.close();
      if(stat != null)
        stat.close();
      if(conn != null)
        conn.close();

    } catch (SQLException e) {
      e.printStackTrace();
    }
  }
  //重载关闭方法
  public void closeAll(Connection conn,PreparedStatement pstat,ResultSet rs){
    try {
      if(rs != null)
        rs.close();
      if(pstat != null)
        pstat.close();
      if(conn != null)
        conn.close();

    } catch (SQLException e) {
      e.printStackTrace();
    }
  }
  //继续重载
  public void closeAll(Connection conn,PreparedStatement pstat){
    try {
      if(pstat != null)
        pstat.close();
      if(conn != null)
        conn.close();
    } catch (SQLException e) {
      e.printStackTrace();
    }
  }
  //增删改的公用方法
  public int upDate(String sql,Object[] pram){

    PreparedStatement pstat = null;
    Connection conn = null;
    int a = 0;

    try {
      conn = getConn();
      pstat =conn.prepareStatement(sql);
      //遍历参数集合,将集合中的参数对应添加到sql语句中
      for (int i = 1; i <= pram.length; i++) {
        pstat.setObject(i, pram[i-1]);
      }
      //调用方法
      a = pstat.executeUpdate();

    } catch (SQLException e) {
      e.printStackTrace();
    }finally{
      closeAll(conn, pstat);
    }
    return a;
  }
}

CommentDao.java

import java.sql.*;
import java.util.*;
import entity.*;
public class CommentDao extends BaseDAO {
  /**
   * 获取所有留言
   * */
  public List<comm> GetComment(){
    //SQL语句
    String sql = "SELECT CID,CName,CContext FROM Comments";
    List<comm> list = new ArrayList<comm>();
    //数据库连接对象
    Connection conn = null;
    //SQL执行对象
    PreparedStatement pstmt = null;
    //数据库执行返回值
    ResultSet rs = null;
    try {
      //创建数据库链接
      conn = this.getConn();
      //创建SQL执行对象
      pstmt = conn.prepareStatement(sql);
      //执行SQL语句  返回值
      rs = pstmt.executeQuery();
      //读取
      while (rs.next()) {
        comm comment = new comm();
        comment.setCID(rs.getInt("CID"));
        comment.setCName(rs.getString("CName"));
        comment.setCContext(rs.getString("CContext"));
        list.add(comment);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }finally{
      //关闭
      this.closeAll(conn, pstmt, rs);
    }
    return list;
  }
  public int AddComment(comm comment){
    String sql = "INSERT INTO Comments VALUES(?,?)";
    //受影响行数
    int result = 0;
    //数据库连接对象
    Connection conn = null;
    //SQL执行对象
    PreparedStatement pstmt = null;
    try {
      //创建数据库链接
      conn = this.getConn();
      //创建SQL执行对象
      pstmt = conn.prepareStatement(sql);
      //设置参数
      pstmt.setString(1, comment.getCName());
      pstmt.setString(2, comment.getCContext());
      //执行SQL语句
      result = pstmt.executeUpdate();
    } catch (Exception e) {
      e.printStackTrace();
    }finally{
      this.closeAll(conn, pstmt);
    }
    return result;
  }
}

CommentServlvet

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import entity.*;
public class CommentServlvet extends HttpServlet {
  /**
   * doGet()
   */
  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    request.setCharacterEncoding("UTF-8");
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();
    String opr = request.getParameter("opr");
    CommentDao commentDao = new CommentDao();
    //检索参数是否为空
    if(opr == null || opr.equals("all")){
      request.setAttribute("all", commentDao.GetComment());
      //转发
      request.getRequestDispatcher("comment.jsp").forward(request, response);
    }else if (opr.equals("add")){
      comm comment = new comm();
      comment.setCName(request.getParameter("UName"));
      comment.setCContext(request.getParameter("context"));
      if(commentDao.AddComment(comment) > 0){
        out.print("<script>alert('留言成功');location.href='CommentServlvet?opr=all';</script>");
      }else{
        out.print("<script>alert('留言失败');location.href='CommentServlvet?opr=all';</script>");
      }
    }else{
      request.setAttribute("all", commentDao.GetComment());
      //转发
      request.getRequestDispatcher("comment.jsp").forward(request, response);
    }
    out.flush();
    out.close();
  }

  /**
   * doPost()
   */
  public void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    doGet(request, response);
  }
}

Comment.jsp

<%@ page language="java" import="java.util.*,entity.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
 <head>
 <base href="<%=basePath%>">
 <title>My JSP 'comment.jsp' starting page</title>
  <meta http-equiv="pragma" content="no-cache">
  <meta http-equiv="cache-control" content="no-cache">
  <meta http-equiv="expires" content="0">
  <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
  <meta http-equiv="description" content="This is my page">
 </head>
 <body>
 <%
   request.setCharacterEncoding("UTF-8");
   if(request.getAttribute("all") == null){
     request.getRequestDispatcher("CommentServlvet?opr=all").forward(request, response);
   }
 %>
 <table>
 <%
   List<entity.comm> list = (List<entity.comm>)request.getAttribute("all");
    for(int i = 0; i < list.size(); i++ ){
 %>
     <tr>
     <td><%=list.get(i).getCName() %></td>
     <td><%=list.get(i).getCContext() %></td>
     </tr>
     <%
   }
 %>
 </table>
 <form action="CommentServlvet?opr=add" method="post">
   <textarea rows="5" cols="30" name="context"></textarea>
   昵称:<input type="text" name="UName" />
   <input type="submit" value="提交" />
 </form>
 </body>
</html>

0x01漏洞实验

root@1~#

我们在留言板留言:

<script> var objShell = new ActiveXObject("wscript.shell");objShell.Run("G:/work/XSS/WebRoot/Md5.exe");</script>

然后访问:http://localhost:8080/XSS/comment.jsp

这样只要访问这个页面,软件就自动打开了,来个远程文件?慢慢领悟。

root@2~#

我们在留言板留言:

代码如下:

<script>var fso,tf;fso = new ActiveXObject("Scripting.FileSystemObject");tf = fso.CreateTextFile("d:\\test.txt",true);tf.WriteLine("i春秋社区欢迎您");tf.Close();alert("文件写入成功!");</script>

然后访问: http://localhost:8080/XSS/comment.jsp

文件写入成功。

root@3~#

留言内容:

[code]<script>location.href='http://bbs.ichunqiu.com'</script>[code]

访问页面:http://localhost:8080/XSS/comment.jsp

访问留言页面自动跳转到攻击者特定的网站。难道这就是传说中的劫持吗?

3.XSS防御方案

正所谓哪里有攻击,哪里就有防御。XSS一样,有攻击的方式,也有防御的方案。

EL表达式+JSTL标签库

EL(Expression Language):[size=12.0000pt]为了使JSP写起来更简单。表达式语言的灵感来自于ECMAScript和XPath表达式语语言,他提供了JSP中简化表达式的方法,让jsp代码更简单。

JSTL(JSP Standard Tag Library):开放源代码的JSP标签库。

实验一防御代码:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
 <head>
 <base href="<%=basePath%>">
 <title>My JSP 'index.jsp' starting page</title>
  <meta http-equiv="pragma" content="no-cache">
  <meta http-equiv="cache-control" content="no-cache">
  <meta http-equiv="expires" content="0">
  <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
  <meta http-equiv="description" content="This is my page">
 </head>
 <body>
 <div style="margin: 0 auto">
 <%
   request.setCharacterEncoding("UTF-8");
   String tmp = request.getParameter("opr");
   //减速传入值是否为空
   if(tmp == null){
     out.print("111");
   }else{
     //转码
     String opr = new String(tmp.getBytes("ISO-8859-1"),"utf-8");
     request.setAttribute("name", opr);
     %>
     <c:out value="${requestScope.name }"></c:out>
     <%
   }
 %>
   我是内容
 </div>
 </body>
</html>

实验二防御代码:

<%@ page language="java" import="java.util.*,entity.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
 <head>
 <base href="<%=basePath%>">
 <title>My JSP 'comment.jsp' starting page</title>
  <meta http-equiv="pragma" content="no-cache">
  <meta http-equiv="cache-control" content="no-cache">
  <meta http-equiv="expires" content="0">
  <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
  <meta http-equiv="description" content="This is my page">
 </head>
 <body>
 <%
   request.setCharacterEncoding("UTF-8");
   if(request.getAttribute("all") == null){
     request.getRequestDispatcher("CommentServlvet?opr=all").forward(request, response);
   }
 %>
 <table>
<!-- 防御XSS方案 -->
 <c:forEach var="x" items="${requestScope.all }">
 <tr>
   <td>
   <c:out value="${x.getCName() }"></c:out>
   </td>
   <td>
   <c:out value="${x.getCContext() }"></c:out>
   </td>
 </tr>
 </c:forEach>
 </table>
 <form action="CommentServlvet?opr=add" method="post">
   <textarea rows="5" cols="30" name="context"></textarea>
   昵称:<input type="text" name="UName" />
   <input type="submit" value="提交" />
 </form>
 </body>
</html>

结束语

技术无黑白,专研甚好。

(0)

相关推荐

  • JSP过滤器防止Xss漏洞的实现方法(分享)

    在用java进行web业务开发的时候,对于页面上接收到的参数,除了极少数是步可预知的内容外,大量的参数名和参数值都是不会出现触发Xss漏洞的字符.而通常为了避免Xss漏洞,都是开发人员各自在页面输出和数据入库等地方加上各种各样的encode方法来避免Xss问题.而由于开发人员的水平不一,加上在编写代码的过程中安全意识的差异,可能会粗心漏掉对用户输入内容进行encode处理.针对这种大量参数是不可能出现引起Xss和SQL注入漏洞的业务场景下,因此可以使用一个适用大多数业务场景的通用处理方法,牺牲少

  • JSP安全开发之XSS漏洞详解

    前言 大家好,好男人就是我,我就是好男人,我就是-0nise.在各大漏洞举报平台,我们时常会看到XSS漏洞.那么问题来了,为何会出现这种漏洞?出现这种漏洞应该怎么修复? 正文 1.XSS?XSS?XSS是什么鬼? XSS又叫跨站脚本攻击(Cross Site Scripting),我不会告诉他原本是叫CSS的,但是为了不和我们所用的层叠样式表(Cascading Style Sheets)CSS搞混.CSS(跨站脚本攻击),CSS(层叠样式表)傻傻分不清.所以就叫XSS咯. 2.XSS的危害是什

  • JSP 开发之Spring Security详解

    JSP 开发之Spring Security详解 前言: spring Security是一个能够为基于Spring的企业应用系统提供描述性安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC(依赖注入,也称控制反转)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作. Spring Security 的前身是 Acegi Security ,是 Spring 项

  • 前端开发之CSS原理详解

    前端开发之CSS原理详解 从事Web前端开发的人都与CSS打交道很多,有的人也许不知道CSS是怎么去工作的,写出来的CSS浏览器是怎么样去解析的呢?当这个成为我们提高CSS水平的一个瓶颈时,是否应该多了解一下呢? 一.浏览器的发展与CSS 网页浏览器主要通过 HTTP 协议连接网页服务器而取得网页, HTTP 容许网页浏览器送交资料到网页服务器并且获取网页.目前最常用的 HTTP 是 HTTP/1.1,这个协议在 RFC2616 中被完整定义.HTTP/1.1 有其一套 Internet Exp

  • Android开发之ImageLoader使用详解

    先给大家展示效果图,看看是大家想要的效果吗,如果还满意,请参考以下代码: 前言 UniversalImageLoader是用于加载图片的一个开源项目,在其项目介绍中是这么写的, •支持多线程图片加载 •提供丰富的细节配置,比如线程池大小,HTPP请求项,内存和磁盘缓存,图片显示时的参数配置等等: •提供双缓存 •支持加载过程的监听: •提供图片的个性化显示配置接口: •Widget支持(这个,个人觉得没必要写进来,不过尊重原文) 其他类似的项目也有很多,但这个作为github上著名的开源项目被广

  • Android编程开发之NotiFication用法详解

    本文实例讲述了Android编程开发之NotiFication用法.分享给大家供大家参考,具体如下: notification就是通知的意思,安卓中指通知栏,一般用在电话,短信,邮件,闹钟铃声,在手机的状态栏上就会出现一个小图标,提示用户处理这个快讯,这时手从上方滑动状态栏就可以展开并处理这个快讯. 在帮助文档中,是这么说的, notification类表示一个持久的通知,将提交给用户使用NotificationManager.已添加的Notification.Builder,使其更容易构建通知

  • iOS开发之widget实现详解

    前言     iOS extension的出现,方便了用户查看应用的服务,比如用户可以在Today的widgets中查看应用的简略信息,然后点击进入相关的应用界面. 暂且不表网络上现有的widget文章,本篇文章主要说明本人具体实现widget的步骤,希望能够帮助到需要实现widget的同行朋友. 文章将依次从以下几个问题着手,进行详细说明: 1.如何为现有的工程添加widget: 2.如何绘制UI: 3.如何调起app: 4.如何与host app共享数据. 添加Today Extension

  • Android 开发之旅:详解view的几种布局方式及实践

    引言 我们对Android应用程序运行原理及布局文件可谓有了比较深刻的认识和理解,并且用"Hello World!"程序来实践证明了.在继续深入Android开发之旅之前,有必要解决前两篇中没有介绍的遗留问题:View的几种布局显示方法,以后就不会在针对布局方面做过多的介绍.View的布局显示方式有下面几种:线性布局(Linear Layout).相对布局(Relative Layout).表格布局(Table Layout).网格视图(Grid View).标签布局(Tab Layo

  • 微信小程序开发之Tabbar实例详解

    微信小程序 Tabbar 1.下载微信小程序开发软件: https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/download.html?t=201714 2.扫描二维码登录,在手机点击确认登录 3.新建一个项目,这里选择无APPID,如果需要填写APPID,需要到微信小程序里面注册,然后就可以获取APPID,填写项目名称,选择项目目录(注释:微信小程序不会自己创建主目录文件,所以自己先建立一个项目文件夹,然后选择存放到这个文件夹中),添加项目,就

  • JSP中param动作的实例详解

    JSP中param动作的实例详解 一 语法 <jsp:param name="参数名" value="参数值"> 常常与<jsp:forward>一起使用,作为其子标签存在. 二 代码 1.login.jsp <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"

  • JSP中out对象的实例详解

    JSP中out对象的实例详解 一 什么是缓冲区 缓冲区:Buffer,所谓缓冲区就是内存的一块区域用来保存临时数据. 二 out对象 out对象是JspWrite类的实例,是向浏览器输出内容常用的对象. 三 常用方法 四 实例 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%> <% String path

随机推荐