- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章干货:Node.js 安全指南由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
当项目周期快结束时,开发人员会越来越关注应用的“安全性”问题。一个安全的应用程序并不是一种奢侈,而是必要的。你应该在开发的每个阶段都考虑应用程序的安全性,例如系统架构、设计、编码,包括最后的部署.
在这篇教程中,我们将一步步来学习如何提高Node.js应用程序安全性的方法.
。
来自用户输入或其他系统的数据,你都必须要进行验证。否则,这会对当前系统造成威胁,并导致不可想象的安全漏洞。现在,让我们学习如何验证Node.js中的传入数据。你可以使用名为validator的模块来执行数据验证。 例如:
const validator = require('validator');validator.isEmail('foo@bar.com'); //=> truevalidator.isEmail('bar.com'); //=> false
另外,你也可以使用joi模块来进行数据和模型的验证,例如:
const joi = require('joi'); try { const schema = joi.object().keys({ name: joi.string().min(3).max(45).required(), email: joi.string().email().required(), password: joi.string().min(6).max(20).required() }); const dataToValidate = { name: "Shahid", email: "abc.com", password: "123456", } const result = schema.validate(dataToValidate); if (result.error) { throw result.error.details[0].message; } } catch (e) { console.log(e); }
。
SQL注入可以让恶意用户通过传递非法参数,来篡改SQL语句。下面是一个例子,假设你写了这样一个SQL:
UPDATE users SET first_name="' + req.body.first_name + '" WHERE id=1332;
在正常情况下,你希望这次查询应该是这样的:
UPDATE users SET first_name = "John" WHERE id = 1332;
但是现在,如果有人将first_name的值按下面这种方式传递:
John", last_name="Wick"; --
这时,你的SQL语句就会变成这样:
UPDATE users SET first_name="John", last_name="Wick"; --" WHERE id=1001;
你会看到,WHERE条件被注释掉了,这次更新会将整张表所有用户的first_name改成John,last_name改成Wick。这下,你闯祸了! 。
如何避免SQL注入 。
避免SQL注入攻击最有效的办法就是将输入数据进行过滤。你可以对每一个输入数据逐一进行验证,也可以用参数绑定的方式验证。开发者们最常用的就是参数绑定的方式,因为它高效而且安全.
如果你在使用一些比较流行的ORM框架,例如sequelize、hibernate等等,那么框架中就已经提供了这种数据验证和SQL注入保护机制.
如果你更喜欢依赖数据库模块,例如mysql for Node,那么你可以使用数据库提供的过滤方法。下面代码是使用mysql for Node的一个例子:
var mysql = require('mysql');var connection = mysql.createConnection({ host : 'localhost', user : 'me', password : 'secret', database : 'my_db'});connection.connect();connection.query( 'UPDATE users SET ?? = ? WHERE ?? = ?', ['first_name',req.body.first_name, ,'id',1001], function(err, result) { //...});
??的地方被字段名称替换,?的地方被字段值替换,这样就保证了输入值的安全性.
你也可以使用存储过程来提高安全级别,但是由于缺乏可维护性,开发人员倾向于避免使用存储过程.
同时,你还应该执行服务器端的数据验证。 但我不建议你手动验证每个字段,可以使用joi等模块来解决这个问题.
类型转换 。
JavaScript是一种动态类型语言,即值可以是任何类型。你可以使用类型转换方法来验证数据的类型,这样就能保证,只有指定类型的数据才可以进入数据库。比如,用户ID只能是数字类型,看下面的代码:
var mysql = require('mysql');var connection = mysql.createConnection({ host : 'localhost', user : 'me', password : 'secret', database : 'my_db'});connection.connect();connection.query( 'UPDATE users SET ?? = ? WHERE ?? = ?', ['first_name',req.body.first_name, ,'id',Number(req.body.ID)], function(err, result) { //...});
你注意到变化了吗?这里我们使用了Number(req.body.ID)方法来确保用户ID必须为数字.
。
敏感数据(例如密码)应该以一种安全的方式存储在系统中,这样,恶意用户就不会滥用敏感信息。在本节中,我们将学习如何存储和管理通用的密码,几乎每个应用程序在其系统中都有不同的密码存储方式.
密码哈希 。
哈希是一个将输入值生成固定大小字符串的函数。哈希函数的输出值是无法解密的,因此可以说是“单向的”。因此,像密码这样的数据,存储在数据库中的值必须是哈希值,而不是明文.
你也许想知道,既然哈希是一种不可逆的加密方式,那么攻击者又是如何取得密码访问权限的呢?
正如我上面提到的那样,哈希加密使用输入字符串并生成固定长度的输出值。因此,攻击者采取了相反的方法,他们从常规密码列表中生成哈希,然后将哈希与系统中的哈希进行比较以找到密码。这种攻击方式叫做查表法(Lookup Tables) 。
这就是为什么你作为系统架构师,绝不允许系统中使用简单通用密码的原因。为了避免攻击,你也可以使用一种叫”salt"的东西,我们称之为“哈希加盐法”。将salt附加到密码哈希中,从而使输入值唯一。salt值必须是随机的不可预测的。我们建议你使用的哈希算法是BCrypt,在Node.js中,你可以使用bcyrpt节点模块执行哈希处理.
请参考下面例子中的代码:
const bcrypt = require('bcrypt');const saltRounds = 10;const password = "Some-Password@2020";bcrypt.hash( password, saltRounds, (err, passwordHash) => { //we will just print it to the console for now //you should store it somewhere and never logs or print it console.log("Hashed Password:", passwordHash);});
SaltRounds函数是哈希函数的成本,成本越高,生成的hash密码越安全。你应该根据服务器的计算能力来确定salt值,密码的hash值生成后,用户输入的密码将会和存储在数据库中的hash值比对,参考代码如下:
const bcrypt = require('bcrypt');const incomingPassword = "Some-Password@2020";const existingHash = "some-hash-previously-generated"bcrypt.compare( incomingPassword, existingHash, (err, res) => { if(res && res === true) { return console.log("Valid Password"); } //invalid password handling here else { console.log("Invalid Password"); }});
密码存储 。
无论你是用数据库还是文件来存储密码,都不能使用明文存储。我们在上一节已经学到,你可以将密码进行哈希后存储在数据库中。我推荐密码字段用varchar(255)数据类型,你也可以选择不限长度的字段类型。如果你使用的是bcrypt,则可以使用varchar(60)字段类型,因为bcrypt会生成固定长度为60个字符的哈希.
认证和授权 。
一个拥有合适的角色权限系统,将会阻止一些恶意用户在系统中做一些越权的事情。为了实现正确的授权过程,将合适的角色和权限分配给每个用户,以便他们可以执行权限范围内的某些任务。在Node.js中,你可以使用著名的ACL模块,根据系统中的授权来开发访问控制列表.
const ACL = require('acl2');const acl = new ACL(new ACL.memoryBackend());// guest is allowed to view blogsacl.allow('guest', 'blogs', 'view')// check if the permission is grantedacl.isAllowed('joed', 'blogs', 'view', (err, res) => { if(res){ console.log("User joed is allowed to view blogs"); }});
请查阅acl2文档以获取更多信息和示例代码.
。
黑客经常会使用软件反复使用不同的密码尝试获得系统权限,直到找到有效密码为止,这种攻击方式叫做暴力攻击。为了避免这种攻击,一种简单有效的办法是“让他等一会”,也就是说,当某人尝试登录系统并尝试输入无效密码3次以上时,请让他们等待60秒左右,然后再尝试。这样,攻击者将大大提高时间成本,并且将使他们永远无法破解密码.
防止这种攻击的另一种方法是屏蔽无效登录请求的IP。系统在24小时内允许每个IP进行3次错误地登录尝试。如果有人尝试进行暴力破解,则将其IP封锁24小时。 许多公司已使用这种方法来防止暴力攻击。 如果使用Express框架,则有一个中间件模块可在传入请求中启用速率限制。 它称为express = brute.
下面是一个例子.
安装依赖项 。
npm install express-brute --save
在路由中启用它 。
const ExpressBrute = require('express-brute');const store = new ExpressBrute.MemoryStore(); // stores state locally, don't use this in productionconst bruteforce = new ExpressBrute(store);app.post('/auth', bruteforce.prevent, // error 429 if we hit this route too often function (req, res, next) { res.send('Success!'); });//...
。
现在已经2021年了,你也应该使用HTTPS来向网络中发送数据了。HTTPS是具有安全通信支持的HTTP协议的扩展。使用HTTPS,可以保证用户在互联网中发送的数据是被加密的,是安全的.
在这里我不打算详细介绍HTTPS协议的工作原理,我们只讨论如何使用它。这里我强烈推荐使用LetsEncrypt来为你的所有域名生成安全证书.
你可以在基于Apache和Nginx的Web服务器上使用LetsEncrypt。我强烈建议你在反向代理或网关层上使用HTTPS协议,因为它们有很多繁重的计算操作.
。
会话(session)是任何动态Web应用程序最重要的部分,一个安全的会话对用户和系统来说真的是非常必要的。会话是使用Cookie实现的,因此必须确保其安全以防止会话劫持。以下是可以为每个cookie设置的属性列表以及它们的含义:
在Express框架中,你可以使用express-session npm模块来管理会话.
const express = require('express');const session = require('express-session');const app = express();app.use(session({ secret: 'keyboard cat', resave: false, saveUninitialized: true, cookie: { secure: true, path: '/'}}));
。
跨站点请求伪造攻击利用系统中受信任的用户,对Web应用程序执行有害的恶意操作。在Node.js中,我们可以使用csurf模块来缓解CSRF攻击。该模块需要首先初始化express-session或cookie-parser,你可以看看下面的示例代码:
const express = require('express');const cookieParser = require('cookie-parser');const csrf = require('csurf');const bodyParser = require('body-parser');// setup route middlewaresconst csrfProtection = csrf({ cookie: true });const parseForm = bodyParser.urlencoded({ extended: false });// create express appconst app = express();// we need this because "cookie" is true in csrfProtectionapp.use(cookieParser());app.get('/form', csrfProtection, function(req, res) { // pass the csrfToken to the view res.render('send', { csrfToken: req.csrfToken() });});app.post('/process', parseForm, csrfProtection, function(req, res) { res.send('data is being processed');});app.listen(3000);
在网页上,你需要创建一个隐藏输入域,将CSRF令牌保存在该输入域中,例如:
<form action="/process" method="POST"> <input type="hidden" name="_csrf" value="{{csrfToken}}"> Favorite color: <input type="text" name="favoriteColor"> <button type="submit">Submit</button></form>
如果使用的是AJAX请求,那么CSRF令牌可以通过请求头(header)来传递.
var token = document.querySelector('meta[name="csrf-token"]').getAttribute('content'); headers: { 'CSRF-Token': token }
。
拒绝服务或DOS攻击,可以让攻击者通过破坏系统,使系统被迫关闭服务或用户无法访问服务。攻击者通常会向系统发送大量的流量和请求,从而增加服务器CPU和内存负载,导致系统崩溃。为了缓解Node.js应用程序中的DOS攻击,首先是要识别此类事件, 我强烈建议将这两个模块集成到系统中.
正则表达式拒绝服务攻击(ReDOS)是DOS攻击的一种,攻击者利用系统中正则表达式的设计缺陷或计算复杂度来大量消耗服务器的系统资源,造成服务器的服务中断或停止.
我们可以使用一些工具来检查有风险的正则表达式,从而避免这些正则表达式的使用。例如这个工具:
https://github.com/davisjam/vuln-regex-detector 。
。
我们在项目中都使用了大量的依赖项。我们还需要检查并验证这些依赖关系,以确保整个项目的安全性。NPM已经具有这样的审核功能来查找项目的漏洞。只需在源代码目录中运行下面的命令即可:
npm audit
要修复漏洞,可以运行此命令:
npm audit fix
您也可以先进行dry run来检查修复程序,然后再将其应用到项目中.
npm audit fix --dry-run --json
。
HTTP提供了一些安全头信息,可以防止常见的攻击。如果使用的是Express框架,则可以使用helmet模块,1行代码就可以启用所有安全头.
npm install helmet --save
下面来看看如何使用:
const express = require("express"); const helmet = require("helmet"); const app = express(); app.use(helmet()); //...
这将启用以下HTTP头
这些HTTP头可防止恶意用户的各种攻击,例如点击劫持,跨站点脚本攻击等.
(本文完) 。
公众号 - 前端新世界 。
原文地址:https://www.cnblogs.com/frontworld/p/14352795.html?utm_source=tuicool&utm_medium=referral 。
最后此篇关于干货:Node.js 安全指南的文章就讲到这里了,如果你想了解更多关于干货:Node.js 安全指南的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我想让我的 NSIS 代码更具可读性。 我需要一些关于明智地编写代码部分的指南(比如 C# 中有 #region #endregion)或任何可以使编写 NSIS 代码变得有趣和容易的信息. 请帮帮我
我正在尝试找出Gherkin中所有可用的语法/格式,例如关于多行参数以及我不知道的所有其他内容。 在挖掘Google搜索结果之后,似乎综合指南位于here中: 我以为那很好,并且it链接到一个页面,该
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 5年前关闭。 Improve thi
当我将 guides 添加到 valueAxesSettings 中时,即使我选择 valueAxesSettings 到 valueAxes 中,它也不起作用。此外,valueAxesSetting
我正在寻找有关如何管理 .NET 程序集的三个不同程序集版本号的指针、建议,甚至是口述。 Product 版本是最简单的,因为这似乎通常由业务决定。然后,文件版本似乎用于部署之间的版本控制,其中实际的
昨晚我脑子里冒出一件事。我想知道为什么我们在项目之间仍然有不同的编码风格。由于风格是个人的东西,我认为最好这样对待它。我们为什么不呢?这有什么技术限制吗? 我举几个例子: // Code sample
我有一个应用程序,用户可以在其中从主 Activity 登录,然后可以使用 ListView 浏览实体的层次结构。因此,Activity 堆栈看起来像这样: A -> B -> B -> B -> .
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 9 年前。 Improve
大家好,上个月我开始学习 CSS。我做的第一件事是阅读我能在 www.w3school.com 上找到的所有内容,之后我开始阅读 CSS Mastery 2nd版本。我已经建立了几个自己的网站并取得了
我希望用户能够上传个人资料图片。 关于如何最好地处理这个问题,是否有任何指导方针?例如 - 在哪里保存图像?和要使用的文件夹结构。- 让用户难以浏览每个人的个人资料照片? 谢谢。 最佳答案 如果你自己
我有兴趣了解有关条件重启系统及其工作原理的更多信息。我不知道从哪里开始。我一直在查看源代码,但想知道是否有更高级别的指南可用。 最佳答案 Kent Pitman:条件系统 http://www.nhp
我想将小型、精简且平均的基于 C 的解析器合并到我的 Android 项目中。我过去做过 JNI 编程,但没有在 Android 上进行任何类型的 native (C) 开发。我的计划是将 C lib
免责声明:我试图搜索类似的问题,但是它返回了关于每个 C++ 问题的信息...此外,我将感谢任何可以提出更好标题的人。 C++ 中有两个著名的循环结构:while 和for。 我故意忽略了 do ..
我一直在尝试批量删除 Wordpress 帖子中的垃圾链接,如下所示: . 它们位于 post_content 列下的 wp_posts 表中。我试图通过在 href 标记中添加 % 的通配符来做到这
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 6 年前。 Improve
我们正在讨论为实体类定义方法的最佳方式 - 作为扩展方法或使用分部类。我们讨论的这类方法不会修改实体的状态,它们是纯粹的“辅助”方法,可以查询状态并返回值。 这两种方法的主要好处是保持实体类干净,同时
您将如何在 Flutter 中在实际屏幕上实现引导层。像这样: 最佳答案 这不是微不足道的。以下是必需的组件: 首先,你必须open a transparent full screen dialog
我们需要通过在 C/C++ 中实现特定算法来解决的大多数科学计算问题都需要远低于 double 的精度。例如,1e-6、1e-7 精度涵盖了 ODE 求解器或数值积分的 99% 情况。即使在我们确实需
我正在研究对专有 UI 框架(用于桌面应用程序)的 RTL 支持,我想知道:是否有关于如何更改小部件渲染的指南? 我正在寻找以下内容的列表: 复选框标签位于复选框左侧,右对齐 工具栏按钮从右到左排列
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
我是一名优秀的程序员,十分优秀!