后端安全
后端常见安全方面的问题
- SQL 注入:窃取修改数据库内容
- XSS 攻击:窃取前端的 cookie 内容(前端可以处理)
- 密码加密:⚠️ 保障用户信息安全
Tip
有些攻击需要硬件和服务来支持(OP 支持),如 DDOS 攻击
SQL 注入
最原始、最简单的攻击,通过输入一个 SQL 片段,最终在服务器端拼接为完整 SQL 语句时就可以成为攻击代码。
- 攻击:可以通过输入特殊字符
--
(最后含一个空格) 来注释掉 SQL 后面的内容。
当登录时使用用户提供的username
和password
来拼接 SQL 语句时jsconst login = (username, password) => { const sql = `select username, realname from users where username='${username}' and password='${password}';` //... }
可以在用户名一栏填入username' --
拼接形成的 SQL 语句的后半部分将被注释,这样就可以使用任意密码完成登录。如输入用户名Ben' --
和密码666
(不正确),拼接后可以得到的 SQL 语句是select username, realname from users where username='Ben' -- ' and password='666';
- 防御:使用函数
escape()
处理拼接 SQL 语句的变量,该函数对于用户输入的特殊字符进行转义。
通过sql.escape()
函数来处理用户提供的内容(非字符串形式),再用来拼接 SQL 语句jsconst mysql = require('mysql2') // ... const login = (username, password) => { username = escape(username); password = escape(password); const sql = `select username, realname from users where username=${username} and password=${password};` // ... }
如果输入的内容含有特殊的字符,该函数会对其进行转义,如输入用户名Ben' --
和密码666
(不正确),则拼接后可以得到的 SQL 语句是select username, realname from users where username='Ben\' -- ' and password='1';
XSS 攻击
在页面展示内容掺杂 JavaScript 代码,以获取用户的敏感信息,如 cookie、session id 等。
- 攻击:在博客系统创建内容,如果有的用户混入恶意的 JavaScript 代码,当博文内容没有经过处理直接展示出来,其他用户访问该文章时这些 JavaScript 代码就会运行,可能会泄露敏感信息。
- 防御:对用户输入的内容中特殊字符进行转义,特别是可能在 HTML 页面表示代码的
<
和>
符号
常见需要转义的字符
字符 | 转移后的字符 |
---|---|
& | &: |
< | < |
> | gt; |
" | " |
' | ' |
/ | / |
使用模块 xss 对用户输入内容进行转译。
js
const xss = require('xss')
let content = xss(content); // 使用 xss 模块对输入的内容进行转译
如果用户输入的内容是 <script>alert(1)</script>
则经过 xss
转译后的内容是 <script>alert(1)</script>
Tip
存储在数据库中的内容是通过 xss
模块转译后的内容,不具有攻击功能。如果再从数据库读取相应的内容展示在页面时,需要前端进行反转译,以使内容正确显示。
密码加密
当数据库被攻破,如果内容经过加密,可以避免用户真实信息马上被泄露。
- 攻击:获取用户在某个网站的用户名和密码,再去尝试登录其他系统
- 防御:将密码存储到数据库前进行加密,即使攻破了数据库获取数据也不知道密码明文
用户注册时提供明文密码,服务器使用特定的密钥和加密算法对它进行加密(密钥存储在 Node.js 服务器中),再将加密后的一串「乱码」存储在 MySQL 数据库中(在 MySQL 数据库中并不存储明文密码);然后用户登录时提供明文密码,服务器使用相同的密钥和加密算法对明文密码进行加密,得到的「乱码」再用于在数据库中的匹配查找。
密钥和(加密后的)数据分别存储在不同的服务器中,通过这种方式存储密码即使数据库被攻破后,也不会造成密码明文立即泄露。
js
// crypto 是 Node.js 提供的一个用于加密的模块
const crypto = require('crypto')
// 密钥
const SECRET_KEY ='advbs'
// md5 加密
function md5(content) {
let md5 = crypto.createHash('md5')
return md5.update(content).digest('hex') // 以 16 进制方式输出
}
// 加密函数
function genPassword(password) {
const str = `password=${password}&&key=${SECRET_KEY}` // 拼接字符串,其中需要包含密码和密钥
return md5(str) // 使用 md5 方式加密
}
// const result = genPassword('123')
// console.log(result);
module.exports = {
genPassword
}