Web 安全基础

两个角度看 web 安全 假如你是一个 hacker —— 攻击 跨站脚本攻击(XSS,Cross Site Scripting)

  • 恶意脚本注入,,浏览器将其当成自身 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 请求,窃取或修改用户敏感信息
  • 跨站伪造请求示例
    Web 安全基础
    文章图片

    • 最常见的是利用链接发起 GET 请求(不局限于 GET 请求,构造 HTTP 请求即可)
SQL 注入(SQL Injection)
  • SQL 注入流程
    Web 安全基础
    文章图片

    • 示例
      // 读取请求字段直接以字符串的形式拼接 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:短时间内,来自大量僵尸设备的请求流量,服务器不能及时完成全部请求,导致请求堆积,产生雪崩效应,无法响应新请求
基于传输层的攻击方式 —— 中间人攻击
为什么产生?
  • 明文传输
  • 信息篡改不可知
  • 对方身份未验证
    Web 安全基础
    文章图片
假如你是一个开发者 —— 防御 针对 XSS 攻击
  • 永远不信任用户的提交内容
  • 不要将用户提交的内容直接转换成 DOM
    Web 安全基础
    文章图片
  • 针对 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 标签

CSRF 的防御
  • 因为其攻击方式是伪造请求,是异常来源,如果限制请求来源,也就限制了伪造请求
  • 具体方法 CSRF —— token
    Web 安全基础
    文章图片
  • 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*)+/
    • 代码扫描 + 正则性能测试
    • 不要使用用户提供的正则
  • DDoS:
    • 流量治理:负载均衡过滤、API 网关过滤、CDN 扛量
    • 快速自动扩容
    • 非核心服务降速
传输层的防御
  • 使用 HTTPS(HTTP + TLS)
    Web 安全基础
    文章图片
  • 【Web 安全基础】HTTPS 的特性:
    • 可靠性:加密,非明文传输
    • 完整性:MAC 验证、禁止篡改、验证 hash
    • 不可抵赖性:数字签名(CA 证书),进行身份验证 — 密码学
  • SRI — Subresource Integrity:防止 CDN 静态资源被篡改
  • Feature / Permission Policy:限制一个页面下,可以使用哪些功能

    推荐阅读