【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 = {
    '&': '&',
    '<': '&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应用的安全性,从而更好地保护用户数据和服务的稳定性。当然,这些只是安全性加固的一部分,实际应用中还需要根据具体情况采取更多的安全措施。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Windows 频繁失去焦点分析

原文&#xff1a;https://blog.iyatt.com/?p14383 1 前言 刚才在打字的时候发现会随机失去焦点&#xff0c;然后又要用鼠标点一下正在输入的位置才能继续输入&#xff0c;特别烦。开始我怀疑是手碰到触摸板导致失去焦点&#xff0c;但是我用了差不多十年带触摸板的笔记本电脑…

[ C++ ] STL---仿函数与priority_queue

目录 仿函数 示例一&#xff1a; 示例二 : 常见的仿函数 priority_queue简介 priority_queue的常用接口 priority_queue的模拟实现 基础接口 push() 堆的向上调整算法 堆的插入 pop() 堆的向下调整算法 堆的删除 priority_queue最终实现 仿函数 仿函数&#xff…

基于stm32与TJC3224T124_011串口屏的PID调参器(附完整工程)

电赛在即&#xff0c;每次比赛调PID都是一件比较繁琐的事。每次都要在程序中改完再烧录到板子上&#xff0c;特别耗时。正好最近发现实验室的一块串口屏比较好玩。 于是就做了这个调PID的东西。它可以通过串口直接修改PID的值&#xff0c;从而达到快速调PID的目的。下面我将完整…

【Python】学习率调整策略详解和示例

学习率调整得当将有助于算法快速收敛和获取全局最优&#xff0c;以获得更好的性能。本文对学习率调度器进行示例介绍。 学习率调整的意义基础示例无学习率调整方法学习率调整方法一多因子调度器余弦调度器 结论 学习率调整的意义 首先&#xff0c;学习率的大小很重要。如果它…

音乐制作利器 :FL Studio21中文编曲音乐制作软件免费下载

一、引言 在音乐的世界里&#xff0c;每个人都有自己独特的音色和表达方式。而今天&#xff0c;我们要为你推荐一款能让您的音乐创作更上一层楼的神器——FL Studio21中文编曲音乐制作软件。这款功能强大的音乐制作软件&#xff0c;不仅拥有丰富的音色库和高效的编辑功能&#…

Quartz

Quartz 1.核心概念1.1 核心概念图1.2 demo 2.Job2.1为什么设计成JobDetailJob, 而不直接使用Job2.2 间隔执行时, 每次都会创建新的Job实例2.3 定时任务默认都是并发执行的&#xff0c;不会等待上一次任务执行完毕2.3.1 不允许并发执行 2.4 在运行时, 通过JobDataMap向Job传递数…

Python自动化测试环境搭建

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号&#xff1a;互联网杂货铺&#xff0c;回复1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 请事先自行安装好​​Pycharm​​​软件哦&#xff0c;我…

深度学习模型部署(十二)CUDA编程-绪

CUDA 运行时 API 与 CUDA 驱动 API 速度没有差别&#xff0c;实际中使用运行时 API 较多&#xff0c;运行时 API 是在驱动 API 上的一层封装。​ CUDA 是什么&#xff1f;​ CUDA(Compute Unified Device Architecture) 是 nvidia 推出的一个通用并行技术架构&#xff0c;用它…

基于冠豪猪优化器(CPO)的无人机路径规划

该优化算法是2024年新发表的一篇SCI一区top论文具有良好的实际应用和改进意义。一键运行main函数代码自动保存高质量图片 1、冠豪猪优化器 摘要&#xff1a;受冠豪猪(crest Porcupine, CP)的各种防御行为启发&#xff0c;提出了一种新的基于自然启发的元启发式算法——冠豪猪…

视觉轮速滤波融合1讲:理论推导

视觉轮速滤波融合理论推导 文章目录 视觉轮速滤波融合理论推导1 坐标系2 轮速计2.1 运动学模型2.2 外参 3 状态和协方差矩阵3.1 状态3.2 协方差矩阵 4 Wheel Propagation4.1 连续运动学4.2 离散积分4.2.1 状态均值递推4.2.2 协方差递推 5 Visual update5.1 视觉残差与雅可比5.2…

蓝桥杯2023年第十四届省赛真题-买瓜|DFS+剪枝

题目链接&#xff1a; 0买瓜 - 蓝桥云课 (lanqiao.cn) 蓝桥杯2023年第十四届省赛真题-买瓜 - C语言网 (dotcpp.com) &#xff08;蓝桥官网的数据要求会高一些&#xff09; 说明&#xff1a; 这道题可以分析出&#xff1a;对一个瓜有三种选择&#xff1a; 不拿&#xff0c…

Vue3基础笔记(2)事件

一.事件处理 1.内联事件处理器 <button v-on:click"count">count1</button> 直接将事件以表达式的方式书写~ 每次单击可以完成自增1的操作~ 2.方法事件处理器 <button click"addcount(啦啦啦~)">count2</button> 如上&…

每日必学Linux命令:mv命令

mv命令是move的缩写&#xff0c;可以用来移动文件或者将文件改名&#xff08;move (rename) files&#xff09;&#xff0c;是Linux系统下常用的命令&#xff0c;经常用来备份文件或者目录。 一&#xff0e;命令格式&#xff1a; mv [选项] 源文件或目录 目标文件或目录二&am…

Open WebUI大模型对话平台-适配Ollama

什么是Open WebUI Open WebUI是一种可扩展、功能丰富、用户友好的大模型对话平台&#xff0c;旨在完全离线运行。它支持各种LLM运行程序&#xff0c;包括与Ollama和Openai兼容的API。 功能 直观的界面:我们的聊天界面灵感来自ChatGPT&#xff0c;确保了用户友好的体验。响应…

轻松掌握C语言中的sqrt函数,快速计算平方根的魔法秘诀

C语言文章更新目录 C语言学习资源汇总&#xff0c;史上最全面总结&#xff0c;没有之一 C/C学习资源&#xff08;百度云盘链接&#xff09; 计算机二级资料&#xff08;过级专用&#xff09; C语言学习路线&#xff08;从入门到实战&#xff09; 编写C语言程序的7个步骤和编程…

第1章 实时3D渲染流水线

前言 本书所剖析的Unity 3D内置着色器代码版本是2017.2.0f3&#xff0c;读者可以从Unity 3D官网下载这些着色器代码。这些代码以名为builtin_shaders-2017.2.0f3.zip的压缩包的形式提供&#xff0c;解压缩后&#xff0c;内有4个目录和1个license.txt文件。 目录CGIncludes存放了…

苍穹外卖项目-01(开发流程,介绍,开发环境搭建,nginx反向代理,Swagger)

目录 一、软件开发整体介绍 1. 软件开发流程 1 第1阶段: 需求分析 2 第2阶段: 设计 3 第3阶段: 编码 4 第4阶段: 测试 5 第5阶段: 上线运维 2. 角色分工 3. 软件环境 1 开发环境(development) 2 测试环境(testing) 3 生产环境(production) 二、苍穹外卖项目介绍 …

Docker搭建LNMP环境实战(05):CentOS环境安装Docker-CE

前面几篇文章讲了那么多似乎和Docker无关的实战操作&#xff0c;本篇总算开始说到Docker了。 1、关于Docker 1.1、什么是Docker Docker概念就是大概了解一下就可以&#xff0c;还是引用一下百度百科吧&#xff1a; Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以…

SE注意力模块学习笔记《Squeeze-and-Excitation Networks》

Squeeze-and-Excitation Networks 摘要引言什么是全局平均池化&#xff1f; 相关工作Deep architectures Squeeze-and-Excitation Blocks3.1. Squeeze: Global Information Embedding3.2. Excitation: Adaptive Recalibration3.3. Exemplars: SE-Inception and SE-ResNet 5. Im…

百科词条编辑必备指南,让你轻松上手创建

1.注册账号&#xff1a;首先&#xff0c;你需要注册一个百科平台的账号。例如&#xff0c;对于百度百科&#xff0c;你需要有一个百度账号。 搜索词条&#xff1a;在百科全书平台上搜索您想要编辑的词条。如果词条已经存在&#xff0c;可以直接编辑&#xff1b;如果词条不存在&…