介绍一下 Web
端相关的攻击手法及原理,包括但不限于 前端
后端
运维
javascript
本文后端语言将使用PHP
,由于通过对比,PHP
做为后端代码演示,是最显而易见的。php
以及本文介绍的全部攻击手法都将提供Docker
靶场,方便后续你们自行研究、测试。html
此篇文章是由我以前写的安全文章进行了部分汇总、优化及添加。若是你们比较感兴趣,能够去Freebuf Black-Hole看我以前写的文章。前端
XSS
本质就是在别人的浏览器里执行你的JavaScript
代码,其余都是一种辅助手段。java
利用JavaScript操做DOM的特性,来作到攻击git
常常出现的状况:先后端分离架构github
不少开发者,都知道不到万不得已不要使用eval
函数,不使用的缘由其中一点就是不安全,可是难道不使用eval
就不会有安全问题么?答案是否认的。web
见下面的代码:sql
<script>
window.open(new URL(location.hash.slice(1)).href)
</script>复制代码
为了更好的说明,我这里简单的把做用说明一下:docker
假设当前url为
http://baidu.com/#http://360.cn
,那么location.hash.slice(1)
的结果就是http://360.cn
new URL(url).href
则是会对url进行解析,并取出解析后的url。若是你的url不知足它内部的判断,则会报错。
是否是以为这段代码没什么问题。毕竟有new URL()
这种浏览器内置函数帮咱们作了过滤。
OK,那咱们就要去攻破这个函数的判断。下图为URL
接口规范中的列表:
咱们能够看到hello:world
是符合规范的。并且hello:
正好又是JavaScript
里的标记
,相似于C语言中的goto
。那咱们更改url为: http://baidu.com/#javascript:alert(1)
。则会成功触发漏洞。
DOM XSS
也属于反射型 XSS
,通常而言统称都叫反射 XSS
,只有当须要划分比较细时,才会分开来。
由于前/后端没有作好相对应的过滤,致使的问题
常常出现的状况:MVC架构
由于像MVC
这种架构,实际上是在后端语言中编写前端代码,在访问url的时候,会先由后端根据请求去构造前端页面,再返回前端源码到浏览器端,而这个过程当中,若是出现了XSS漏洞,又由于后端参与其中,因此咱们通常认为这是反射型XSS
。
见下面的 PHP 代码:
<?php
// 关闭浏览器的XSS检测机制
header("X-XSS-Protection: 0;");
$bg = $_GET['bg'];
if (empty($bg)) {
$bg = '999';
}
echo "<div style='width: 120px; height: 120px; background-color:#$bg'>我是一只小方块</div>";
?>复制代码
能够看到,这段代码将会获取url参数中的bg
来获取背景颜色。乍一看,好像没什么问题。可是要知道其中$bg
是可控的。那咱们只须要把里面的标签闭合掉就行。见下面:
http://127.0.0.1:8082/?bg=123' onclick='alert(1)
上面的代码放在bg
参数里,那代码就变成了
<div style='width: 120px; height: 120px; background-color:#123' onclick='alert(1)
'>我是一只小方块</div>
在反射XSS的基础上,作了一步 入库的操做
见下面的代码:
// 获取客户端的IP地址
// 此段代码来之:https://stackoverflow.com/questions/3003145/how-to-get-the-client-ip-address-in-php
$ipaddress = 'UNKNOWN';
$keys = array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR');
foreach($keys as $k) {
if (isset($_SERVER[$k]) && !empty($_SERVER[$k])) {
$ipaddress = $_SERVER[$k];
break;
}
}
// 获取内容,并对内容作编码过滤
$content = htmlspecialchars($_POST['content'], ENT_QUOTES);
$sql = "INSERT INTO xss.message (content, ip) VALUES ('$content', '$ipaddress')";
$conn->query($sql);复制代码
这段代码看起来是没有任何问题的,由于咱们已经对content
参数作了进一步的编码过滤。
htmlspecialchars(string,ENT_QUOTES)
此方法的编码规则为:
&
编码为&
"
编码为"
'
编码为'
<
编码为<
>
编码为>
那即便咱们写入了HTML标签等代码,也会被转码,假如咱们提交的内容为<script>alert(1)</script>
那在数据库的里表现就会变成: <script>alert(1)</script>
那难道没有办法绕过去么?答案固然是能够。
能够看到,这段代码不止把内容入库了,还把用户的IP也入库了。那问题就出现了,CLIENT-IP
、X_FORWARDED_FOR
是用户可控的。只须要安装 ModHeader 这个浏览器插件便可如图:
修改后,再去从新提交一次,就会发现已经成功入库了,如图:
CSRF能够理解为是一种借刀杀人的手法,通常出如今表单提交里。最多见的是出现的开源项目里,好比各种CMS。
<form method="post" action="addAdminUser.php">
<div class="input-group">
<label for="username">要添加的管理员帐号: </label>
<input type="input" name="username">
</div>
<div class="input-group">
<label for="password">要添加的管理员密码: </label>
<input type="password" name="password">
</div>
<div class="input-group">
<button type="submit">添加</button>
</div>
</form>复制代码
见上面代码,此代码存在于管理员后台里。用于添加管理员帐号。而且 addAdminUser.php
里是有对当前用户的 Cookies
作了校验,非管理员帐户不能添加。
可是这个表单里没有 验证码
、Token
,以及 addAdminUser.php
里没有作 referer
来源校验。
就会出现 CSRF
漏洞。
由于浏览器发现你请求了某个资源后,会自动把你未过时的 Cookies
加入到请求头里。也就是说,即便是在其余网站里,发送了添加管理员的请求,会自动把你登录后的 Cookies
加入到请求里,服务端会认为是你本人触发的(由于 Cookies
校验成功)
至于为何这里 Cors
没有起到做用,是由于这种方式,请求后是拿不到任何返回信息的,因此 Cors
并不会拦截。若是你使用 Ajax
来请求,是确定会被拦截掉,由于 Ajax
请求是能够拿到返回信息,全部会被 Cors
拦截掉。
那除了 form
标签,还有什么方法能够进行攻击呢?在 w3c cors
规范中,有这么一句话:
A simple cross-origin request has been defined as congruent with those which may be generated by currently deployed user agents that do not conform to this specification. Simple cross-origin requests generated outside this specification (such as cross-origin form submissions using
GET
orPOST
or cross-originGET
requests resulting fromscript
elements) typically include user credentials, so resources conforming to this specification must always be prepared to expect simple cross-origin requests with credentials.----详情可见 w3c cors
这里没有说的特别细,我补充了一下,大体意思是说,使用 GET
或 POST
进行表单提交时,亦或者使用一些 HTML
标签引发的 GET
请求,如:a
、img
等,基本上都会携带用户凭据(Cookies)
SSRF
本质其实和 CSRF
相差不大。只是 CSRF
面向的是客户端的用户,而 SSRF
面向的是服务端自己。
这种漏洞通常出现于:会访问并返回用户可控的资源的功能上。
例如:在线查看网站源码
、获取用户发连接的title
、在线翻译网页
等
<script>
// 根据url动态拼接url
function seeCode() {
const url = document.getElementsByTagName('input')[0].value;
location.href = location.origin + location.pathname + '?url=' + url
}
</script>
<input type="text" placeholder="请输入要查看源代码的网站 URL"/>
<button onclick="seeCode()">查看</button>
<?php
$url = $_GET['url'];
if ("" == trim($url)) {
return;
}
// 获取内容
$websiteCode = file_get_contents($url);
// 转码后存入 textarea 标签里
echo "<textarea>".htmlspecialchars($websiteCode, ENT_QUOTES)."</textarea>";
?>复制代码
能够看到,这里没有对用户的输入作任何的过滤,致使用户能够直接输入http://192.168.1.2
等url,来访问内网资源,由于访问资源的是服务端自己,而服务端自己也是能够访问同局域网的资源的。
JSON Hijacking
其实本质和 CSRF
原理同样
这里的原理指的是,漏洞产生的原理同样,仍是由于标签产生的请求,会携带用户凭证
这个攻击手法和 CSRF
最大的不一样,就是 JSON Hijacking
在 CSRF
的基础上,又利用了 JSONP
的特性
<?php
require 'utils.php';
// 用户认证、并获取用户信息
$result = getUserInfo();
if (count($result) != 3) {
echo "";
exit();
}
$fnName = $_GET['callback'];
if ("" == trim($fnName)) {
echo "";
exit();
}
// 输出为: getInfo({"name": name, "balance": balance });
echo "$fnName({name: '$result[0]', balance: '$result[2]'})";
?>复制代码
<script>
function getInfo(data) {
console.log(data); // {"name": name, "balance": balance}
}
</script>
<script src="./json.php?callback=getInfo"></script>复制代码
若是有恶意攻击者,写了一个页面,而且也在网页里加入了<script src="http://xxx/json.php?callback=getInfo"></script>
根据上文提到的 w3c cors
规范中,若是用户事先已经登录过了,再打开恶意攻击者发的连接,那么攻击者就能够获取一些本不该该获取的敏感信息。