前言 Web 安全的兴起
Web
攻击技术的发展也可以分为几个阶段。在 Web 1.0
时代,人们更多的是关注服务器端
动态脚本的安全问题,比如将一个可执行脚本(俗称 webshell
)上传到服务器上,从而获得权
限。后续有出现了SQL
注入,SQL
注入的出现是Web
安全史上的一个里程碑,SQL
注入漏洞至今仍然是Web
安全领域中的一个重要组成部分。再后续另一个里程碑的安全问题问世–XSS
(跨站脚本攻击)。伴随着 Web 2.0
的兴起,XSS
、CSRF
等攻击已经变得更为强大。Web
攻击的思路也从服务器端转向了客户端,转向了浏览器和用户。
Web
技术发展到今天,构建出了丰富多彩的互联网。互联网业务的蓬勃发展,也催生出了
许多新兴的脚本语言,比如 Python
、Ruby
、NodeJS
等,敏捷开发成为互联网的主旋律。而手机技术、移动互联网的兴起,也给 HTML 5
带来了新的机遇和挑战。与此同时,Web
安全技术,也将紧跟着互联网发展的脚步,不断地演化出新的变化。
跨站脚本攻击(XSS
)是客户端脚本安全中的头号大敌。OWASP TOP 10
威胁多次把 XSS
列在榜首,该篇文章将重点介绍XSS
的攻防问题
①网络安全学习路线
②20份渗透测试电子书
③安全攻防357页笔记
④50份安全攻防面试指南
⑤安全红队渗透工具包
⑥网络安全必备书籍
⑦100个漏洞实战案例
⑧安全大厂内部视频资源
⑨历年CTF夺旗赛题解析
初探XSS
跨站脚本攻击,英文全称是 Cross Site Script
,本来缩写是 CSS
,但是为了和层叠样式表(Cascading Style Sheet
,CSS
)有所区别,所以在安全领域叫做“XSS
”。
XSS
攻击,通常指黑客通过HTML
注入 篡改网页,插入恶意脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击行为。在这种行为最初出现之时,所有的演示案例全是跨域行为,所以叫做 “跨站脚本” 。时至今日,随着Web
端功能的复杂化,应用化,是否跨站已经不重要了,但 XSS
这个名字却一直保留下来。
随着Web
发展迅速发展,Web
开发已经被应用的非常广泛了,由之前的单一PC
端扩展到现在的移动端(APP
、H5
),甚至包括桌面工具、设备大屏等等,所以在产生的应用场景越来越多,越来越复杂的情况下,同时大多数互联网(尤其是传统行业)的产品开发版本迭代上线时间非常短,一周一版本,两周一大版本的情况下,忽略了安全这一重要属性,一旦遭到攻击,后果将不堪设想。
XSS
攻击类型分类
XSS
攻击可以分为3类:反射型(非持久型)、存储型(持久型)、基于DOM XSS
;
反射型
反射型XSS
只是简单地把用户输入的数据“反射”给浏览器。也就是说,黑客往往需要诱使用户“点击”一个恶意链接,才能攻击成功。反射型XSS
也叫做 “非持久型 *\*\*XSS\*\*
*”(**Non-persistent XSS**
)。
通常反射型XSS
的恶意代码存在URL
里,通过URL
传递参数的功能,如网站搜索、跳转等。由于需要用户主动打开恶意的URL
才能生效,攻击者往往会结合多种手段诱导用户点击。
一个最初级的反射型攻击是:我们对网页数据进行获取:
html复制代码<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XSS攻防演练</title>
</head>
<body>
<div id="t"></div>
<input id="s" type="button" value="这是一个按钮" onclick="test()">
</body>
<script>
function test() {
const arr = [
'自定义的数据1',
'自定义的数据2',
'自定义的数据3',
'<img src="11" οnerrοr="console.log(window.localStorage)" />'
];
const t = document.querySelector('#t');
arr.forEach(item => {
const p = document.createElement('p');
p.innerHTML = item;
t.append(p);
})
}
</script>
</html>
当黑客点击这是一个按钮
时,即可轻松获取本地localStorage
数据,从而获取关键信息。
存储型
存储型 XSS
会把用户输入的数据“存储”在服务器端。这种 XSS
具有很强的稳定性。
比较常见的一个场景就是,黑客写下一篇包含有恶意 JavaScript
代码的博客文章,文章发表后,所有访问该博客文章的用户,都会在他们的浏览器中执行这段恶意的 JavaScript
代码。黑客把恶意的脚本保存到服务器端,所以这种 XSS
攻击就叫做 “存储型 *\*\*XSS\*\*
*”。
html复制代码<!-- 例如我们分别在网站中的输入框中输入以下信息,并保存到远程数据库 -->
<img src="11" onerror="console.log(window.localStorage)" />
<img src="11" onerror="alert(111)" />
页面输入
使用者浏览页面,分别先后触发了alert
弹框和localStorage
获取本地数据:
以上就是一个典型的存储型攻击。
基于DOM XSS
实际上,这种类型的XSS
并非按照“数据是否保存在服务器端”来划分,DOM Based XSS
从效果上来说也是反射型XSS
。单独划分出来,是因为DOM Based XSS
的形成原因比较特别,发现它的安全专家专门提出了这种类型的XSS
。DOM 型 XSS
跟前两种XSS
的区别:DOM 型 XSS
攻击中,取出和执行恶意代码由浏览器端完成,属于前端JavaScript
自身的安全漏洞,而其他两种XSS
都属于服务端的安全漏洞。
接下来我们来看一个简单的示例:
html复制代码<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XSS攻防演练</title>
</head>
<body>
<h3>基于DOM的XSS</h3>
<input type="text" id="input">
<button id="btn">提交内容</button>
<div id="div"></div>
</body>
<script>
const input = document.getElementById('input');
const btn = document.getElementById('btn');
const div = document.getElementById('div');
let inputValue;
input.addEventListener('change', (e) => {
inputValue = e.target.value;
}, false);
btn.addEventListener('click', () => {
div.innerHTML = `<a href=${inputValue}>链接地址</a>`
}, false);
</script>
</html>
我们再页面输入框中输入以下文本'' onclick=alert(/xss/)
,这里的''
引号是为了关闭掉href
属性,给它赋予了一个空值。然后点击提交内容
按钮,则页面中的<div id="div"></div>
标签包含了一下html
内容
html
复制代码<a href onlick="alert(/xss/)">链接地址</a>
XSS
攻击防御
关于XSS
的防御是非常复杂的,值得幸运的是现代浏览器、前端框架/库已经帮我们做了相当大的一部分工作。
HttpOnly
HttpOnly
最早是由微软提出,并在IE 6
中最先实现的,至今已经逐渐成为一个标准。浏览器将禁止页面的JavaScript
访问带有HttpOnly
属性的Cookie
。所以我们需要在http
的响应头set-cookie
时设置httpOnly
,让浏览器知道不能通过document.cookie
的方式获取到cookie
内容。
严格地说,HttpOnly
并非为了对抗 XSS——HttpOnly
解决的是XSS
后的 Cookie
劫持攻击。所以说使用HttpOnly
有助于缓解XSS
攻击,但仍然需要其他能够解决XSS
漏洞的方案;
输入检查
对于用户的输入内容我们需要持怀疑态度。在对输入不做任何过滤检查的情况下用户可能输入任何字符串。比如我们期望输入的内容是:hello word
, 也许我们收到的内容是onclick=alert(/xss/)
。
在XSS
的防御上,输入检查一般是检查用户输入的数据中是否包含一些特殊字符,如<、>、’、”
等。如果发现存在特殊字符,则将这些字符过滤或者编码。这种输入检查的方式,可以称为“XSS Filter”
。互联网上有很多开源的“XSS Filter”
的实现。比如一个简单的htmlencode
转义:
javascript复制代码const htmlEncode = function (handleString){
return handleString
.replace(/&/g,"&")
.replace(/</g,"<")
.replace(/>/g,">")
.replace(/ /g," ")
.replace(/\'/g,"'")
.replace(/\"/g,""");
}
但是输入检查也有弊端,比如
- 攻击者绕过前端页面直接使用接口就可以提交恶意代码到远程库中。
- 输入数据,还可能会被展示在多个地方,每个地方的语境可能各不相同,如果使用单一的替换操作,则可能会出现问题。输入检查也需要有针对性,如果我们想表达的意思是一个数小于另一个数(
3 < 4
),前端转义后的字符就变成3 < 4
,当这个值被存到远端时后,再通过AJAX
获取使用就会造成不必要的麻烦,比如我就进行数值计算等等。
输出检查
一般来说,除富文本的输出外,在变量输出到HTML
页面时,可以使用编码或转义的方式来防御XSS
攻击。
XSS的本质还是一种“HTML 注入”,用户的数据被当成了HTML代码一部分来执行,从而混淆了原本的语义,产生了新的语义。
如同输入检查一样,我们可以对输出进行编码转义。
1.在HTML
中输出
比如我们的html代码中有这样一段代码:
html复制代码<div>$htmlVar</div>
<a href="">$htmlVar</a>
如果输出的变量没有进行安全处理,直接使用并渲染在页面中,都能导致直接产生XSS
。最终的结果可能生成一下代码:
html复制代码<div><script>alert('我是一个XSS攻击者')</script></div>
<a href="#"><img href="" onclick="alert('我是另外一个XSS攻击者')"></a>
这个预防的方法就是对html进行转义检查
2. 在HTML
属性中输出
如果我们的html属性时动态值,那么利用属性也可以被攻击;
html
复制代码<div id="testXSS" data-name=""></div>
现在往data-name
属性中插入一段未转义的代码"><script>alert('我是一个XSS攻击者')</script><"
,结果如下:
html
复制代码<div id="testXSS" data-name=""><script>alert('我是一个XSS攻击者')</script><""></div>
3. 在<script>
标签中输出
在<script>
标签中输出时,首先应该确保输出的变量在引号中。
html复制代码<script>
// 假设userData是攻击者注入的数据
let xssVar = userData;
</script>
攻击者需要先闭合引号才能实施XSS攻击:
html复制代码<script>
// 假设userData是攻击者注入的数据
let xssVar = "";alert('我是一个script XSS攻击者');
</script>
4. 在CSS
中输出
在 CSS
和 style
、style attribute
中形成 XSS
的方式非常多样化,所以,一般来说,尽可能禁止用户可控制的变量在“<style>
标签”、“HTML
标签的style
属性”以及“CSS
文件”中输出。如果一定有这样的需求,则推荐使用一个关于CSS转义库。
防御DOM Based XSS
DOM Based XSS
是一种比较特别的XSS
漏洞,前文提到的几种防御方法都不太适用,需要特别对待。这个本质上,实际上就是网站前端JavaScript代码本身不够严谨,把不可信的数据当作代码执行了。
如果用 Vue/React
技术栈,并且不使用 v-html
/dangerouslySetInnerHTML
功能,就在前端render
阶段避免innerHTML
、outerHTML
的 XSS
隐患。稍后会有专门的Vue
关于XSS
的防御段落。
会触发DOM Based XSS
的地方有很多,以下几个地方是JavaScript
输出到HTML
页面的必经之路。
-
document.write()
; -
document.writeln()
; -
xxx.innerHTML()
; -
xxx.outerHTML()
; -
xxx.innerHTML.replace()
; -
document.attachEvent()
; -
window.attachEvent()
; -
window.location()
; -
window.name()
;所以开发者需要重点关注这几个地方的参数是否可以被用户控制。如果项目中有用到这些的话,一定要避免在字符串中拼接不可信数据。
Vue
中的XSS
防御
如果你在项目中使用了Vue
作为前端开发框架,恭喜你,Vue
将为你解决绝大多数的XSS
攻击问题,但是Vue
不是一个预防XSS
攻击的框架,在开发使用的时候还是有被攻击的漏洞存在;
Vue
中的防御措施
不论使用模板还是渲染函数,Vue
都会将插值的内容都会自动转义。也就是说对于这份模板:
html复制代码<template>
<p>{{userData}}</p>
</template>
<script>
// 从远程获取的数据
userData = "<script>alert('xss')</script>"
</script>
最终编译后页面显示的html
源码内容如下:
html复制代码<p>
<script>alert('xss')</script>
</p>
原因是Vue
帮我们对数据进行了转义,因此避免了脚本注入。该转义通过诸如 textContent 的浏览器原生的 API 完成,所以除非浏览器本身存在安全漏洞,否则不会存在安全漏洞。转义后的内容如下:
html
复制代码<script>alert("xss")</script>
注入HTML
如果你要动态注入远程的HTML
内容,首先你应该确保这些内容是安全有效的,否则你应该采取一些防御措施,去过滤或转义掉一些危险的标签符号;例如你可以这样显示的渲染HTML
:
html复制代码<!-- 当使用模版时 -->
<div v-html="userProvidedHtml"></div>
<!-- 当使用渲染函数时 -->
<script>
h('div', {
domProps: {
innerHTML: this.userProvidedHtml
}
})
</script>
<!-- 当使用JSX 的渲染函数时 -->
<div domPropsInnerHTML={this.userProvidedHtml}></div>
例如我们可以使用一个简单的方法(或者引用一个更加健壮的库/插件XSS来过滤一遍这个远程的userProvidedHtml
数据内容,以确保安全;
javascript复制代码// 一个简单的函数,通过转义<为<以及>为>来实现防御HTML节点内容
const escape = function(str){
return str.replace(/</g, '<').replace(/>/g, '>')
}
样式注入
在使用Vue
要在模板内避免渲染 style
标签:
html
复制代码<style>{{ userProvidedStyles }}</style>
这是因为,一但通过userProvidedStyles
,恶意用户仍可以提供 CSS
来进行“点击诈骗”,例如将链接的样式设置为一个透明的方框覆盖在“登录”按钮之上。然后再把https://user-XSS-website.com/
做成你的应用的登录页的样子,它们就可能获取一个用户真实的登录信息,所以Vue推荐使用对象语法
且只允许用户提供特定的可以安全控制的property
的值:
html复制代码<!-- sanitizedUrl应为受控的地址 -->
<a
v-bind:href="sanitizedUrl"
v-bind:style="{
color: userProvidedColor,
background: userProvidedBackground
}"
>
click me
</a>
安全问题“没有银弹”
在解决安全问题的过程中,不可能一劳永逸,也就是说“没有银弹”。
一般来说,人们都会讨厌麻烦的事情,在潜意识里希望能够让麻烦越远越好。而安全,正是一件麻烦的事情,而且是无法逃避的麻烦。任何人想要一劳永逸地解决安全问题,都属于一相情愿,是“自己骗自己”,是不现实的。
最佳实践
通用的规则是只要允许执行未过滤的用户提供的内容 (不论作为 HTML
、JavaScript
甚至 CSS
),你就可能令自己处于被攻击的境地。这些建议实际上不论使用 Vue
、React
还是别的框架甚至不使用框架,都是成立的。
题外话
网络安全行业特点
1、就业薪资非常高,涨薪快 2022年猎聘网发布网络安全行业就业薪资行业最高人均33.77万!
2、人才缺口大,就业机会多
2019年9月18日《中华人民共和国中央人民政府》官方网站发表:我国网络空间安全人才 需求140万人,而全国各大学校每年培养的人员不到1.5W人。猎聘网《2021年上半年网络安全报告》预测2027年网安人才需求300W,现在从事网络安全行业的从业人员只有10W人。
行业发展空间大,岗位非常多
网络安全行业产业以来,随即新增加了几十个网络安全行业岗位︰网络安全专家、网络安全分析师、安全咨询师、网络安全工程师、安全架构师、安全运维工程师、渗透工程师、信息安全管理员、数据安全工程师、网络安全运营工程师、网络安全应急响应工程师、数据鉴定师、网络安全产品经理、网络安全服务工程师、网络安全培训师、网络安全审计员、威胁情报分析工程师、灾难恢复专业人员、实战攻防专业人员…
职业增值潜力大
网络安全专业具有很强的技术特性,尤其是掌握工作中的核心网络架构、安全技术,在职业发展上具有不可替代的竞争优势。
随着个人能力的不断提升,所从事工作的职业价值也会随着自身经验的丰富以及项目运作的成熟,升值空间一路看涨,这也是为什么受大家欢迎的主要原因。
从某种程度来讲,在网络安全领域,跟医生职业一样,越老越吃香,因为技术愈加成熟,自然工作会受到重视,升职加薪则是水到渠成之事。
关于网络安全学习指南
学习网络安全技术的方法无非三种:
第一种是报网络安全专业,现在叫网络空间安全专业,主要专业课程:程序设计、计算机组成原理原理、数据结构、操作系统原理、数据库系统、 计算机网络、人工智能、自然语言处理、社会计算、网络安全法律法规、网络安全、内容安全、数字取证、机器学习,多媒体技术,信息检索、舆情分析等。
第二种是自学,就是在网上找资源、找教程,或者是想办法认识一-些大佬,抱紧大腿,不过这种方法很耗时间,而且学习没有规划,可能很长一段时间感觉自己没有进步,容易劝退。
第三种就是去找培训。
接下来,我会教你零基础入门快速入门上手网络安全。
网络安全入门到底是先学编程还是先学计算机基础?这是一个争议比较大的问题,有的人会建议先学编程,而有的人会建议先学计算机基础,其实这都是要学的。而且这些对学习网络安全来说非常重要。但是对于完全零基础的人来说又或者急于转行的人来说,学习编程或者计算机基础对他们来说都有一定的难度,并且花费时间太长。
第一阶段:基础准备 4周~6周
这个阶段是所有准备进入安全行业必学的部分,俗话说:基础不劳,地动山摇
第二阶段:web渗透
学习基础 时间:1周 ~ 2周:
① 了解基本概念:(SQL注入、XSS、上传、CSRF、一句话木马、等)为之后的WEB渗透测试打下基础。
② 查看一些论坛的一些Web渗透,学一学案例的思路,每一个站点都不一样,所以思路是主要的。
③ 学会提问的艺术,如果遇到不懂得要善于提问。
配置渗透环境 时间:3周 ~ 4周:
① 了解渗透测试常用的工具,例如(AWVS、SQLMAP、NMAP、BURP、中国菜刀等)。
② 下载这些工具无后门版本并且安装到计算机上。
③ 了解这些工具的使用场景,懂得基本的使用,推荐在Google上查找。
渗透实战操作 时间:约6周:
① 在网上搜索渗透实战案例,深入了解SQL注入、文件上传、解析漏洞等在实战中的使用。
② 自己搭建漏洞环境测试,推荐DWVA,SQLi-labs,Upload-labs,bWAPP。
③ 懂得渗透测试的阶段,每一个阶段需要做那些动作:例如PTES渗透测试执行标准。
④ 深入研究手工SQL注入,寻找绕过waf的方法,制作自己的脚本。
⑤ 研究文件上传的原理,如何进行截断、双重后缀欺骗(IIS、PHP)、解析漏洞利用(IIS、Nignix、Apache)等,参照:上传攻击框架。
⑥ 了解XSS形成原理和种类,在DWVA中进行实践,使用一个含有XSS漏洞的cms,安装安全狗等进行测试。
⑦ 了解一句话木马,并尝试编写过狗一句话。
⑧ 研究在Windows和Linux下的提升权限,Google关键词:提权
以上就是入门阶段
第三阶段:进阶
已经入门并且找到工作之后又该怎么进阶?详情看下图
给新手小白的入门建议:
新手入门学习最好还是从视频入手进行学习,视频的浅显易懂相比起晦涩的文字而言更容易吸收,这里我给大家准备了一套网络安全从入门到精通的视频学习资料包免费领取哦!
如果你对网络安全入门感兴趣,那么你需要的话可以在下方扫码领取!!