{"id":20340698,"url":"https://github.com/chanmenglin/websecurity","last_synced_at":"2025-10-10T01:13:33.329Z","repository":{"id":171593579,"uuid":"158497746","full_name":"ChanMenglin/WebSecurity","owner":"ChanMenglin","description":"Web-Security(Web 安全)","archived":false,"fork":false,"pushed_at":"2019-11-20T02:25:11.000Z","size":2713,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-23T05:41:21.357Z","etag":null,"topics":["cookie","cookies-csrf","cookies-document","csrf","data-security","database","javascript","samesite","samesite-cookie-csrf","samesite-cookies","security","server-security","sql","web","web-security","website","xss","xss-cookies"],"latest_commit_sha":null,"homepage":"https://chanmenglin.github.io/WebSecurity/","language":null,"has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ChanMenglin.png","metadata":{"files":{"readme":"README.MD","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-11-21T05:52:36.000Z","updated_at":"2024-05-24T14:13:44.000Z","dependencies_parsed_at":null,"dependency_job_id":"b0df83b8-009d-47f3-b698-3911ff7d7fe4","html_url":"https://github.com/ChanMenglin/WebSecurity","commit_stats":null,"previous_names":["chanmenglin/websecurity"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ChanMenglin/WebSecurity","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChanMenglin%2FWebSecurity","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChanMenglin%2FWebSecurity/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChanMenglin%2FWebSecurity/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChanMenglin%2FWebSecurity/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ChanMenglin","download_url":"https://codeload.github.com/ChanMenglin/WebSecurity/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ChanMenglin%2FWebSecurity/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279002404,"owners_count":26083373,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-09T02:00:07.460Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cookie","cookies-csrf","cookies-document","csrf","data-security","database","javascript","samesite","samesite-cookie-csrf","samesite-cookies","security","server-security","sql","web","web-security","website","xss","xss-cookies"],"created_at":"2024-11-14T21:23:08.805Z","updated_at":"2025-10-10T01:13:33.288Z","avatar_url":"https://github.com/ChanMenglin.png","language":null,"readme":"# Web 安全(Web Security)\n\n\u003e 前置知识：  \n\u003e * 原生 JavaScript\n\u003e * 少量 Node.js 基础\n\u003e * HTTP 基础知识( Cookies / Session )\n\u003e * Web 后端基础知识( HTTP / SQL )\n\u003e * SQL 及 关系型数据库 基础\n\n[MDN Web 文档 - Web 安全](https://developer.mozilla.org/zh-CN/docs/Web/Security)\n\n# 目录（Contents）\n\n* [1. 跨站脚本攻击 XSS (Cross Site Scripting)](#1-跨站脚本攻击-xss-cross-site-scripting)\n    * [1.1 HTML节点内容](#11-html节点内容)\n        * [1.1.1 HTML属性](#111-html属性)\n        * [1.1.2 JavaScript 代码](#112-javascript-代码)\n    * [1.2 富文本](#12-富文本)\n        * [1.2.1 黑名单过滤](#121-黑名单过滤)\n        * [1.2.2 白名单过滤](#122-白名单过滤)\n    * [1.3 CSP (Content Security Policy) 内容安全策略](#13-csp-content-security-policy-内容安全策略) \n* [2. 跨站请求伪造 CSRF (Cross Site Request Forgy)](#2-跨站请求伪造-csrf-cross-site-request-forgy)\n    * [2.1 SameSite Cookie，防止 CSRF 攻击](#21-samesite-cookie防止-csrf-攻击)\n    * [2.2 在前端页面加入验证信息](#22-在前端页面加入验证信息)\n    * [2.3 通过 referer 禁止来自第三方网站的强求](#23-通过-referer-禁止来自第三方网站的强求)\n* [3. 前端 Cookies 安全性](#3-前端-cookies-安全性)\n    * [3.1 Cookies 的特点](#31-cookies-的特点)\n    * [3.2 Cookies 的特性](#32-cookies-的特性)\n    * [3.3 Cookies 操作](#33-cookies-操作)\n    * [3.4 Cookies 作用](#34-cookies-作用)\n    * [3.5 Cookies 安全问题](#35-cookies-安全问题)\n        * [3.5.1 生成用户凭证](#351-生成用户凭证)\n        * [3.5.2 Cookies 和 XSS 的关系](#352-cookies-和-xss-的关系)\n        * [3.5.3 Cookies 和 CSRF 的关系](#353-cookies-和-csrf-的关系)\n    * [3.6 Cookies 安全策略](#36-cookies-安全策略)\n* [4. 点击劫持](#4-点击劫持)\n    * [4.1 点击劫持的原理](#41-点击劫持的原理)\n    * [4.2 点击劫持的前提](#42-点击劫持的前提)\n    * [4.3 点击劫持的防御](#43-点击劫持的防御)\n* [5. 传输过程安全问题](#5-传输过程安全问题)\n    * [5.1 HTTP 传输窃听和篡改的危害](#51-http-传输窃听和篡改的危害)\n    * [5.2 HTTPS TLS(SSL) 加密](#52-https-tlsssl-加密)\n    * [5.3 部署 HTTPS 的网站](#53-部署-https-的网站)\n* [6. 用户密码安全问题（接入层）](#6-用户密码安全问题接入层)\n    * [6.1 密码的作用](#61-密码的作用)\n    * [6.2 密码的存储](#62-密码的存储)\n        * [6.2.1 密码的存储原则](#621-密码的存储原则)\n        * [6.2.2 密码存储方案](#622-密码存储方案)\n    * [6.3 密码的传输](#63-密码的传输)\n        * [6.3.1 HTTPS传输](#631-https传输)\n        * [6.3.2 频率限制（防猜解）](#632-频率限制防猜解)\n        * [6.3.3 前端加密（作用有限）](#633-前端加密作用有限)\n    * [6.4 密码的替代方案](#64-密码的替代方案)\n* [7. SQL注入攻击](#7-sql注入攻击)\n    * [7.1 SQL 注入危害](#71-sql-注入危害)\n    * [7.2 SQL 注入防御](#72-sql-注入防御)\n    * [7.3 NoSQL 注入和防御](#73-nosql-注入和防御)\n* [8. 上传问题（接入层）](#8-上传问题接入层)\n    * [8.1 上传文件的问题](#81-上传文件的问题)\n    * [8.2 上传漏洞防御](#82-上传漏洞防御)\n        * [8.2.1 限制上传后缀（有时不可靠）](#821-限制上传后缀有时不可靠)\n        * [8.2.2 文件类型检查（可绕过）](#822-文件类型检查可绕过)\n        * [8.2.3 文件内容检查（可欺骗）](#823-文件内容检查可欺骗)\n        * [8.2.4 程序输出（防止文件被当作程序执行）](#824-程序输出防止文件被当作程序执行)\n        * [8.2.5 权限控制 - 可写可执行互斥](#825-权限控制---可写可执行互斥)\n* [9. 信息泄露和社会工程学](#9-信息泄露和社会工程学)\n    * [9.1 信息泄露](#91-信息泄露)\n    * [9.2 信息泄露的途径](#92-信息泄露的途径)\n    * [9.3 信息保护](#93-信息保护)\n* [10 安全策略](#10-安全策略)\n\n## 1. 跨站脚本攻击 XSS (Cross Site Scripting)\n\nXSS攻击原理：来自用户的数据被当作脚本在页面中执行  \n\n### 1.1 HTML节点内容\n\n可对用户输入进行转译处理\n\n#### 1.1.1 HTML属性\n\n```javascript\n/**\n * 对 HTML 节点内容及属性进行 XSS 攻击的预防代码\n * 将 HTML 节点内容及属性转译为 HTML 实体\n * 适用于绝对禁止用户输入 HTML 内容的场景\n */\nvar escapeHTMLProperty = function( str ) {\n    if (!str) return '';\n    // \u0026 的转译必须放在所有转译的最前面\n    str = str.replace(/\u0026/g, '\u0026amp;')\n        .replace(/\u003c/g, '\u0026lt;')\n        .replace(/\u003e/g, '\u0026gt;')\n        .replace(/\"/g, '\u0026quto;')\n        .replace(/'/g, '\u0026#39;');\n    // 一般不对空格进行转译\n    // .replace(/ /g, '\u0026#32;')\n    return str;\n}\n```\n\n#### 1.1.2 JavaScript 代码\n\nJavaScript 中可以直接使用 `JSON.stringify( str )` 方法进行转译\n\n### 1.2 富文本\n\n采用过滤的方式进行防御\n\n#### 1.2.1 黑名单过滤\n\n```javascript\n/**\n* 采用 黑名单过滤 对富文本内容进行过滤\n* 次方法的问题在于 XSS\b攻击 的变种很多，很难对所有情况进行逐一过滤\n* 此处仅做演示，并不会用于真实环境\n*/\nvar xssFilter = function ( html ) {\n    if (!html) return '';\n    html = html.replace(/\u003c\\s*\\/?script\\s*\u003e/g, '') // 替换 \u003cscript\u003e 标签\n        .replace(/javascript:[^'\"]*/g, ''); // 替换 javascript='' 的调用（常出现在 a 标签）\n        .replace(/onerror\\s*=\\s*['\"]?[^'\"]*['\"]?/g, '') // 替换 \u003cimg src=\\'abc\\' onerror=\\'alert(1)\\' /\u003e 一类的攻击\n    // 还有 SVG\\Object 等 XSS攻击 手段还未进行过滤\n    return html;\n}\n```\n\n#### 1.2.2 白名单过滤\n\n白名单过滤需要先解析 HTML。  \n**方法一**：这里采用 [cheerio](https://cheerio.js.org) 这个库进行解析。(cheerio的使用与 jQuery 类似，比较容易上手)\n\n```shell\n# 安装 cheerio\nnpm install cheerio --save-dev\n```\n\n```javascript\n/**\n * 采用 白名单过滤+cheerio 对富文本内容进行过滤\n * 需要维护白名单列表，有较好的定制化和灵活性\n */\nvar xssFilter = function ( html ) {\n     if (!html) return '';\n     // 白名单列表\n     var whiteList = {\n         'img': ['src'],\n         'font': ['color', 'size'].\n         'a': ['href'],\n     };\n    // 引入 cheerio\n    var cheerio = require('cheerio');\n    var $ = cheerio.load(html);\n    $('*').each(function (index, e) {\n        // 当标签名不在白名单中时，将其移除(name 为标签名)\n        if (whiteList[e.name]) $(e).remove(); return;\n        // 当标签名在白名单时，对其属性进行判断(attribs 为标签的属性集合)\n        for (var attr in e.attribs) {\n            // 当属性名不在相应标签的属性列表中时，将其移除\n            // （cheerio 中将属性设为 null 即为移除该属性）\n            if (whiteList[e.name].indexOf(attr) === -1) $(e).attr(attr, null);\n        }\n    })；\n    return html;\n}\n```\n\n**方法二**：使用第三方 XSS 白名单防御库 [js-xss](https://github.com/leizongmin/js-xss)\n\n```shell\n# 安装 js-xss\nnpm install xss --save-dev\n```\n\n```javascript\n/**\n * 采用 白名单过滤+js-xss 对富文本内容进行过滤\n * 快捷、方便，灵活性较差，不需要/少量的白名单维护\n */\nvar xssFilter = function ( html ) {\n    if (!html) return '';\n    var xss = require('xss');\n    return xss(html);\n}\n```\n\n### 1.3 [CSP](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP) (Content Security Policy) 内容安全策略\n\nCSRF原理：在用户不知情的倩况下冒充用户身份对目标网站发送请求。\n\n可指定可执行的内容。\n\n```html\n\u003c-这只是一个示例，具体的写法以及参数的意义请参见上方的链接-\u003e\n\u003cmeta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self'; img-src https://*; child-src 'none';\"\u003e\n```\n\n## 2. 跨站请求伪造 CSRF (Cross Site Request Forgy)\n\n**CSRF**：是一种常见的冒用用户身份的方法  \n\u003e **攻击特点**：\n\u003e 1. B 网站向 A 网站请求\n\u003e 2. 请求带 A 网站 Cookies\n\u003e 3. 不访问 A 网站前端\n\u003e 4. referer 为 B 网站\n\n### 2.1 SameSite Cookie，防止 CSRF 攻击\n\n此方法可有效防止对用户身份( Cookies )的冒用，但仍然可以进行匿名攻击，需要对匿名用户的权限进行控制。(此方法的[兼容性](https://caniuse.com/#search=SameSite)不好)  \n[SameSite Cookie，防止 CSRF 攻击](http://www.cnblogs.com/ziyunfei/p/5637945.html)  \n[SameSite - OWASP](https://www.owasp.org/index.php/SameSite)\n\n### 2.2 在前端页面加入验证信息\n\n此方法可防止 CSRF 攻击中不访问被攻击网站前端的问题\n\n1. 验证码\n\n[ccap](https://github.com/DoubleSpout/ccap) 这是一个生成验证码的库。这种方式对用户体验有较大影响，不适宜大量使用。\n\n2. token\n\n```javascript\n// 此变量为随机生成并取整，将会放在页面表单及Cookies中\nvar csrfToken = parseInt(Math.random() * 9999999, 10);\n```\n\n### 2.3 通过 referer 禁止来自第三方网站的强求\n\n[[JS] js 获取 referer,兼容各种浏览器](https://www.51-n.com/t-4016-1-1.html)\n\n## 3. 前端 [Cookies](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies) 安全性\n\n**Cookies**：前端数据存储\n\n### 3.1 Cookies 的特点\n\n* 前端数据存储（大小：4kb 左右）\n* 后端可通过 http 头进行设置\n* 请求时通过 http 头传给后端\n* 前端可读写\n* 遵守同源策略  \n\u003e 同源策略：对于 Cookies 而言，同一个源下的 Cookies 才能读写。  \n\u003e 源：当协议、域名、端口全部一致时才叫同源。\n\n### 3.2 Cookies 的特性\n\n* 域名：指定 Cookies 的使用范围。\n* 有效期：指定 Cookies 的有效期，过期后就会失效。\n* 路径：指定 Cookies 作用于网站上的哪一级，具体为 URL 的层级。可以为不同层级的 URL 设置不同的 Cookies，只有当这个层级的页面被访问时对应的 Cookies 才能被访问。\n* http-only：Cookies 只能被 HTTP协议 使用，不能被 JavaScript 读取。\n* Secure：指定 Cookies 是否只能在 HTTPS 的网站中使用，指定后在 HTTP 的网站中则不能使用。\n* SameSite：指定第三方网站的请求是否可以使用 Cookies。([2.1 SameSite Cookie，防止 CSRF 攻击](#21-samesite-cookie防止-csrf-攻击))\n\u003e 浏览器开发者工具中查看 Cookies 信息：\n\u003e 在 浏览器的开发者工具 -\u003e Application/存储空间 -\u003e Cookies 就可以找到 Cookies 信息。\n\u003e * Name（名称）: 健\n\u003e * Value（值）: 值\n\u003e * Domain（域）: 域名\n\u003e * Path（路径）: 路径\n\u003e * Expires / Max-Age（过期时间）: 有效期（Session 表示只在会话内有效）\n\u003e * Size（大小）: 大小\n\u003e * HTTP（HTTP）: http-only\n\u003e * Secure（安全）: Secure\n\u003e * SameSite（相同站点）: SameSite（不是所有浏览器都有此属性）  \n\u003e\n\u003e 英文名称参考Google Chrome 70.0.3538.102（正式版本）（64 位）,中文名称参考Safari 浏览器12.0.1 (14606.2.104.1.1)\n\n### 3.3 Cookies 操作\n\n* 读取 Cookies：document.cookie\n* 设置 Cookies 有效期：document.cookie = 'a=1;expires=Tue, 27 Nov 2018 03:40:29 GMT'\n* 删除 Cookies：并没有删除 Cookies 的方法，但可以通过给 Cookies 的有效期设置一个过去的时间，就可以删除 Cookies。\n\u003e expires 的值为过期时间，且只能为此格式，此格式时间的快速获取方法：  \n\u003e ```javascript\n\u003e var d = new Date();\n\u003e d.toGMTString();\n\u003e ```\n\n### 3.4 Cookies 作用\n\n* 存储个性化设置\n* 存储未登录时用户的唯一标识\n* 存储已登陆用户的凭证\n* 存储其他业务数据（页面缓存）\n\n\u003e Cookies - 登陆用户凭证\n\u003e * 前端提交用户信息\n\u003e * 后端验证用户信息\n\u003e * 后端通过 HTTP 头设置用户凭证\n\u003e * 后续访问时后端先验证用户凭证\n\n### 3.5 Cookies 安全问题\n\n#### 3.5.1 生成用户凭证\n\n* 用户ID，使用用户ID作为用户的标示并不安全，有被篡改的风险\n* 用户ID + 签名：可防止 用户ID 被篡改，Cookies 中会同时存储用户ID和签名，作为校验。\n\n```javascript\n// 加密签名模块\n// crypto 为 Node\bJs 自带的加密模块\nimport crypto from 'crypto';\nvar crypt = {};\n// 随机的字符，越复杂越安全\nconst key = '#@56562366\u0026##%';\ncrypt.cryptUserId = function( userId ) {\n    var sign = crypto.createHmac('sha256', key)\n    sing.update( userId + '' );\n    return sign.digest( 'hex' );\n}\nexport crypt;\n```\n\n* SessionId：在 Cookies 中不存储任何用户信息，后端可通过 SessionId 判断用户的身份\n\n```javascript\n/** \n* SessionId\n*/ \nvar session = {};\nvar cache = {};\n\nsession.set = function( userId, obj) {\n    var sessionId = Math.random();\n    if ( !cache[sessionId] ) {\n        cache[sessionId] = {};\n    }\n    cache[sessionId].content = obj;\n    return sessionId;\n}\n\nsession.get = function( userId ) {\n    return cache[sessionId] \u0026\u0026 cache[sessionId].content;\n}\nexport session;\n```\n\n#### 3.5.2 Cookies 和 XSS 的关系\n\n* XSS 可能偷取 Cookies\n* http-only 的 Cookies 不会被偷（[3.2 Cookies 的特性](#32-Cookies-的特性)）\n\n#### 3.5.3 Cookies 和 CSRF 的关系\n\n* CSRF 利用了用户 Cookies\n* 攻击站点无法读写 Cookies（[2.2 在前端页面加入验证信息](#22-在前端页面加入验证信息)）\n* 最好能阻止第三方使用 Cookies（[2.1 SameSite Cookie，防止 CSRF 攻击](#21-samesite-cookie防止-csrf-攻击)）\n\n### 3.6 Cookies 安全策略\n\n* 签名防篡改（[3.5.1 生成用户凭证](#351-生成用户凭证)）\n* 私有变换（加密）\n\n```javascript\n// node 中的加密\nimport crypto from 'crypto';\n\n// 密钥\nvar key = '22e323##%\u0026@%#$565';// 越复杂，越安全\n\n// 加密\n// 创建加密对象\nvar cipher = crypto.createCipher('des', key);\ncipher.update('hello world', 'utf8', 'hex');\ntext += cipher.final('hex');\n\n// 解密\n// 创建解密对象\nvar decipher = crypto.createDecipher('des', key);\ndecipher.update(text, 'hex', 'utf8');\noriginalText += decipher.final('utf8');\n// 加密和解密过程均为流式输出，因此要采用 += 接收，否则只会有部分内容。\n```\n\n* heep-only（防止XSS）（[3.2 Cookies 的特性](#32-Cookies-的特性)）\n* secure（防止传输过程中的窃听）（[3.2 Cookies 的特性](#32-Cookies-的特性)）\n* SameSite（[2.1 SameSite Cookie，防止 CSRF 攻击](#21-samesite-cookie防止-csrf-攻击)）\n\n## 4. 点击劫持\n\n**点击劫持**：是一种常见的利用用户的身份，在用户不知情的情况下完成操作的一种攻击\n\u003e 点击劫持的特点：\n\u003e * 用户操作，但不知情\n\u003e * 通过点击能进行的操作都可以通过点击劫持进行\n\n### 4.1 点击劫持的原理\n\n将目标网站作为一个 iframe 嵌入到攻击者网站中，并在视觉上进行隐藏（如调整透明度），用户看不见这个 iframe。对用户的点击进行引导，使用户进行一些指定的操作（如某种游戏），从而实现特定的目的（如银行转账）。  \n\n### 4.2 点击劫持的前提\n\n目标网站能够被攻击网站嵌套在 iframe 中。  \n\n### 4.3 点击劫持的防御\n\n未内嵌的网站与内嵌网站的区别在于，未内嵌的网站的 `top === window` 和 `top.location === window.location` 均为 `true`。而在 iframe 中 `top` 指向最外层的 `window`，`window` 指向 iframe 本身，结果为 `false`。\n\n* JavaScript 禁止内嵌\n\n```javascript\n/** \n* JavaScript 禁止内嵌\n* 此方法的问题在于 HTML5 iframe 中有一个新的属性\n* [sandbox](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/iframe)\n* sandbox='allow-forms' 时可以正常提交表单，但不会执行脚本，导致此方法失效\n*/\nif ( top.location !== window.location ) {\n    top.location = window.location;\n}\n```\n\n* [X-FRAME-OPTIONS](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/X-Frame-Options) 禁止内嵌（推荐）\n* 辅助手段 [2.2 在前端页面加入验证信息](#22-在前端页面加入验证信息)\n\n* IFrame 安全策略（允许内嵌）\n\n[IFrame 沙盒](https://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/)\n\n## 5. 传输过程安全问题\n\nHTTP 传输窃听和篡改：由于 HTTP 采用明文传输信息，导致请求发送过程中的所有设备（浏览器、代理服务器、链路、服务器等）均可读取甚至篡改发送的数据。\n\n```bash\n# 查看向一个 url 发送请求时会经过那些中间节点\n# 其中所展示的任何一个节点均可进行 HTTP 传输窃听和篡改\n# Mac OS/Linux\ntraceroute url\n# Windows\ntracert url\n```\n\n### 5.1 HTTP 传输窃听和篡改的危害\n\n* 窃听通过网络传输的一切信息，包括敏感信息（账号、密码等）\n* 插入广告\n* 重定向网站（如钓鱼网站）\n* 无法防御的 XSS 和 CSRF 攻击\n\n### 5.2 HTTPS TLS(SSL) 加密\n\n确认服务器身份的原理：\n\n1. 浏览器 -\u003e CA 获取内置信任列表\n2. 服务器 -\u003e CA 申请证书\n3. CA -\u003e 服务器 验证域名，颁发证书\n4. 浏览器 -\u003e 服务器 发起请求\n5. 服务器 -\u003e 浏览器 出具证书\n6. 浏览器 验证通过\n\nCA 安全的原则：\n\n* 证书无法伪造\n* 这书私钥不能泄露\n* 域名管理权不能泄露\n* CA 遵守原则\n\n\u003e 浏览器开发者工具中查看 这书 信息：\n\u003e 在 浏览器的开发者工具 -\u003e Security 点击 View Certificate 就可以查看 这书 信息。\n\u003e \n\u003e Mac OS 中查看本机中受信任的证书：\n打开 钥匙串访问（keycha）程序 -\u003e 系统跟证书 就可以查看系统中所有受信任的证书\n\n### 5.3 部署 HTTPS 的网站\n\n[https配置与部署 - 向上爬的蜗牛 - CSDN博客](https://blog.csdn.net/abld99/article/details/74011487)\n\n## 6. 用户密码安全问题（接入层）\n\n### 6.1 密码的作用\n\n证明用户身份：将存储的密码与输入的密码进行比对以确认用户身份。  \n\n**密码的泄露渠道**\n\n* 数据库被盗\n* 服务器被入侵\n* 通许被窃听\n* 内部人员泄露数据\n* 其他网站（撞库）：多网站采用相同的账号密码，一个被盗殃及其他\n\n### 6.2 密码的存储\n\n#### 6.2.1 密码的存储原则\n\n* 严禁明文存储（防泄漏）\n* 单向变换（防泄漏）\n* 变换复杂度要求（防猜解）\n* 密码复杂度要求（防猜解）\n* 加盐（防猜解）\n\n#### 6.2.2 密码存储方案\n\n1. 哈希算法（信息摘要）\n* 明文 - 密文 一一对应\n* 雪崩效应：明文的些许差异会导致完全不同的密文\n* 密文 - 明文 无法反推\n* 密文是固定的长度\n* 常见的哈希算法：[md5](https://zh.wikipedia.org/zh-hans/MD5) | [sha1](https://zh.wikipedia.org/wiki/SHA-1) | [sha256](https://zh.wikipedia.org/wiki/SHA-2)\n\n[单向变换彩虹表](https://cmd5.com) 会导致简单的密码及加密变得不安全。由于彩虹表的计算及存储限制，使用复杂的密码（长度 + 复杂度）即可大幅减少密码被反推的威胁。  \n\n2. 帮助用户加强复杂度：\n* 多级加密（防止彩虹表反推）\n* 增加密码长度：在用户密码的基础上增加固定的字符（防止彩虹表反推）\n* 加盐：增加用户唯一的字符（提高安全性）\n\n\u003e 多级（嵌套）加密的好处：\n\u003e * 变换越多越安全\n\u003e * 加密成本几乎不变（密码的生成会慢一些）\n\u003e * 彩虹表失效（密码足够复杂）\n\u003e * 解密成本倍增（更安全）\n\n```javascript\n/**\n* 密码加密\n* 这里只做了两次加密，不是很安全\n* 实际项目中可使用多协议多次加密，可提高安全性\n*/\nimport crypt from 'crypto';\nlet password = {};\n\nconst md5 = (str) =\u003e {\n    const md5Hash = crypt.createHash('md5');\n    md5Hash.update(str);\n    return md5Hash.digest('hex');\n}\n\nconst salt = () =\u003e {\n    // 这里采用硬编码添加字符串，字符串一旦添加不能改变且越复杂越安全\n    return md5(Math.random() + 999999 + 'fd4fb5 e#687f%$@_%%$#32' + new Date().getTime());\n}\n\npassword.encryptPassword = (password) =\u003e {\n    return md5(salt + password);\n}\n\nexport password;\n```\n\n### 6.3 密码的传输\n\n#### 6.3.1 HTTPS传输\n\n[5.3 部署 HTTPS 的网站](#53-部署-HTTPS-的网站)\n\n#### 6.3.2 频率限制（防猜解）\n\n此处不做说明\n\n#### 6.3.3 前端加密（作用有限）\n\n添加 [js-md5](https://github.com/emn178/js-md5) 模块\n\n```bash\nnpm install -save-dev js-md5\n```\n\n```javascript\nimport md5 from 'js-md5';\n// 此处只是示例，可增加加密字符串的复杂度以提高安全性\nconst password = md5(password)\n```\n\n### 6.4 密码的替代方案\n\n1. 生物特征密码\n    * 指纹\n    * 声纹\n    * 虹膜\n    * 人脸识别\n\n生物特征密码的问题：\n\n* 私密性 - 容易泄露\n* 安全性 - 碰撞（生物识别采用相似性进行匹配，并不能保证完全匹配）\n* 唯一性 - 终身唯一，无法改变（一旦被破解很难改变）\n\n## 7. SQL注入攻击\n\n### 7.1 SQL 注入危害\n\n* 猜解密码\n* 获取数据\n* 删库删表\n* 拖库\n\n### 7.2 SQL 注入防御\n\n* 关闭错误输出（不要将错误信息抛到前台，应做模糊处理）\n* 检查数据类型（对传入 SQL 的数据做类型检查，包括用户输入的和层序获取的，以防篡改）\n* 对数据进行转译（转译不能防止所有的 SQL 注入）\n\n```javascript\nconst mysql = require('mysql');\nexports.getConnection = function(){\n    /** \n     * 此为 Mysql 对象\n    */\n    let connection = mysql.createConnection({\n        host: 'localhost',\n        database: 'safety',\n        user: 'root',\n        password: '123456789'\n    });\n    connection.connect();\n    return connection;\n};\n\n// 参数转译方法\nconnection.escape(id);\n// 一、转译 SQL 语句\n`select * from table where id = ${ connection.escape(id) }`\n// 二、通过类似参数化查询，在传递参数前会进行转译\n`select * from table where id ?`, [id]\n```\n\n* 使用参数化查询（避免 SQL 注入威胁）  \n\n[mysql2](https://github.com/brianmario/mysql2) 可以支持 MySQL 参数化查询，从而避免 SQL 注入的威胁。mysql2 为第三方工具，向下兼容 mysql\n\n* 使用 [ORM（对象关系映射）](https://zh.wikipedia.org/wiki/%E5%AF%B9%E8%B1%A1%E5%85%B3%E7%B3%BB%E6%98%A0%E5%B0%84)  \n\n[Sequelize](https://demopark.github.io/sequelize-docs-Zh-CN/) | [Github](https://github.com/sequelize/sequelize) ：是一个Node.js ORM, 目前支持 Postgres, MySQL, SQLite 和 Microsoft SQL Server.  \n安装 Sequelize\n\n```bash\n# 安装 Sequelize\nnpm install --save-dev Sequelize\n# 还有以下之一:\n$ npm install --save pg pg-hstore // Postgres\n$ npm install --save mysql2 // MySQL\n$ npm install --save sqlite3 // SQLite\n$ npm install --save tedious // MSSQL\n```\n\n```javascript\n/**\n * sequelize.js\n * Sequelize 实例\n * 此处引入的为刚才安装的 sequelize 第三方库\n */\nimport Sequelize from 'sequelize';\n\nlet sequelize = new Sequelize({\n    host: 'localhost',\n    database: 'safety',\n    username: 'root',\n    define: {\n        freezeTableName: true,\n    },\n});\nexport sequelize;\n// -------------------------------------------\n/**\n * Post.js\n * 使用 Sequelize 定义的数据模型\n * 此处引入的为刚才创建的 sequelize 实例sequelize.js，\n * 此处一定注意区分\n */\nimport sequelize from './sequelize'; // 实例\nimport Sequelize from 'sequelize'；// \b模块\n\nvar Post = sequelize.define('post', {\n    // 字段\n},\n{\n    // 此处可不加\n    // 如果添加 则为指定表名\n    // 如果不加 sequelize 会尝试对应表名\n    tableName: 'post'.\n});\nexport Post;\n```\n\n### 7.3 NoSQL 注入和防御\n\n[mongoose](https://mongoosejs.com) | [Github](https://github.com/Automattic/mongoose)\n\n## 8. 上传问题（接入层）\n\n### 8.1 上传文件的问题\n\n* 文件由用户上传\n* 用户能够通过 Url 访问上传的文件\n* 访问时文件可能会当作程序执行\n\n### 8.2 上传漏洞防御\n\n#### 8.2.1 限制上传后缀（有时不可靠）\n\n```javascript\n/**\n* 禁止用户上传 JS 文件（有时此方法会不可靠）\n* 此处只做演示，在 Nodejs 环境中几乎没有上传漏洞\n* 但在如 PHP 中，上传漏洞较为严重\n* 不同语言的文件处理不同，需要不同的防御方式\n*/\nimport path from 'path';\n// file 为上传的文件对象\n// 此处为取文件后缀名\nconst ext = path.extname(file.name);\nif (ext === 'js') throw new Error('不能上传js文件');\n```\n\n### 8.2.2 文件类型检查（可绕过）\n\n```javascript\n/**\n* 文件类型检查（此方法为浏览器提供，可绕过）\n* 不同语言的文件处理不同，需要不同的防御方式\n*/\nif (file.type !== 'image/png') throw new Error('上传的文件类型错误');\n```\n\n### 8.2.3 文件内容检查（可欺骗）\n\n```javascript\n/** \n* 文件内容检查（可欺骗）\n* 由于同一类型文件的前几位二进制位是相同的，可以根据此特性进行判断\n* 但可通过修改文件前几位让层序误判文件类型\n*/\nimport fs from 'fs';\n\nconst fileBuffer = fs.readFileSync(file.path);\nfileBuffer[0] == ox5b;\n```\n\n### 8.2.4 程序输出（防止文件被当作程序执行）\n\n在访问莫文件时不直接输出，而是通过程序读取文件再输出，从而阻止了文件的执行。Node.js 的 fs 模块就是采用的这种方式，因此在 Node.js 中几乎不存在上传文件漏洞，在其他环境中可以使用此方法进行防御。此方法会有一定的性能损失。\n\n```javascript\nimport fs from 'fs';\n\nfs.readFileSync(filePath);\n```\n\n#### 8.2.5 权限控制 - 可写可执行互斥\n\n对目录文件权限进行控制，可写（如用户上传的文件）目录中的不给予执行权限，可执行（如程序文件）目录不给予写入权限，防止攻击中篡改和注入。\n\n## 9. 信息泄露和社会工程学\n\n### 9.1 信息泄露\n\n* 泄露系统的敏感信息\n* 泄露用户的敏感信息\n\n### 9.2 信息泄露的途径\n\n* SQL注入\n* XSS / CSRF\n* 错误信息失控：将错误信息直接暴露\n* 水平权限控制不当：系统中用户权限管理不当\n\n### 9.3 信息保护\n\n[OAuth 思想](https://zh.wikipedia.org/wiki/%E5%BC%80%E6%94%BE%E6%8E%88%E6%9D%83)~\n\n* 一切行为由用户授权\n* 授权行为不泄露敏感信息（请求授权的网站只能拿到 token，根据此 token 确认用户身份）\n* 授权会过期\n\n使用 OAuth 思想 防止数据泄露\n\n* 用户授权读取资料\n* 无授权资料不可读取\n* 不允许批量获取数据\n* 数据接口可风控审计\n\n## 10 安全策略\n\n1. [内容安全策略简介](https://www.html5rocks.com/en/tutorials/security/content-security-policy/)  \n2. [IFrame 沙盒](https://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/)\n\n---\n\n[context](https://www.contextis.com/en/resources)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchanmenglin%2Fwebsecurity","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchanmenglin%2Fwebsecurity","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchanmenglin%2Fwebsecurity/lists"}