实现 XSS 攻击简单示例
XSS 简例
CSRF与 XSS 攻击经常在公司安全检查中出现,部分项目组也会来找我询问如何解决。网上关于其概念的介绍很多,但终感觉纸上得来终觉浅,决定写一个简单的例子来运行一下来了解其攻击方式,来更深刻理解其危害。关于其概念,这篇文章 维基百科 XSS 有比较全面介绍,中文的访问不到,在这里不再赘述其内容,下面我们以一个简单的例子来实战一下 XSS 攻击。
一个贴吧例子
大家往发布帖子回复帖子看帖子,都很正常,但是有个人发了一段 js 代码,并且贴吧网站使用了有漏洞的代码去解析,那么就可以模仿人发贴。
构建项目所涉及项目
- spring boot
构建项目
- 初始化一个 spring boot 2 项目,项目名为 xss-blog
- 添加主要依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
- 查看帖子,发布帖子业务
@RestController
@RequestMapping("/blog")
public class BlogController {
/**
* 存放所有帖子
*/
private ArrayList<String> blogs = new ArrayList<>(10);
/**
* 查看帖子
* @return
*/
@GetMapping("/")
public ArrayList<String> showBlog(){
return blogs;
}
/**
* 发布帖子
* @param blogText
*/
@PostMapping("/")
public void postBolg(@RequestBody String blogText){
System.out.println(blogText);
blogs.add(blogText);
}
/**
* 清空帖子
*/
@DeleteMapping("/")
public void deleteBolg(){
blogs.clear();
}
}
- 帖子操作页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Blog</title>
<script src="jquery.js"></script>
<script>
/**
* 查看帖子
*/
function showBlogs(){
const xhr = new XMLHttpRequest();
xhr.open('GET','/blog/',true);
xhr.onreadystatechange =function(e){
if(this.readyState ==4&&this.status ==200){
let blogsDiv = document.getElementById("blogsDiv");
let blogs = JSON.parse(this.response);
let blogsShow = '';
for(let i=0; i<blogs.length; i++){
blogsShow += blogs[i] + "<br/>";
}
blogsDiv.innerHTML = "";
// 注意这里
$('#blogsDiv').append(blogsShow);
}
}
xhr.send();
}
/**
* 发布帖子
*/
function postBlog() {
var blogText = document.getElementById("blogText").value;
const xhr = new XMLHttpRequest();
xhr.open('POST','/blog/',true);
xhr.onreadystatechange =function(e){
if(this.readyState ==4&&this.status ==200){
alert('OK');
}
}
xhr.send(blogText);
}
/**
* 清空帖子
*/
function clearBlogs(){
const xhr = new XMLHttpRequest();
xhr.open('DELETE','/blog/',true);
xhr.onreadystatechange =function(e){
if(this.readyState ==4&&this.status ==200){
alert("OK");
}
}
xhr.send();
}
</script>
</head>
<body>
<button onclick="clearBlogs()">清空服务端博客</button>
<div>测试脚本 <script>alert('12')</script></div>
<br/>
<input type="text" id="blogText">
<button onclick="postBlog()">发表博客</button>
<br/>
<br/>
<button onclick="showBlogs()">查看博客</button>
<br/>
博客内容
<hr/>
<div id="blogsDiv">
</div>
</body>
</html>
成功攻击演示
- 启动项目
- 通过 http://127.0.0.1:8080 访问贴吧
- 输入 “博客内容1” 点击 发表博客,弹出提示点击确定
- 点击查看博客,正确显示博客内容
- 输入页面提示的测试脚本 <script>alert('12')</script> 点击发表博客,弹出提示点击确定
- 点击查看博客,则执行了输入的内容的脚本,若替换为发表博客或者转发博客的脚本,若是银行系统其危害自己去考虑吧。哈哈。
攻击防御
- 注意:防御此类攻击前后端都能实现,前后端应该都去实现,越安全越好。
- 前端防御以此项目为例,将页面 showBlogs 方法中的 $('#blogsDiv').append(blogsShow); 替换为 blogsDiv.innerHTML = blogsShow;
- 后端转义标签,例如将 "<" 转为 "< ;" 方式实现。所以有时候需要考虑是否要去如此实现,比如要生成html文件,那么这个转义就没啥必要了。用jsp去生成的时候要额外注意,生成的html会将此脚本看作自己的一部分。