XSS(跨站脚本攻击)是常见的网络安全问题之一,如果不经常回顾很容易忘记知识点。查阅一些讲解文章或攻击案例的时候,心里总会想着我会了,手却很自动:不,你不会。
因此想写一个简单的XSS攻击例子,方便日后回顾。
下面是写一个简单的node服务,服务端会根据请求url的参数来决定页面的部分内容。
let http = require('http')
let url = require('url');
let app = http.createServer(function (request, response) {
let reqUrl = request.url
let urlObj = url.parse(reqUrl, true)
let queryObj = urlObj.query
function getParameter(key) {
return queryObj[key] || ''
}
// 服务端渲染
// html模板
var str = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XSS</title>
</head>
<body>
<input id="val" type="text" value="<%= getParameter("keyword") %>">
<button>搜索</button>
<div>
<a href="<%= getParameter("redirect") %>">点击链接</a>
</div>
</body>
</html>
`
let htmlstr = str.replace(/<%=(.+)%>/g, (_, $1) => {
let a = eval($1)
return a
})
response.writeHead(200)
response.write(htmlstr)
response.end()
})
app.listen(3000, function() {
console.log('3000 running')
})
// 访问http://localhost:3000/?keyword="><script>alert('XSS');</script>&redirect=javascript:alert('XSS');
正常情况下,我们是输入类似这样http://localhost:3000/?keyword=123
来访问。但是别有用心者可能会输入http://localhost:3000/?keyword="><script>alert('XSS');</script>&redirect=javascript:alert('XSS');
来,如果我们没有经过一些HTML转义、白名单过滤等方法来对参数进行处理,而是直接将参数拼接到html字符串模板上,那么就很容易被攻击者注入攻击脚本。
比如上面的例子,我们访问http://localhost:3000/?keyword="><script>alert('XSS');</script>&redirect=javascript:alert('XSS');
的时候,最终返回给浏览器的将会是
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XSS</title>
</head>
<body>
<input id="val" type="text" value=""><script>alert('XSS');</script>">
<button>搜索</button>
<div>
<a href="javascript:alert('XSS');">点击链接</a>
</div>
</body>
</html>
另外
HTML 5 中指定不执行由 innerHTML 插入的 <script>
标签,例如下面的例子是没有危险的。
const name = "John";
// assuming 'el' is an HTML DOM element
el.innerHTML = name; // harmless in this case
// ...
name = "<script>alert('I am John in an annoying alert!')</script>";
el.innerHTML = name; // harmless in this case
但是向下面这样做,依旧会有危险
const name = "<img src='x' οnerrοr='alert(1)'>";
el.innerHTML = name; // shows the alert