XSS全称是Cross Site Scripting(为了和CSS进行区分,就叫XSS)即跨站脚本,当目标网站目标用户浏览器渲染HTML文档的过程中,出现了不被预期的脚本指令并执行时,XSS就发生了
XSS有三类:反射型XSS(非持久型)、存储型XSS(持久型)和DOM XSS
发出请求时,XSS代码出现在URL中,作为输入提交到服务器端,服务器端解析后响应,XSS代码随响应内容一起传回给浏览器,最后浏览器解析执行XSS代码。这个过程像一次反射,所以称反射型XSS。
一个简单的例子:
echo $_GET['x'];
?>
如果输入x的值没有经过任何过滤直接输出,假设提交链接为:
http://www.foo.com/xss/reflect.php?x=
则alert()函数会在浏览器访问时触发
存储型XSS和反射型XSS的差别仅在于,提交的代码会存储在服务器端(数据库、内存、文件系统等),下次请求目标页面时不用再提交XSS代码。最典型的例子就是留言板XSS,用户提交一条包含XSS代码的留言存储到数据库,目标用户查看留言板时,那些留言就会从数据库中加载出来并显示,于是出发了XSS攻击
DOM XSS和反射型XSS、存储型XSS的区别在于DOM XSS代码并不需要服务器参与,出发XSS靠的是浏览器的DOM解析,完全是客户端的事情
www.xss.com/domxss.html 代码如下:
触发方式为:www.xss.com/domxss.html#alert(1) 这个URL#后的内容是不会发送到服务器端的,仅仅在客户端被接收并执行,常见的输入点有:
document.URL
document.URLUnencoded
document.localtion
document.referrer
window.location
window.name
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
My JSP 'xss_test.jsp' starting page
<%
String str = request.getParameter("name");
out.print(str);
%>
首先访问:http://localhost:8080/jsp/user/xss_test.jsp?name=小明
接着我们试着加载一个js脚本看看,访问:http://localhost:8080/jsp/user/xss_test.jsp?name=
上面我都是用的Firefox或者chrome,但是这个只能用IE,因为只有IE才有ActiveXObject这个对象,而且访问之前要去IE的Internet选项里把安全级别调成很低,具体来说就是各种设置全部启用
既然连本地文件都可以打开,那么远程木马,写入文件?自己想象…
大部分网站都会和数据库打交道,XSS漏洞如果出现在这些网站会怎么样?
user_insert.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
My JSP 'user_insert.jsp' starting page
输入用户信息
user_insert_action.jsp
<%@page import="java.sql.*"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
user_insert_action.jsp
<%
//1.获取请求参数
String username = request.getParameter("username");
String password = request.getParameter("password");
String name = request.getParameter("name");
String sex = request.getParameter("sex");
String classes = request.getParameter("classes");
String phone = request.getParameter("phone");
String email = request.getParameter("email");
String qq = request.getParameter("qq");
%>
<%
//2.向数据库插入数据
Connection conn = null;
PreparedStatement pstmt = null;
try {
//2.1 加载驱动类
Class.forName("com.mysql.jdbc.Driver");
//2.2 创建数据库连接
String url = "jdbc:mysql://localhost:3306/jsp?useUnicode = true & characterEncoding = UTF-8";
String userName = "root";
String pwd = "root";
conn = DriverManager.getConnection(url, userName, pwd);
//2.3 创建预处理声明
String sql = "insert into user" + "(username,password,name,sex,classes,phone,email,qq)"
+ "values(?,?,?,?,?,?,?,?)";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, username);
pstmt.setString(2, password);
pstmt.setString(3, name);
pstmt.setString(4, sex);
pstmt.setString(5, classes);
pstmt.setString(6, phone);
pstmt.setString(7, email);
pstmt.setString(8, qq);
//2.4 向数据库发送sql语句
int res = pstmt.executeUpdate();
out.println(res);
} catch (Exception e) {
e.printStackTrace();
} finally {
pstmt.close();
conn.close();
}
%>
user.jsp
<%@page import="cn.edu.wic.jsp.bean.User"%>
<%@page import="java.sql.DriverManager"%>
<%@page import="java.sql.ResultSet"%>
<%@page import="java.sql.PreparedStatement"%>
<%@page import="java.sql.Connection"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://"
+ request.getServerName() + ":" + request.getServerPort()
+ path + "/";
%>
JDBC
<%
List users = new ArrayList();
Connection conn = null;
PreparedStatement pstmt = null;//发送声明的对象
ResultSet rs = null;//返货结果集的对象
try {
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/jsp?useUnicode=true&characterEncoding=UTF-8";
String username = "root";
String password = "root";
conn = DriverManager.getConnection(url, username, password);
pstmt = conn.prepareStatement("select * from user");
rs = pstmt.executeQuery();
while (rs.next()) {
User user = new User();
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
user.setName(rs.getString("name"));
%>
<%= user.getId() + ","%>
<%= user.getUsername() + "," %>
<%= user.getPassword() + "," %>
<%= user.getName() %>
<%
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (pstmt != null) {
try {
pstmt.close();
} catch (Exception e) {
}
}
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
}
}
}
%>
用户从user_insert.jsp输入信息提交,然后跳转到user_insert_action.jsp,页面会显示数据库更改的条数信息,然后访问user.jsp查询数据库中的用户信息
首先在user_insert.jsp输入信息
提交后跳转到user_insert_action.jsp,页面显示1,说明用户信息成功插入数据库
最后,访问user.jsp,XSS注入成功
上面实验一进行的实验都可以在这上面利用,比方说写入文件,或者实现页面跳转
信息提交成功
然后访问user.jsp,首先弹框1,没问题,点击确定后,就直接跳转到baidu的网站去了
如果我把弹框的信息删掉,只保留跳转,产生的效果就是只要有用户访问到user.jsp页面,就立马跳转到百度去了,类似DNS劫持