这是我参与「第四届青训营 」笔记创作活动的第3天
WEB开发的安全之旅
攻击篇
XSS跨站攻击
-
什么是XSS
- XSS(Cross Site Script)跨站脚本攻击是指攻击者在Web页面里插入恶意Script代码,当用户访问网页时,该代码会执行如
<script>alert("text");</script>
- XSS(Cross Site Script)跨站脚本攻击是指攻击者在Web页面里插入恶意Script代码,当用户访问网页时,该代码会执行如
-
XSS主要利用了什么
- 盲目信任用户的提交内容
- 直接把用户提交的字符串转为DOM如
document.write,element.innerHTML= anyString;
-
XSS的一些特点
- 难以从UI上感知,攻击者通常在暗地执行脚本
- 窃取用户信息(cookie、token)
- 绘制UI(例如弹窗),诱骗用户点击/填写表单
-
XSS的Demo(此Demo为存储型XSS攻击的一种形式)
public async submit(ctx){
const {content,id} = ctx.request.body;
//没有对content进行过滤就直接存入数据库了
await db.save({
content,
id
});
}
public async render(ctx){
//从数据库读取content
const {content} = await db.query({
id:ctx.query.id
});
//此处也没有对content过滤,直接使用模板字符串渲染dom
ctx.body = `<div>${content}</div>`;
}
那么如果用户在输入框等地方进行提交<script>alert("text");</script>
实际提交的请求就是
fetch("/submit",{
body:JSON.stringify({
id:"1",
content: `<script>alert("text");</script>`
});
});
那么最后实际的ctx.body = <div><script>alert("text");</script></div>
- 存储型XSS攻击
- 恶意脚本被存在数据库中
- 访问页面->读数据->被攻击
- 危害最大,对全部用户可见
- 反射型XSS攻击
- 不涉及数据库
- 从url上攻击
- 如
host/path/?param=<script>alert("text");</script>,服务器会从用户请求的参数中读取片段
- 基于DOM的XSS攻击
- 不需要服务器的参与
- 恶意攻击的发起和执行全在浏览器完成
- 与反射型相似,但是反射型是在服务端进行注入,而基于DOM的XSS注入完全是由浏览器完成
- 基于Mutation的XSS攻击
- 利用浏览器渲染DOM的特性(独特优化)
- 不同浏览器会有区别(按浏览器攻击)
- 如
<noscript><p title ="</noscript><img src=x onerror=alert(1)>">在很多的xss过滤工具中会把title属性当做合法的内容。将该代码放入chrom浏览器中,则会解析成
<div>
<noscript><p title ="</noscript>
<img scr = "x" onerror = "alert(1)">
"">"
</div>
CSRF跨站伪造请求
-
特点
- 用户不知情的前提下
- 利用用户权限
- 构造指定hhttp请求,窃取或修改用户敏感信息
-
攻击方式方式
- 构造一个get的请求如a标签,img标签
- 构造一个post请求表单
-
分类
- SQL注入
- CLI
- OS command
- SSRF(严格来说不算注入,但是原理类似)
Injection
- SQL Injection(SQL注入)
- 原理:处理请求字段的时候采取直接拼接SQL语句的方法
- 如用户在登录框中输入
text;DROP TABLE table;如果不做预编译处理直接拼接字符串,则数据库执行的语句可能是select text from tb_user;DROP TABLE table
- Injection demo2
//执行
public saync converVideo(ctx){
const {video,options} = ctx.request.body
exec(`convert-cli ${video} -o ${options};
ctx.body = "ok"
}
fetch("/api",{
method: "POST",
body:JSON.stringfy({ option : `‘ && rm -rf xx` })
})
//读取+修改
暴露重要文件如
/etc/passwd
/etc/shadow
~/.ssh
/etc/apache2/http.conf
/etc/nginx/nginx.conf
- SSRF demo
- 请求用户自定义的callback URL
- web server通常有内网访问权限
public async webhook(ctx){
//callback可能是内网url
//如 http://secret.com/get-employ_payrolls
ctx.body = await fetch(ctx.query.callback);
//访问callback相当于暴露内网信息
}
DoS
- 定义:通过某种方式构造特定请求导致服务器资源被消耗,来不及响应更多请求导致请求挤压,进而雪崩效应
- 正则表达式--贪婪模式
- 在写正则时使用?则是匹配一个即可,不使用则是尽量多
const greedyRegExp = /a+/;//有多少匹配多少
const nonGreedyRegExp = /a+?/;//有一个就行
const str = "aaaaaaaaaaa"
console.log(str.match(greedyRegExp)[0]);//aaaaaaaaaaa
console.log(str.match(nonGreedyRegExp)[0]);//a
- 基于正则表达式的Dos
- 贪婪:n次不行,n-1次再试试?-回溯
- DDos
- 不搞复杂的,量大就完事
- 特点:直接访问ip,任意api,主要想消耗带宽
- 原理:攻击者发大量SYN,服务器按规范返回ACK+SYC,当时攻击者此时不会返回第三次ACK,导致三次握手没有完成,连接无法释放,很快达到最大连接数,新请求无法继续
传输层:中间人攻击
-
利用原理
- 明文传输
- 信息篡改不可知
- 对方身份未验证
防御篇
XSS
- 永远不信任用户的提交内容
- 不要将用户提交内容直接转成DOM,应该转为String
- XSS工具
- 前端
- 主流框架默认防御XSS
- goole0closure-librar
- 服务端(Node)
- DOMPurify
- 前端
- 如果需求需要动态生成DOM
- string->dom 一定要转义
- 上传svg 对svg进行扫描
- 用户自定义跳转链接 进行过滤
- 用户自定义样式
Same-origin Policy(SoP同源策略)
- 同源是什么
- 两个url上的协议,域名,端口号相同
Content Security Policy(CSP内容安全策略)
- 允许开发者自定义那些源(域名)被认为是安全的
- 来自安全源的脚本可以执行,否则抛错
- 对eval+inline script直接拒绝
//服务器的响应头部
Content-Security-Policy:script-src 'self'
Content-Security-Policy:script-src 'self' https://domain.com
//浏览器meta设置
<meta http-equiv="Content-Security-Policy" content = "script-src self">
CSRF的防御
- 请求头部校验
- if(伪造请求===异常来源)then限制请求来源
- Origin 同源请求中,GET+HEAD不发送
- Referer
- 如果Origin和Referer是自己的域名就放行
- token
- 验证token
- token必须和具体用户绑定,才可以防止其他用户利用
- token必须设置过期时间
- CSRF--iframe攻击
- X-Frame-Options:DENY/SAMEORIGIN 规避该攻击
- DENY当前页面不能作为iframe加载
- SAMEORIGIN 必须是同源才记载iframe
- CSRF anti-pattern
- GET !== GET+POST
- 不能将更新获取等功能放在同一个get接口,该是get就是get,该是post就是post
- SameSite Cookie
- 从根源上解决CSRF的攻击
- 我的Cookie只能为我所用,不携带第三方cookie
- 限制的是Cookie的domian属性和当前页面的域名是否匹配
- 如果依赖cookie的第三方服务怎么办
- Set-Cookie:SameSIte=None; Secure;
- 服务器端设置属性为none,不对samesite进行限制,但是表明cookie为secure,已确认安全
- SameSite 对比 CORS
- SameSite
- Cookie发送
- domain属性对比页面域名
- 出了这个屋就不认了
- CORS
- 资源读写(http请求)
- 资源域名对比页面域名
- 白名单
- SameSite
- 防御CSRF的正确姿势
- 从node角度讲,应该在中间生成中间件完成CSRF的防御
Injection SQL防御
- 使用prepared statement
- 以Java中Mybatis进行增删改查为例
- 当使用$符号插入参数,则进行的是字符串拼接
- 使用#符号插入参数,其实是将输入内容作为参数
Injection beyond SQL
- 最小权限原则
- 建立允许名单+过滤
- 预防rm -rf
- 对url类型参数进行协议,域名,ip等限制
- 避免攻击者访问内网
DoS
- 代码Review,避免正则表达式写出贪婪正则
- 代码扫描+正则性能测试
- 拒绝使用用户提供的正则
DDos
- 流量治理
- 负载均衡
- API网关
- CDN
- 快速自动扩容
- 非核心服务降级
- 容出更多计算资源应对集中流量
传输层-防御中间人
- HTTPS(其实HTTP3页内置了TLS1.3)
- HTTP,TLS
- 特点
- 可靠性:加密
- 完整性:MAC验证,防止篡改
- 不可抵赖性:数字签名
- HTTPS加密过程简介
- TLS握手以及非对称加密和对称加密过程
- HTTPS特性简介
- 完整性
- 传输内容:加密信息+加密信息_hash
- 接收方将加密信息hash,与传输来的加密信息_hash对比,如果不一样则被篡改了
- 数字签名
- 签名执行者,包含私钥,公钥
- 过程:签名执行者使用私钥加密,生成对应签名,具备公钥的人使用公钥进行校验
- 不可抵赖性:数字签名
- CA:Certificate Authority(证书机构)完成相关签名工作
- 比如服务提供方将公钥合并成信息,使用CA提供的私钥进行签名,生成真正服务器端保存的证书,证书传递给浏览器侧,浏览器侧使用CA颁发的私钥进行校验,如果通过,则身份可信
- 每个浏览器里面都会有大量CA颁发的证书,证书包含CA的各个公钥
- 成也证书,败也证书,当签名算法不够强壮,签名算法可以被暴力破解
- CA:Certificate Authority(证书机构)完成相关签名工作
- 完整性
- HSTS
- 将http请求主动升级到https
- 流程
- 浏览器端向服务端发出一次https请求
- 服务器接收请求后返回Strict-Transport-Securit这个请求头部并且传递一个值max-age:3600s,在这之后的这么多秒内,如果发送的http请求都升级为https请求
- 缺点:一定要先有一次https请求
- Subresource Integrity(SRI)
- 如果cdn被攻陷,导致静态资源被劫持
- 实际是对比hash值
- 伪代码:
- 如果cdn被攻陷,导致静态资源被劫持
//integerity表明了当前摘要的算法以及具体值
<script src = "https://example/app.js"
integerity="sha384-{some-hash-value}"
crossoring="anonymous">
//拿到资源后会将其进行计算,对比hash值,如果不同可能被篡改了
const remoteHash = hash(content);
if(tagHash!== remoteHash){
throw new Error("wrong hash");
}
- Feature Policy/Permission Policy
- 一个源页面下可以使用哪些功能
- camera
- microphone
- autoplay
- 一个源页面下可以使用哪些功能