【Node.js从基础到高级运用】十八、Node.js的安全性加固

引言

在Web开发中,安全性是一个不可忽视的话题。Node.js作为一个流行的后端平台,同样需要关注各种潜在的安全威胁,并采取措施加以防御。本文将介绍如何在Node.js应用中防御常见的Web攻击,以及如何使用安全相关的中间件来加固安全性。

防御常见的Web攻击

防御XSS攻击

跨站脚本攻击(XSS)是一种常见的攻击方式,攻击者通过在页面插入恶意脚本,来盗取用户信息或者进行其他恶意操作。为了防御XSS攻击,我们需要对用户输入的内容进行转义处理。

const express = require('express');
const app = express();
//const bodyParser = require('body-parser'); // 引入body-parser模块用于解析请求体
//从Express 4.16.0版本开始,
//body-parser模块的功能已经被集成到了Express本身中,因此你可以不用单独安装body-parser,而是直接使用express.json()和express.urlencoded()中间件
app.use(express.json()); // 用于解析JSON格式的请求体
app.use(express.urlencoded({ extended: true })); // 用于解析URL编码的请求体
app.post('/submit-comment', (req, res) => {// 获取用户输入的评论内容let comment = req.body.comment;// 对评论内容进行HTML转义,防止XSS攻击comment = escapeHtml(comment);console.log('提交的内容:'+comment)// 存储评论内容到数据库等操作...// ...res.send('评论已提交');
});// HTML转义函数
function escapeHtml(text) {const map = {'&': '&amp;','<': '&lt;','>': '&gt;','"': '&quot;',"'": '&#039;'};return text.replace(/[&<>"']/g, (m) => map[m]);
}app.listen(3000, () => {console.log('Server is running on port 3000');
});

运行:
在这里插入图片描述
在这里插入图片描述

防御CSRF攻击

跨站请求伪造(CSRF)攻击是一种利用用户已登录的身份,在用户不知情的情况下进行恶意请求的攻击方式。为了防御CSRF攻击,我们可以使用CSRF令牌。

const express = require('express');
const csrf = require('csurf');
const cookieParser = require('cookie-parser');
const app = express();
app.use(express.json()); // 用于解析JSON格式的请求体
app.use(express.urlencoded({ extended: true })); // 用于解析URL编码的请求体
// 使用cookie-parser中间件来解析cookie
app.use(cookieParser());
// 设置CSRF保护
const csrfProtection = csrf({ cookie: true });app.get('/form', csrfProtection, (req, res) => {// 发送带有CSRF令牌的表单到客户端res.send(`<form action="/submit-form" method="POST"><input type="hidden" name="_csrf" value="${req.csrfToken()}"><input type="text" name="data"><button type="submit">提交</button></form>`);
});app.post('/submit-form', csrfProtection, (req, res) => {// 处理表单提交res.send('表单数据已提交');
});app.listen(3000, () => {console.log('Server is running on port 3000');
});

运行:
http://localhost:3000/form
在这里插入图片描述
http://localhost:3000/submit-form
在这里插入图片描述

防御注入攻击

注入攻击,尤其是SQL注入,是攻击者通过输入恶意数据,篡改后端数据库查询的一种攻击方式。为了防御注入攻击,我们应该使用参数化查询。

MongoDB
const express = require('express');
const mongoose = require('mongoose');
const app = express();
app.use(express.json()); // 用于解析JSON格式的请求体
app.use(express.urlencoded({ extended: true }));// 连接MongoDB数据库  注释掉用于运行测试用例
// mongoose.connect('mongodb://localhost:27017/userDB');// 创建用户模型
const User = mongoose.model('User', new mongoose.Schema({username: String,password: String
}));app.post('/login', async (req, res) => {// 获取用户输入的用户名和密码const { username, password } = req.body;try {// 使用Mongoose的查询方法,它会自动处理参数化查询,防止NoSQL注入const user = await User.findOne({ username, password }).exec();if (user) {res.send('登录成功');} else {res.send('用户名或密码错误');}} catch (error) {res.status(500).send('服务器错误');}
});// app.listen(3000, () => {
//   console.log('Server is running on port 3000');
// });module.exports = app;
mysql
const express = require('express');
const mysql = require('mysql');
const app = express();app.use(express.urlencoded({ extended: true }));// 创建数据库连接
const connection = mysql.createConnection({host: 'localhost',user: 'your_username',password: 'your_password',database: 'your_database'
});app.post('/login', (req, res) => {// 获取用户输入的用户名和密码const username = req.body.username;const password = req.body.password;// 使用参数化查询防止SQL注入const query = 'SELECT * FROM users WHERE username = ? AND password = ?';connection.query(query, [username, password], (error, results) => {if (error) throw error;if (results.length > 0) {res.send('登录成功');} else {res.send('用户名或密码错误');}});
});app.listen(3000, () => {console.log('Server is running on port 3000');
});

使用安全相关的中间件

使用Helmet加固HTTP头部

Helmet是一个集成了多个安全相关的HTTP头部设置的中间件,它可以帮助你设置一些安全相关的HTTP头部来增强应用的安全性。

const express = require('express');
const helmet = require('helmet');
const app = express();// 使用Helmet中间件
app.use(helmet());// 其他路由和中间件...
// ...app.listen(3000, () => {console.log('Server is running on port 3000');
});

