[TOC]
# XSS
<span style="font-family: 楷体;font-weight: 700;">跨网站指令码(Cross-site scripting,通常简称为:XSS)</span> 是一种网站应用程式的安全漏洞攻击,是代码注入的一种。它允许恶意使用者将程式码注入到网页上,其他使用者在观看网页时就会受到影响。这类攻击通常包含了 HTML 以及使用者端脚本语言。
XSS 分为三种:反射型,存储型和 DOM-based
## 如何攻击
### 反射型
反射型 XSS 只是简单地把用户输入的数据 “反射” 给浏览器,这种攻击方式往往需要攻击者诱使用户点击一个恶意链接,或者提交一个表单.
### 存储型
存储型 XSS 会把用户输入的数据 "存储" 在服务器端,当浏览器请求数据时,脚本从服务器上传回并执行。这种 XSS 攻击具有很强的稳定性。
比较常见的一个场景是攻击者在社区或论坛上写下一篇包含恶意 JavaScript 代码的文章或评论,文章或评论发表后,所有访问该文章或评论的用户,都会在他们的浏览器中执行这段恶意的 JavaScript 代码。
### 基于DOM
基于 DOM 的 XSS 攻击是指通过恶意脚本修改页面的 DOM 结构,是纯粹发生在客户端的攻击。
## 如何防御
最普遍的做法是转义输入输出的内容,对于引号,尖括号,斜杠进行转义
``` js
function escape(str) {
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, "`");
str = str.replace(/\//g, "/");
return str
}
```
对于显示富文本来说,不能通过上面的办法来转义所有字符,因为这样会把需要的格式也过滤掉。这种情况通常采用白名单过滤的办法,当然也可以通过黑名单过滤,但是考虑到需要过滤的标签和标签属性实在太多,更加推荐使用白名单的方式。
``` javaScript
var xss = require("xss");
var html = xss('<h1 id="title">XSS Demo</h1><script>alert("xss");</script>');
// -> <h1>XSS Demo</h1><script>alert("xss");</script>
console.log(html);
```
以上示例使用了`js-xss`来实现。可以看到在输出中保留了`h1`标签且过滤了`script`标签
```javaScript
通过 whiteList 来指定,格式为:{'标签名': ['属性1', '属性2']}。
不在白名单上的标签将被过滤,不在白名单上的属性也会被过滤。以下是示例:
// 只允许 a 标签,该标签只允许 href, title, target 这三个属性
var options = {
whiteList: {
a: ["href", "title", "target"]
}
};
// 使用以上配置后,下面的HTML
// <a href="#" onclick="hello()"><i>大家好</i></a>
// 将被过滤为
// <a href="#">大家好</a>
```
### CSP
<span style="font-family: 楷体;font-weight: 700;">内容安全策略(Content Security Policy,CSP )</span> 是一个额外的安全层,用于检测并削弱某些特定类型的攻击,包括跨站脚本 XSS 和数据注入攻击等。无论是数据盗取、网站内容污染还是散发恶意软件,这些攻击都是主要的手段。
我们可以通过 CSP 来尽量减少 XSS 攻击。CSP 本质上也是建立白名单,规定了浏览器只能够执行特定来源的代码。
通常可以通过 HTTP Header 中的`Content-Security-Policy`来开启 CSP
* 只允许加载本站资源
```html
Content-Security-Policy: default-src 'self'
```
* 只允许加载 HTTPS 协议图片
```html
Content-Security-Policy: img-src https://*
```
* 允许加载任何来源框架
``` html
Content-Security-Policy: child-src 'none'
```
也可以通过 HTML 的 meta 标签
```html
<meta http-equiv="Content-Security-Policy" content="script-src 'self' ">
```
具体使用方式见 [https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP)
# CSRF
<span style="font-family: 楷体;font-weight: 700;">跨站请求伪造(Cross-site request forgery / one-click attack / session riding / CSRF)</span> 是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法。XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对用户网页浏览器的信任。
简单点说,CSRF 就是利用用户的登录态发起恶意请求(一般是利用浏览器自动发送 cookie 的机制)。
## 如何攻击
假设网站中有一个通过 Get 请求提交用户评论的接口,那么攻击者就可以在钓鱼网站中加入一个图片,图片的地址就是评论接口
```html
<img src="http://www.domain.com/xxx?comment='attack'"/>
```
如果接口是 Post 提交的,就相对麻烦点,需要用表单来提交接口
```html
<form action="http://www.domain.com/xxx" id="CSRF" method="post">
<input name="comment" value="attack" type="hidden">
</form>
```
这里多提一句 Cookie 的发送机制:当向 HTTP 服务器请求某个 URL 时,浏览器将该 URL 与客户主机中存储的所有 Cookie 比较,如果发现域名相匹配 Cookie,则匹配 Cookie 中包含名字/值的那一行将被包含在 HTTP 请求头中,以保证依赖于 Cookie 的功能得以实现。
虽然一般情况下浏览器的跨域限制会保护我们的 cookie,但是就如上面的简单的例子 img 标签的 src 是不受跨域限制的,那么 domain 属性与这个 GET 请求的 domain 相同的 Cookies 都会被自动携带在请求头中。
![](https://box.kancloud.cn/1595efac21dbf0bddbd78bb9a42abb12_754x338.png)
## 如何防范
防范 CSRF 可以遵循以下几种规则:
1. Get 请求不对数据进行修改
2. 不让第三方网站访问到用户 Cookie
3. 阻止第三方网站请求接口
4. 请求时附带验证信息,比如验证码或者 token(比如利用 axios 拦截器)
### SameSite
可以对 Cookie 设置`SameSite`属性。该属性设置 Cookie 不随着跨域请求发送,该属性可以很大程度减少 CSRF 的攻击,但是该属性目前并不是所有浏览器都兼容。
### 验证 Referer
对于需要防范 CSRF 的请求,我们可以通过验证 Referer 来判断该请求是否为第三方网站发起的。HTTP Referer 是 HTTP 请求头部的一部分,浏览器向 Web 服务器发送请求时一般都会自动带上 Referer 以告诉服务器我是从哪个页面来的。
### 使用验证码
验证码被认为是对抗 CSRF 攻击最简洁而有效的防御方法。
CSRF 攻击往往是在用户不知情的情况下构造了网络请求。而验证码会强制用户必须与应用进行交互(验证码由服务器随机给出),才能完成最终请求。因此通常情况下,验证码能够很好地遏制 CSRF 攻击。
但验证码并不是万能的,因为出于用户考虑,不能给网站所有的操作都加上验证码。因此,验证码只能作为防御 CSRF 的一种辅助手段,而不能作为最主要的解决方案。
### Token
服务器下发一个随机 Token(算法不能复杂),每次发起请求时将 Token 携带上,服务器验证 Token 是否有效。
客户端可以把 token 存在 cookie(如果 token 不是用于验证的话,就防范 CSRF 而言就不存在 cookie 中了)或者 Local / Session Storage中。
# 加密算法分析
## 好的和不好的安全算法
在保护数据和受限的用户信息方面,不是所有加密算法都具有同等效果。有的算法追求的是速度,力求快速而准确地加密和解密大量数据。有些则故意放慢速度。加入一个储存一百万加密用户记录的数据库被窃取了,攻击者在尝试各种破解方法(例如使用字典中的每个词)攥取数据,我们自然是希望其破解的速度越慢越好。
### 好的算法
`PBKDF2`
 PBKDF2 是 *Password-Based Key Derivation Function 2* 的简称,它在输入(密码)上应用一个伪随机函数(例如哈希、暗码或 HMAC),此外还会加盐。这个过程会重复多次,得出一个密钥。
`bcrypt`
 bcrypt 是基于 Blowfish 密码法的密钥导出函数,在保护密钥的过程中会加盐,而且具有适应能力。随着时间的推移,我们可以增加迭代次数,不断放慢速度,抵抗暴力攻击。
`scrypt`
 scrypt 也是一个密钥导出函数,专门用于抵御大型硬件攻击,因为它需要大量内存,从而放慢了计算的速度。
### 不好的算法(对密码而言)
`MD5`
 MD5(也称消息摘要算法,message-digest algorithm)生成一个 128 位哈希值,通常使用一个 32 位十六进制数表示。
`SHA-1`
 SHA 是 Secure HashAlgorithm(安全哈希算法)的简称,其生成一个 160 位(20 字节)的哈希值,通常使用一个 40 位十六进制数表示。
`SHA-2`
 SHA-2 是 SHA-1 的继任,包含 6 个哈希函数,生成的哈希值有 224 位、256 位、384 位和 512 位(SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/244、SHA-512/256)
## 静态数据和动态数据
静态数据指不活动的数字数据,存储在服务器中,例如用于存储密码、个人资料或其他应用所需要数据的数据库。
动态数据指传输中的数据,在应用和数据库之间来回发送,或者在网站和 API 或外部数据源之间来回传送。
<span style="font-size: 18px;font-family:宋体;">静态数据</span>
筹划应对数据泄露的措施时一定要考虑最坏的情况,我们应该假定攻击者已经获取了数据库的访问权,而且最终目的是获取敏感的数据和密码,遇到这种情况,数据库本身必须还有一层加密措施。
加密数据库应该使用强加密算法,如 SHA-256,或者更好的 AES 和 RSA;弱加密算法例如 MD5 和 SHA-1 绝不能用于加密数据库。
其次,应该遵守一些标准做法:
- 把访问控制(用户登录)和数据加密分开。如果用户名或密码失败,数据库本身应该保持加密,从而提供多级保护。
- 用于加密数据库的密钥应该定期更新。
- 加密密钥应该与数据分开存储。
<span style="font-size: 18px;font-family:宋体;">动态数据</span>
动态数据是大多数 Web 和应用开发者每天都要处理的数据,实际上,这包含几种场景:
- 用户填写的注册信息,用于访问账户和认证身份。
- 把个人档案信息传输给 API 服务,或从中获取。
- 应用或网站收集的其他数据,传送给数据库存储起来
## 密码攻击媒介
攻击者获取账户访问权的方式有多种,有些设法操纵用户,另一些则直指应用或网站,下面介绍其中几个:
*钓鱼*
  通过恶意网站或应用骗用户提供登录凭据。这种攻击方式多以电子邮件诈骗形式出现,发件人假扮成某公司职员,编造一些理由让用户登录恶意网站,盗取用户的登录凭据,攥取账户访问权。
*社会工程*
  社会工程比钓鱼高一个档次,往往通过其他通信工具实施,例如电话。攻击者假扮网络技术人员,说是为了维修所报故障,让用户提供登录凭据。
*暴力攻击*
  计算特定长度下所有可能的密钥组合方式,然后逐个尝试,直到猜对密码为止。增加密码长度,破解密码的时间将呈指数级增长。如果这个方法耗时太久,攻击者会转而采取其他方式,例如字典攻击。抵抗暴力攻击的方法之一是**密钥延伸**。
*字典攻击*
  迭代既定的字词表(例如字典中的所有词),尝试所有组合,试图找出匹配加密密码的值。与暴力攻击不同的是,字典攻击只尝试输入常见的字、词或短语。**加盐**能有效地防范这种攻击。
*彩虹表*
  一个大型列表,包含预先计算好的哈希值(使用给定的哈希函数计算)和得出哈希值的密码。与字典攻击不同,彩虹表攻击每次尝试破解时都会应用哈希函数,让攻击者直接对比预先计算好的哈希值和数据库中保存的密码哈希值,因此整个过程更为高效,加盐能有效地防范这种攻击。
## 加盐
盐值是一种随机数据,计算密码的哈希值时用于加强数据,抵御多种攻击媒介。这个随机数据(特别长)能确保生成的哈希值是唯一的,即使多个用户使用相同的密码,添加唯一的盐值后能确保得到的哈希值是唯一的。
## node 中常用的加密算法
Hash 算法加密:
```js
const content = 'password' // 加密的明文
let md5 = crypto.createHash('md5') // 参数为任意 hash 加密的方法名称
md5.update(content)
let d = md5.digest('hex') // 加密后的值为 d
console.log(`加密的结果: ${d}`)
```
Hmac 加密算法:
HMAC 是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code),HMAC 运算利用哈希算法,以一个密钥和一个消息为输入,生成一个消息摘要作为输出。HMAC 可以有效防止一些类似 md5 的彩虹表等攻击,比如一些常见的密码直接 MD5 存入数据库的,可能被反向破解。
<br>
定义 HMAC 需要一个加密用散列函数(表示为 H,可以是 MD5 或者 SHA-1)和一个密钥 K。我们用 B 来表示数据块的字节数,用 L 来表示散列函数的输出数据字节数(MD5 中 L=16,SHA-1 中 L=20)。鉴别密钥的长度可以是小于等于数据块字长的任何正整数值。应用程序中使用的密钥长度若是比 B 大,则首先用使用散列函数 H 作用于它,然后用 H 输出的 L 长度字符串作为在 HMAC 中实际使用的密钥。一般情况下,推荐的最小密钥 K 长度是 L 个字节。
<br>
下面为为一个 Hmac 加密示例(采用sha1方式):(由于密钥会通过随机生成的 16 位数进行加密后再对明文加密,每次生成的新密钥(token)都不同,所以最后生成的密文也不会相同,这种加密不可逆
```js
const crypto = require('crypto')
// hmac-sha1 加密
const content = 'password' // 加密的明文
let token1 = 'miyao' // 加密的密钥
let buf = crypto.randomBytes(16) // 参数表示要生成的盐值的大小,单位为字节
token1 = buf.toString('hex') // 密钥加密
console.log(`生成的 token: ${token1}`)
let SecretKey = token1 // 密钥
let Signture = crypto.createHmac('sha1', SecretKey) // 定义加密方式
Signture.update(content)
let miwen = Signture.digest().toString('base64') // 生成的密文后将再次作为明文再通过 pbkdf2 算法迭代加密
console.log(`加密的结果f: ${miwen}`)
/*
每次都不一样
生成的 token: f89599f5039f4728feabd0361947aede
加密的结果f: qnpe9g0t/Hm+/5ErsgyUUsVksN4=
生成的 token: 575b85075f9d66b1aed48f7b84e9b26e
加密的结果f: 4PvLjzId16X+piXsixeK+cGXNeg=
*/
```
# OAuth2
OAuth2 是一个开放授权标准,它允许用户让第三方应用访问该用户在某服务的特定私有资源但是不提供账号密码信息给第三方应用。
## OAuth2 的四个重要角色
1、`Resource Owner`:资源拥有者
2、`Resource Server`:资源服务器
3、`Client`:第三方应用客户端
4、`Authorization Server`:授权服务器,管理 Resource Owner,Client 和 Resource Server 的三角关系的中间层
OAuth2 解决问题的关键在于使用 Authorization server 提供一个访问凭据给 Client,使得 Client 可以在不知道 Resource owner 在 Resource server 上的用户名和密码的情况下消费 Resource owner 的受保护资源。
我们使用的第三方登录很多功能都遵守 OAth2 规范,如 [QQ OAuth2 API](https://wiki.connect.qq.com/%E4%BD%BF%E7%94%A8authorization_code%E8%8E%B7%E5%8F%96access_token) [微信公众号获取 access_token](https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183)
## 部署 OAuth2 需要完成的工作
由于 OAuth2 引入了 Authorization server 来管理 Resource Owner,Client 和 Resource Server 的三角关系,那么想要用上 OAuth2,是必须要实现以下功能的:
1. 增加一个 Authorization server,提供授权的实现,一般由 Resource server 来提供。
2. Resource server 为第三方应用程序提供注册接口。
3. Resource server 开放相应的受保护资源的 API。
4. Client 注册成为 Resource server 的第三方应用。
5. Client 消费这些 API。
作为资源服务提供商来说,1,2,3 这三件事情是需要完成的。
作为第三方应用程序,要完成的工作是在 4 和 5 这两个步骤中。
其中作为 Resource owner 来说,是不用做什么的,是 OAuth2 受益的千千万万的最终人类用户。
## 资源服务提供商和用户的职责
在一般情况下,Resource server 提供 Authorization server 服务,主要提供两类接口:
- 授权接口:接受 Client 的授权请求,引导用户到 Resource server 完成登陆授权的过程。
- 获取访问令牌接口:使用授权接口提供的许可凭据来颁发 Resource owner 的访问令牌给 Client,或者由 Client 更新过期的访问令牌。
除此之外,还需要提供一个第三方应用程序注册管理的服务。通常情况下会为注册完成的第三方应用程序分配两个成对出现的重要参数:
- client\_id:第三方应用程序的一个标识 id,这个信息通常是公开的信息,用来区分哪一个第三方应用程序。
- client\_secret:第三方应用程序的私钥信息,这个信息是私密的信息,不允许在 OAuth2 流程中传递的,用于安全方面的检测和加密。
作为 Client:在 Client 取得 client\_id 和 client\_secret 之后。使用这些信息来发起授权请求、获取 access\_token 请求和消费受保护的资源。
## OAuth2 授权流程
1\. 消费方:把用户带到服务器提供方登录
2\. 服务提供方:获得授权
3\. 服务提供方:把用户重定向到消费方
4\. 消费方:使用授权码请求访问令牌
5\. 服务提供方:核发访问令牌
6\. 消费方:使用访问令牌访问受保护的资源
![](https://img.kancloud.cn/75/a3/75a30332c17413082c2b07d8778ca225_762x684.png)
这其中比较重要的一个概念是 **访问令牌**,它代表的信息是整个 OAuth2 的核心,也是前 4 步最终要得到的信息。
访问令牌是对 **消费方可访问的用户的哪些信息** 这个完整权限的一个抽象
访问令牌背后抽象的信息有哪些呢?如下 3 类信息。
1. 客户端标识
2. 用户标识
3. 客户端能访问资源所有者的哪些资源以及其相应的权限。
有了这三类信息,那么资源服务器(Resouce Server)就可以区分出来是哪个第三方应用(Client)要访问哪个用户(Resource Owner)的哪些资源(以及有没有权限)。
# DDoS 攻击与防范
DDoS 的攻击原理,往简单说,其实就是利用 TCP/UDP 协议规律,通过占用协议栈资源或者发起大流量拥塞,达到消耗目标机器性能或者网络的目的。
按照攻击对象的不同,将对攻击原理和攻击危害的分析分成 3 类,分别是攻击网络带宽资源、系统以及应用。具体可以参考 [这篇文章](https://www.cnblogs.com/163yun/archive/2018/06/01/9121857.html)
其中,比较常见的一种攻击是 cc 攻击。它就是简单粗暴地送来大量正常的请求,超出服务器的最大承受量,导致宕机。
可以看看阮一峰老师的个人博客遭受 DDoS 攻击时 [采取的措施](https://www.cnblogs.com/southx/p/9414695.html)
![](https://img.kancloud.cn/72/39/72390a784c7146b959214e37a68aa790_1720x783.png)
# 参考链接
[xss 与 csrf](https://github.com/dwqs/blog/issues/68)
[oauth2](https://www.cnblogs.com/linianhui/p/oauth2-authorization.html)
[token](https://juejin.im/post/58da720b570c350058ecd40f)
[node 中常用的加密算法](https://www.cnblogs.com/laogai/p/4664917.html)
[http://louiszhai.github.io/2016/03/05/xss/#Content-Security-Policy](http://louiszhai.github.io/2016/03/05/xss/#Content-Security-Policy)
[https://content-security-policy.com/](https://content-security-policy.com/)
[https://www.cnblogs.com/southx/p/9414695.html](https://www.cnblogs.com/southx/p/9414695.html)
[https://www.cnblogs.com/163yun/archive/2018/06/01/9121857.html](https://www.cnblogs.com/163yun/archive/2018/06/01/9121857.html)
- 序言 & 更新日志
- H5
- Canvas
- 序言
- Part1-直线、矩形、多边形
- Part2-曲线图形
- Part3-线条操作
- Part4-文本操作
- Part5-图像操作
- Part6-变形操作
- Part7-像素操作
- Part8-渐变与阴影
- Part9-路径与状态
- Part10-物理动画
- Part11-边界检测
- Part12-碰撞检测
- Part13-用户交互
- Part14-高级动画
- CSS
- SCSS
- codePen
- 速查表
- 面试题
- 《CSS Secrets》
- SVG
- 移动端适配
- 滤镜(filter)的使用
- JS
- 基础概念
- 作用域、作用域链、闭包
- this
- 原型与继承
- 数组、字符串、Map、Set方法整理
- 垃圾回收机制
- DOM
- BOM
- 事件循环
- 严格模式
- 正则表达式
- ES6部分
- 设计模式
- AJAX
- 模块化
- 读冴羽博客笔记
- 第一部分总结-深入JS系列
- 第二部分总结-专题系列
- 第三部分总结-ES6系列
- 网络请求中的数据类型
- 事件
- 表单
- 函数式编程
- Tips
- JS-Coding
- Framework
- Vue
- 书写规范
- 基础
- vue-router & vuex
- 深入浅出 Vue
- 响应式原理及其他
- new Vue 发生了什么
- 组件化
- 编译流程
- Vue Router
- Vuex
- 前端路由的简单实现
- React
- 基础
- 书写规范
- Redux & react-router
- immutable.js
- CSS 管理
- React 16新特性-Fiber 与 Hook
- 《深入浅出React和Redux》笔记
- 前半部分
- 后半部分
- react-transition-group
- Vue 与 React 的对比
- 工程化与架构
- Hybird
- React Native
- 新手上路
- 内置组件
- 常用插件
- 问题记录
- Echarts
- 基础
- Electron
- 序言
- 配置 Electron 开发环境 & 基础概念
- React + TypeScript 仿 Antd
- TypeScript 基础
- 样式设计
- 组件测试
- 图标解决方案
- Algorithm
- 排序算法及常见问题
- 剑指 offer
- 动态规划
- DataStruct
- 概述
- 树
- 链表
- Network
- Performance
- Webpack
- PWA
- Browser
- Safety
- 微信小程序
- mpvue 课程实战记录
- 服务器
- 操作系统基础知识
- Linux
- Nginx
- redis
- node.js
- 基础及原生模块
- express框架
- node.js操作数据库
- 《深入浅出 node.js》笔记
- 前半部分
- 后半部分
- 数据库
- SQL
- 面试题收集
- 智力题
- 面试题精选1
- 面试题精选2
- 问答篇
- Other
- markdown 书写
- Git
- LaTex 常用命令