不可不知的前端工程化——安全漏洞防护&数据加密
写在前面
对前端而言,由于直接与用户进行交互,涉及到用户数据的展示,并承载着用户输入的一些敏感信息,那如何对用户隐私的保护,防止重要数据泄露,以及防止跨站脚本攻击(XSS)等安全问题的重视与防护就显得尤为重要。现如今,通过安全漏洞扫描,在上线前对项目进行漏洞修复,必要时对敏感数据进行加密处理,已然成为项目能否顺利发布必不可少的环节。
前端常见的安全问题及解决方案
HTTPS
在前端应用中,使用 HTTPS 来进行数据传输加密。HTTPS 需要在服务器端配置 SSL/TLS 证书,而前端代码无需做特殊处理,HTTPS 会自动对数据进行加密传输。
使用方法
- 在服务器上配置 SSL/TLS 证书。
- 将网站的链接协议改为 HTTPS。
- 示例代码:
<!-- 使用 HTTPS 加载外部资源 -->
<script src="https://example.com/script.js"></script>
<img src="https://example.com/image.png" alt="Image">
<!-- 将当前页面重定向到 HTTPS -->
<script>
if (location.protocol !== 'https:') {
location.href = 'https://' + location.host + location.pathname + location.search;
}
</script>
跨站脚本攻击 (XSS)
XSS攻击如何操作?
- 攻击者找到一个存在XSS漏洞的前端应用程序,通常是通过输入框、表单提交等用户输入的地方。
- 攻击者在输入框或其他可注入代码的地方注入恶意脚本代码,如
<script>alert('XSS Attack!');</script>
。 - 当用户浏览该页面时,恶意脚本会在用户的浏览器中执行,导致攻击者能够执行任意操作,如窃取用户的登录凭据、篡改页面内容等。
如何进行XSS防护?
- 输入验证和过滤:对用户输入的数据进行严格验证和过滤,过滤掉或转义特殊字符,确保只接受预期的输入。例如,使用 HTML 编码或 DOM 转义函数来转义用户输入中的特殊字符。
function escapeHTML(input) {
return input.replace(/</g, '<').replace(/>/g, '>');
}
- 输出转义:在将用户输入数据插入到 HTML 页面中时,使用合适的转义函数进行输出转义,确保用户输入不会被当做代码执行。例如,使用
innerText
或textContent
属性来设置元素的文本内容,而不是使用innerHTML
。
var userInput = '<script>alert("XSS Attack!");</script>';
element.innerText = userInput; // 转义用户输入,避免代码执行
- HTTP 头设置:在响应中设置合适的 Content-Security-Policy (CSP) 头,限制页面中可执行的脚本来源和其他资源加载来源,防止恶意脚本的注入。例如,设置
Content-Security-Policy: script-src 'self'
,只允许从同一域名加载脚本。
<!-- 在响应头中设置 Content Security Policy -->
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'
<!-- 或者使用 meta 标签设置 Content Security Policy -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'">
- 定期更新依赖库和框架:保持前端应用程序的依赖库和框架更新到最新版本,以获得最新的安全补丁和漏洞修复。
跨站请求伪造 (CSRF)
跨站请求伪造(CSRF)是一种攻击方法,攻击者通过伪造合法用户的请求,使用户在不知情的情况下执行非授权的操作。
CSRF攻击如何操作?
- 攻击者创建一个恶意网站,并在其中包含一个针对目标网站的请求。
- 诱使用户访问恶意网站,浏览器加载了恶意网站的内容。
- 恶意网站中的请求会利用用户在目标网站的登录状态,向目标网站发送一个伪造的请求。
- 目标网站认为该请求是合法的,执行了攻击者预期的操作,如修改用户信息、执行付款等。
如何进行CSRF防护?
- 验证来源请求:在目标网站的后端,对每个请求进行验证,确保请求来自合法的源。常见的方法是在请求中添加一个CSRF令牌(也称为防跨站请求伪造令牌)并验证该令牌的有效性。示例代码如下:
// 后端随机生成并发送给前端一个CSRF令牌
const csrfToken = generateCSRFToken();
res.cookie('csrfToken', csrfToken);
// 前端发送请求时,将令牌添加到请求头或请求参数中
const headers = { 'X-CSRF-Token': csrfToken };
axios.post('/api/endpoint', data, { headers });
// 后端在处理请求时,验证请求头或请求参数中的CSRF令牌的有效性。
- 使用SameSite属性:设置Cookie的SameSite属性为Strict或Lax,限制Cookie只能在同一站点下发送,防止被恶意网站伪造请求。示例代码如下:
res.cookie('sessionId', sessionId, { sameSite: 'strict' });
敏感数据处理
在前端使用加密算法对用户敏感数据进行加密,确保数据在传输和存储过程中的安全性。常见的前端加密方法包括对称加密和非对称加密。
对称加密(Symmetric Encryption
使用同一个密钥(称为对称密钥)进行加密和解密数据。在加密过程中,原始数据使用对称密钥进行加密,生成密文。在解密过程中,使用相同的对称密钥对密文进行解密,恢复出原始数据。常见的对称加密算法包括DES、AES和RC4等。
非对称加密(Asymmetric Encryption
使用一对密钥(称为公钥和私钥)进行加密和解密数据。在加密过程中,原始数据使用公钥进行加密,生成密文。在解密过程中,使用私钥对密文进行解密,恢复出原始数据。常见的非对称加密算法包括RSA和ECC(椭圆曲线加密)等。
加密解密示例
jsencrypt
是一个用于在前端浏览器中进行非对称加密和解密的 JavaScript 框架。它基于RSA算法,可以使用encrypt
公钥加密数据,在后端使用decryp
私钥进行解密。以下是使用 jsencrypt 进行数据加密和解密的示例代码:
import JSEncrypt from 'jsencrypt'
// RSA加密
// 创建 JSEncrypt 实例
const encrypt = new JSEncrypt();
// 设置公钥
encrypt.setPublicKey(publicKey);
// 待加密的数据
let data = 'sensitive data';
// 加密数据
let encryptedData = encrypt.encrypt(data);
console.log('加密后的数据:', encryptedData);
// RSA解密
const decrypt = new JSEncrypt()
decrypt.setPrivateKey(
`-----BEGIN RSA PRIVATE KEY-----${privateKey}-----END RSA PRIVATE KEY-----`
)
let data = decrypt.decrypt(JSON.stringify(data))
使用 CryptoJS 进行 AES 加密和解密
<script src="crypto-js.min.js"></script>
<script>
// 加密密钥,需要妥善保管
const encryptionKey = '加密密钥';
// 敏感数据
const sensitiveData = '敏感数据';
// 加密
const encryptedData = CryptoJS.AES.encrypt(sensitiveData, encryptionKey).toString();
// 存储加密后的数据
localStorage.setItem('encryptedData', encryptedData);
// 解密
const decryptedData = CryptoJS.AES.decrypt(encryptedData, encryptionKey).toString(CryptoJS.enc.Utf8);
</script>
防止敏感信息泄露
在代码中避免将敏感信息(如 API 密钥、密码等)直接硬编码,而是使用环境变量或配置文件来存储这些敏感信息,并在部署时进行配置。
// 使用环境变量存储敏感信息
const apiKey = process.env.API_KEY;
const apiSecret = process.env.API_SECRET;
结尾
以上,是本人目前在项目中遇到过的常见安全问题且常用的解决方案,如还有遗漏的且需要注意的点,欢迎小伙伴们在评论区留言讨论哦,感谢感谢😄
转载自:https://juejin.cn/post/7251786209340244028