使用rate-limiter-flexible限制请求频率

为了防止恶意用户或者机器人进行暴力破解或者DDoS攻击,我们可以使用rate-limiter-flexible来限制请求的频率。

const express = require('express');
const { RateLimiterMemory } = require('rate-limiter-flexible');
const app = express();
const port = 3000;// 配置内存中的限速器
const rateLimiter = new RateLimiterMemory({points: 5, // 允许每个IP在一定时间内累积的最大点数duration: 1, // 一个时间窗口的长度(秒)// 还有其他可配置的选项
});// 限速器中间件
const rateLimiterMiddleware = (req, res, next) => {rateLimiter.consume(req.ip).then(() => {next(); // 在未超出限制的情况下继续处理请求}).catch(() => {res.status(429).send('Too Many Requests'); // 当达到限制时发送429状态});
};app.use(rateLimiterMiddleware);app.get('/limit-query', (req, res) => {res.send('Hello World!');
});app.listen(port, () => {console.log(`App listening at http://localhost:${port}`);
});

测试:
为了自动化测试和模拟连续的请求,您可以在Linux或Mac终端中使用以下简单的bash循环命令:

for i in {1..10}; do curl http://localhost:3000/limit-query; done

运行结果:
在这里插入图片描述

测试用例

防御XSS攻击的测试用例

//test18.js 修改部分代码
app.post('/submit-comment', (req, res) => {// ...res.send(comment);
});
// test18.test.js
const request = require('supertest');
const app = require('../test18'); // 你的Express应用导出在test18.js文件中describe('XSS  Attack Prevention',()=>{it('它应该转义HTML字符以防止XSS',async  ()=>{const maliciousString = '<script>alert("xss")</script>';const response = await request(app).post('/submit-comment').send({comment: maliciousString})expect(response.text).not.toContain(maliciousString);expect(response.text).toContain('&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;');})
})

测试结果:
在这里插入图片描述

防御CSRF攻击的测试用例

// test18-2.test.js
const request = require('supertest');
const app = require('../test18-2'); describe('CSRF Attack Prevention', () => {test('它应该提供CSRF令牌', async () => {const getResponse = await request(app).get('/form');console.log(1111111,getResponse.text)expect(getResponse.text).toMatch(/name="_csrf"/);});test('它应该拒绝没有CSRF令牌的表单提交', async () => {const postResponse = await request(app).post('/submit-form').send({ data: 'test' });expect(postResponse.statusCode).toBe(403);});
});

测试结果:
在这里插入图片描述

防御注入攻击的测试用例

