两个角度看 web 平安
如果你是一个 hacker —— 攻打
跨站脚本攻打(XSS,Cross Site Scripting)
- 歹意脚本注入,
<script>...</script>
,浏览器将其当成本身 DOM 执行编译 -
次要利用了
- 作为开发者自觉信赖用户提交的内容
- 前端工程师把用户提交的 string 间接转化为 DOM,例如 document.write、element.innerHTML = anyString 等
-
XSS 的一些特点:
- 通常难以从 UI 上感知(暗地执行脚本)
- 窃取用户信息(cookie/token)
- 绘制 UI(例如弹窗),诱骗用户点击 / 填写表单
-
XSS 攻打的分类
-
存储型 XSS(stored XSS)
- 歹意脚本被存在数据库中
- 拜访页面 -> 读数据 -> 被攻打
- 危害最大,对全副用户可见
-
反射型 XSS(reflected XSS)
- 不波及数据库
- 从 URL 上进行攻打
-
基于 DOM 的 XSS(DOM-based XSS)
- 不须要服务器的参加
- 歹意攻打的发动 + 执行,全副在浏览器中实现
- 与反射型 XSS 的区别在于实现注入脚本的中央:反射型在 server 端、DOM-based 在浏览器端
-
Mutation-based XSS
- 利用了浏览器渲染 DOM 的个性(独特优化)
- 不同浏览器会有区别(按浏览器进行攻打)
-
跨站伪造申请(CSRF,Cross-site request forgery)
-
特点:
- 在用户不知情的前提下
- 利用用户权限(cookie)
- 结构指定 HTTP 申请,窃取或批改用户敏感信息
-
跨站伪造申请示例
- 最常见的是利用链接发动 GET 申请(不局限于 GET 申请,结构 HTTP 申请即可)
SQL 注入(SQL Injection)
-
SQL 注入流程
-
示例
// 读取申请字段 间接以字符串的模式拼接 SQL 语句 public async renderForm(ctx){const { username, form_id} = ctx.query; const result = await aql.query(` select a,b,c from table where username = ${username} and form_id = ${from_id} `); ctx.body = renderForm(result); } // 攻击者 fetch("/api",{ method:"POST", headers:{"Content-Type":"application/json"}, body:JSON.stringify({username: "any; drop table tabelname;"}) }) // 造成 select xxx from xxx drop table tablename 删库跑路
-
服务端伪造申请(SSRF,Server-site request forgery)
- 严格上说不是 Injection,然而原理相似
- 申请用户自定义的 callback URL
-
web server 通常有内网拜访权限
public async webhook(ctx){ // callback 可能是内网 url // e.g http://secret.com/get_employ_payrolls ctx.body = await fetch(ctx.query.callback); } // 拜访 callback === 裸露内网信息
服务回绝(DoS,Denial of Service)
- 通过某种形式(结构特定申请),导致服务器资源被显著耗费,来不及响应更多申请导致申请挤压,进而产生雪崩效应
-
ReDos:基于正则表达式的 Dos:反复匹配时
?
与no ?
满足“一个即可”与“尽量多”const greedyRegExp = "/a+/"; // 有多少匹配多少 const nonGreedyRegExp = "/a+?/" // 有一个就能够 const str = "aaaaa"; console.log(str.match(greedyRegExp)[0]) //aaaaa console.log(str.match(nonGreedyRegExp)[0]) //a
- Distributed DoS:短时间内,来自大量僵尸设施的申请流量,服务器不能及时实现全副申请,导致申请沉积,产生雪崩效应,无奈响应新申请
基于传输层的攻击方式 —— 中间人攻打
为什么产生?
- 明文传输
- 信息篡改不可知
- 对方身份未验证
如果你是一个开发者 —— 进攻
针对 XSS 攻打
- 永远不信赖用户的提交内容
- 不要将用户提交的内容间接转换成 DOM
-
针对 XSS 的现成工具:
- 前端支流框架默认进攻 XSS
- google-closure-library
- 在服务端有 Node.js 提供了 DOMPurify 帮忙实现字符串转译避免 XSS
内容安全策略(CSP,Content Security Policy)
- 哪些源被认为是平安的
- 来自平安源的脚本能够执行,否则间接抛错
- 禁止 eval + inline script
-
设置形式:
-
服务器的响应头部
Content-Security-Policy: script-src 'self' // 同源 Content-Security-Policy: script-src 'self' https://domain.com // 同源加 前面这个能够拜访
-
浏览器 meta 标签
<meta htpp-eqiuv="Content-Security-Policy" content="script-src self" />
-
CSRF 的进攻
- 因为其攻击方式是伪造申请,是异样起源,如果限度申请起源,也就限度了伪造申请
- 具体方法 CSRF —— token
-
iframe 攻打是同源申请,怎么解决
- 同源的发送申请没方法用 Origin 限度
- 办法:应用响应头部:
X-Frame-Options:deny/sameorigin
-
防止用户信息被携带:SameSite Cookie
- 从本源上解决了 CSRF,CSRF 是利用用户权限及 cookie,去伪造本人是该用户来进行歹意操作,如果攻击者无奈获取到用户的 cookie 那就没用方法进行伪造了
- sameSite 限度的是 cookie domain、页面域名
- 如果是有 cookie 依赖第三方服务的(例如网站内嵌其余网站的播放器,不登录就没方法发弹幕),能够设置
Set-Cookie: SameSite=None; Secure;
-
SameSite 与 CORS 比照
- SameSite 进行限度:Cookie 发送、domain 与页面域名
- CORS 相似白名单:资源读写 HTTP 申请、资源域名与页面域名、白名单
- 进攻 CSRF 的正确形式 —— 编写中间件
Injection 的进攻
-
针对 SQL Injection:找到我的项目中查问 SQL 的中央,应用 prepared statement
PREPARE q FROM 'SELECT user WHERE gender = ?'; SET @gender = 'female'; EXECUTE q USING @gender; DEALLOCATE PREPARE q;
-
除了 SQL
- 最小权限准则,不容许拜访 sudo || root
- 建设容许名单 + 过滤,不容许进行 rm 这种零碎操作
- 对 URL 类型参数进行协定、域名、ip 等限度,禁止拜访内网
DoS 的进攻
-
Regex DoS:
- Code Review,防止贪心模式
/(ab*)+/
- 代码扫描 + 正则性能测试
- 不要应用用户提供的正则
- Code Review,防止贪心模式
-
DDoS:
- 流量治理:负载平衡过滤、API 网关过滤、CDN 扛量
- 疾速主动扩容
- 非核心服务降速
传输层的进攻
- 应用 HTTPS(HTTP + TLS)
-
HTTPS 的个性:
- 可靠性:加密,非明文传输
- 完整性:MAC 验证、禁止篡改、验证 hash
- 不可抵赖性:数字签名(CA 证书),进行身份验证 — 密码学
- SRI — Subresource Integrity:避免 CDN 动态资源被篡改
- Feature / Permission Policy:限度一个页面下,能够应用哪些性能