// 引入mongoose,用于操作MongoDB数据库
const mongoose = require('mongoose');
// 引入mongodb-memory-server,用于创建MongoDB内存服务器,便于进行测试
const { MongoMemoryServer } = require('mongodb-memory-server'); //版本@6.9.6
// 引入supertest,用于模拟HTTP请求
const supertest = require('supertest');
// 引入你的app,用于测试
const app = require('../test18-4');// 定义一个变量,用于存储MongoDB内存服务器的实例let mongoServer;// 在所有测试用例执行前,启动MongoDB内存服务器并连接
beforeAll(async () => {mongoServer = new MongoMemoryServer();const mongoUri = await mongoServer.getUri();mongoose.connect(mongoUri);
});
// 在所有测试用例执行完毕后,断开数据库连接并停止MongoDB内存服务器
afterAll(async () => {mongoose.disconnect();await mongoServer.stop();
});describe('NoSQL Injection Prevention', ()=>{it('它不应该允许NoSQL注入',async  ()=> {// 创建用户模型const User = mongoose.model('User2', new mongoose.Schema({username: String,password: String}));const user = new User({ username: 'user1', password: 'password1' });await user.save(); // 保存用户到数据库// 尝试使用注入攻击的方式查询用户const maliciousUsername = 'user1' + '{$ne: null}'; // 这是一个注入攻击的尝试const maliciousPassword = 'password1' + '{$ne: null}'; // 这是一个注入攻击的尝试const response = await supertest(app).post('/login').send({ username: maliciousUsername, password: maliciousPassword });expect(response.body.message).not.toBe('登录成功');})
})

测试结果:
在这里插入图片描述

总结

通过上述的措施,我们可以显著提高Node.js应用的安全性,从而更好地保护用户数据和服务的稳定性。当然,这些只是安全性加固的一部分,实际应用中还需要根据具体情况采取更多的安全措施。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/772010.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL-1.数据库的基本操作

1. 数据库的基本操作 show databases; information_schema&#xff1a;信息图式&#xff0c;存储服务器管理数据库的信息 mysql&#xff1a;存放系统信息&#xff0c;用户名密码等 performance_schema&#xff1a;性能图式 sys&#xff1a;系统文件 1.1 创建数据库-studen…

套娃式大小AI群体导致AI觉醒吗?

一、“套娃式”AI训练 目前&#xff0c;我们所讨论的人工智能&#xff08;AI&#xff09;主要是基于机器学习和深度学习技术的算法系统。它们通过不断学习、优化和改进以完成特定任务&#xff0c;但并不具备自我意识或者独立的创造性思考能力&#xff0c;即“觉醒”。 “套娃式…

RHCE作业:搭建web网站

综合练习&#xff1a; 请给openlab搭建web网站 网站需求&#xff1a; 1.域名访问网站 基于域名www.openlab.com可以访问网站内容为 welcome to openlab!!! 2.创建界面 给该公司创建三个子界面分别显示学生信息&#xff0c;教学资料 和缴费网站&#xff0c;基于www.openlab.com…

Splashtop 荣获2024年 Globee® 卓越网络安全两大奖项

2024年3月25日 加利福尼亚州库比蒂诺 Splashtop 在简化随处办公领域处于领先地位&#xff0c;我们自豪地宣布荣获全球卓越企业权威机构 Globee 奖。Splashtop 凭借其安全工作空间解决方案&#xff08;即插即用安全访问平台&#xff0c;使 IT 部门能够简化零信任的实施&#xf…

算法笔记~—位运算

目录 常见位运算&#xff1a; 1、基础位运算 2、对于一个数n。确定、修改这个数n二进制x位。 3、提取&#xff08;确定&#xff09;一个数n最右侧的1&#xff08;bit&#xff09;与干掉最右侧的1&#xff08;bit&#xff09; 4、异或运算律 5、位运算的优先级&#xff1a…

vscode 配置c++环境——3个文件搞定!!!

前提&#xff1a; 在vscode中安装了c扩展 创建文件settings.json {"files.associations": {"string": "cpp","vector": "cpp","array": "cpp","atomic": "cpp","*.tcc"…

[C++]函数重载(什么是函数重载,函数重载的原理(底层怎么实现))

一、什么是函数重载 函数重载是指在同一作用域内&#xff0c;可以有多个功能类似具有相同函数名&#xff0c;不同参数列表&#xff08;包括参数类型、参数个数、参数顺序&#xff09;的函数。编译器会根据函数调用时提供的参数来决定调用哪一个具体的函数。 注意&#xff1a;只…

QT gridlayout 循环设置组件,表格也通用 已解决

在需求中。经常遇到&#xff0c;表格 展示需求。 几乎都是json格式的。 // 列表配置文件QJsonArray listJsonArray getCfgJsonData("details_tab_table_config.json");if (listJsonArray.isEmpty()){return;}ui->gridWidget->setMaximumSize(QSize(310, 180)…

Vant Weapp小程序 van-uploader 文件上传点击无反应,删除无反应

Vant Weapp 1.0 版本开始支持van-uploader组件&#xff0c;请先确认好版本号和引用路径正确&#xff01;&#xff01; <van-uploader file-list"{{ fileList }}" deletable"{{ true }}" />1. 上传无反应 微信小程序用了van-uploader&#xff0c;但是…

第G5周:Pix2Pix理论与实战

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制&#x1f680; 文章来源&#xff1a;K同学的学习圈子 一、背景知识 1.1 图像翻译 图像内容&#xff08;Image Content&#xff09;&#…

冒泡排序 快速排序 归并排序 其他排序

书接上回.. 目录 2.3 交换排序 2.3.1冒泡排序 2.3.2 快速排序 快速排序的优化: 快速排序非递归 2.4 归并排序 基本思想 归并排序非递归 海量数据的排序问题 排序算法时间空间复杂度和稳定性总结 四. 其他非基于比较排序 (了解) 2.3 交换排序 基本思想&#xff1a;…

[技术杂谈]解决windows上出现文件名太长错误

最近执行python setup.py install总是失败&#xff0c;提示文件名太长发现网上有取消限制文件名长度&#xff0c;测试发现改完注册表无需重启cmd就生效了。但是有时候会失败&#xff0c;现在方法放这。 转到Windows“开始”&#xff0c;然后键入REGEDIT。选择注册表编辑器 选…

淘宝app商品数据API接口|item_get_app-获得淘宝app商品详情原数据

获得淘宝app商品详情原数据 API返回值说明 item_get_app-获得淘宝app商品详情原数据 公共参数​​​​​​ 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地…

Linux离线安装mysql,node,forever

PS:本文是基于centos7实现的,要求系统能够查看ifconfig和unzip解压命令, 实现无网络可安装运行 首先现在百度网盘的离线文件包****安装Xftp 和 Xshell 把机房压缩包传到 home目录下****解压unzip 包名.zip 获取IP先获取到 linux 主机的ip ifconfig Xftp 连接输入IP,然后按照…

蓝牙信标定位精度

蓝牙信标定位精度受到多种因素的影响&#xff0c;包括设备硬件、环境因素以及信号干扰等。因此&#xff0c;蓝牙信标的精度并不是固定的&#xff0c;而是会在一定范围内波动。 在我们实际应用过程中&#xff0c;蓝牙信标的精度通常可以做到2-5米。本文重点介绍下影响蓝牙信标精…

StarRocks 助力小红书离线数仓提效,提升百倍回刷性能!

数据处理效率一直是大数据时代的核心话题&#xff0c;它推动着各类数据执行引擎持续迭代产品。从早期的 MapReduce&#xff0c;到今天的 Spark&#xff0c;各行业正不断演进其离线数仓技术架构。 现有以 Spark 为核心的数仓架构在处理大规模数据回刷方面已取得进展&#xff0c…

数组的概述

数组的概述 为什么需要数组 需求分析1&#xff1a; 需要统计某公司50个员工的工资情况&#xff0c;例如计算平均工资、找到最高工资等。用之前知识&#xff0c;首先需要声明50个变量来分别记录每位员工的工资&#xff0c;这样会很麻烦。因此我们可以将所有的数据全部存储到一…

day07-缓存商品、购物车

1. 缓存菜品 1.1 问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大。 结果&#xff1a; 系统响应慢、用户体验差 1.2 实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓…

vue脚手架创建项目:账号登录(利用element-ui快速开发)(取消eslint强制格式)(修改端口号)

新手看不懂&#xff0c;老手不用看系列 文章目录 一、准备工作1.1 取消强制格式检查1.2 导入依赖&#xff0c;注册依赖 二、去element-ui官网找样式写Login组件2.1 引用局部组件2.2 运行项目 三、看一下发现没问题&#xff0c;开始修改前端的代码四、修改端口号4.1 修改后端端口…

Michael.W基于Foundry精读Openzeppelin第52期——ERC4626.sol

Michael.W基于Foundry精读Openzeppelin第52期——ERC4626.sol 0. 版本0.1 ERC4626.sol 1. 目标合约2. 代码精读2.1 constructor()2.2 maxDeposit(address) && previewDeposit(uint256 assets) && deposit(uint256 assets, address receiver)2.3 maxMint(addres…