在nodejs中如何防止ssrf攻击

在nodejs中如何防止ssrf攻击

什么是ssrf攻击

ssrfserver-side request forgery)是服务器端请求伪造,指攻击者能够从易受攻击的Web应用程序发送精心设计的请求的对其他网站进行攻击。(利用一个可发起网络请求的服务当作跳板来攻击其他服务)。

我们用一个例子来解释一下这个概念 。想象一下,我们有一个应用程序,用户需要上传图片及图片名称。那么这个时候是使用img标签显示图片的时候就会先下载图片(向服务器提出请求)。既然攻击者知道我们是在发出这些GET请求,他就会把http://localhost/admin这样的网址作为图片名称传递给服务端。如果我们的系统没有考虑到此攻击,那么将向服务器发送一个请求,当有人能够访问我们的内部系统或服务时这是非常危险的。现在。如果我们显示的是图像是下载请求的结果,它可以使攻击者更容易地探索内部服务和做一些事情。

不同类型的ssrf攻击

  • 服务器攻击:在上面说到的通过图片传递url的例子可知,如果我们传递了类似于localhost127.0.0.1 或者服务器本身的IP,那么我们本身就是在攻击这个服务器。
  • 内部后端系统:在这种情况下,攻击者试图与其他后端系统进行通信。为此他使用了包含内部IP的地址例如 http://192.168.0.68/admin 或者直接使用域名例如https://payment/something
  • 外部系统:这可能是一个只有我们的服务器或内部服务能够交互的外部系统。这可能是一个银行API或任何限制其服务到我们的IP`地址的其他形式的身份验证和授权。

在这里插入图片描述

基本ssrf和盲ssrf是什么

在从URL下载图片的例子中,如果我们直接将响应返回给用户。那么攻击者就能够看到响应并更快地探索我们的内部服务。

如果我们没有显示来自请求的任何响应,那么攻击类型就会变成盲ssrf,这使得攻击者在没有看到响应的情况下更难探索我们的系统。

ssrf攻击的一个例子

下面是一段简历生成网站代码,当我们为个人网站填写一个字段时。它会检查该字段是否是一个有效的网站。如果它不能访问该网址,会给一个反馈。这个应用程序有一个基本部分,路由。必须对自己进行身份验证才能访问这些路由。我们有一个内部服务被称为付款。只有主要的应用程序可以访问它,而且它不是公开的。(这完全是简单化的,目的是了解可能发生的情况)。

让我们看看代码的核心。它包括:

  • 个人网站:查看网址,它会给我们一条信息,告诉我们是否能访问成功,并返回来自个人网站的回应,同时对整个网址提供预览。
  • 我的:用于检查当前用户的余额。它向我们的支付服务发送请求。
  • 钱包:向我们内部的支付服务发送请求。
const express = require('express');
const app = express();
const axios = require('axios');
app.use(express.json());
const paymentServiceAddress = 'localhost:3011'
app.post('/personal-website', async (req, res) => {const url = req.body?.url;try {const websiteHomePageTest = await axios.get(url);await saveAddressInProfile(url);res.json({ message: 'success', url, data: websiteHomePageTest.data });}catch (error) {if (axios.isAxiosError(error)) {return res.json({ message: 'failed', error: error.message }).status(500);} else {console.error(error);res.json({ message: 'failed' }).status(500);}}
});app.post('/me/balance', someAuthenticationMiddleware, async (req, res) => {const response = await axios.post(`http://${paymentServiceAddress}/1/balance`);const balance = response.data.balance;res.json({ balance });
})app.post('/me/balance/payin', someAuthenticationMiddleware, async (req, res) => {const payIn = await payIn()const response = await axios.post(`http://${paymentServiceAddress}/1/balance/increase`);const balance = response.data.balance;res.json({ balance });
})app.listen(3010, () => console.log(`Example app listening at http://localhost:3010`));
async function saveAddressInProfile(image) { console.log('保存图片'); }
function someAuthenticationMiddleware(req, res, next) { next(); }
async function payIn() { }

如果我们在个人网站上使用一个有效的网址,我们会得到这个结果:

在这里插入图片描述

现在,如果我们尝试其他的URL,可以检查是否具备其他额外的服务。

在这里插入图片描述
这个响应给了我们一个内部服务的IPport。现在攻击者应该开始使用这个URL来寻找其他服务。

如果我们尝试一个地址http://localhost:3011。我们看到结果是success,这意味着在这个网址后面有一个服务。让我们看看支付服务的实施情况。我们不能直接向这个服务提出请求,因为它是在一个私人网络中,但是我们可以从主应用程序中提出请求。

const express = require('express');
const app = express();
app.use(express.static('static'));
app.use(express.json());app.get('/', (req, res) => {res.send('pong');
});app.get('/:userId/balance', async (req, res) => {const balance = getUserBalance(req.params.userId);res.json({ balance });
});const users = [{ id: 1, name: 'leo', balance: 100 },{ id: 2, name: 'alex', balance: 200 },{ id: 3, name: 'Jack', balance: 300 }
]
function getUserBalance(userId) {return users.find(user => user.id == userId)?.balance;
}app.listen(3011, () => {console.log(`Example app listening at http://localhost:3011`);
});

在尝试了一点点之后攻击者会发现有一个路径可以获取用户信息。(当URL不正确时,付款服务返回404,我们在响应中看到结果)。

通过使用balance路由,我们可以访问所有用户,使用他们的用户名。一般情况下在主程序上使用这个路径/me/balance,我们可以看到自己的信息,但现在我们也可以未经授权访问其他用户的平衡。

在这里插入图片描述

如何防止ssrf攻击

校验

黑名单

可以使用正则表达式来验证URL,或者列出一个黑名单。列出一些禁止的短语,比如127.0.0.1localhost。我们可以直接使用正则表达式,也可以Zodhapivalidatorjs这些库。

IP地址

直接限制可访问的ip

域名

直接限制可访问的域名。

使用适当的认证和授权

在我们的示例中,看到主应用程序可以访问任何类型的对支付服务的请求。一个更好的方法是传递用户身份验证信息(可能是JWT或会话或任何东西),然后支付从JWT有效载荷中获得用户标识,然后我们确定该用户可以访问这些数据。即使是后端服务也应该在彼此之间有有限的访问权限。如果他们依靠用户访问,那么获得未经授权的访问可能会更困难。

不暴露对未知请求的回应

这个例子中的另一个错误是,它在成功和失败时都公开了一个HTTP请求响应。任何额外信息都可能是攻击者的线索。因此,当个人网站不可用或提供内部服务器时,我们不应该暴露任何相关服务的响应。

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

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

相关文章

10月1日作业

汇编指令合集 用select实现服务器并发代码 #include<myhead.h> #define IP "192.168.0.106" #define PORT 8888int main(int argc, const char *argv[]) {//新建套接字文件int sfd socket(AF_INET, SOCK_STREAM, 0);if(sfd < 0){ERR_MSG("socket&quo…

多线程学习笔记(一)

文章目录 1 线程基础知识复习2 CompletableFuture1、Future和Callable接口2、FutureTask3、对Future的改进4、案例精讲——电商5、常用方法6、CompetableFutureWithThreadPool【重要】 3 锁1、乐观锁和悲观锁2、synchronized 8锁案例3、公平锁和非公平锁4、可重入锁5、死锁及排…

web:[RoarCTF 2019]Easy Calc

题目 进入页面是一个计算器的页面 随便试了一下 查看源代码看看有什么有用的信息 访问一下这个calc.php 进行代码审计 <?php error_reporting(0); if(!isset($_GET[num])){show_source(__FILE__); }else{$str $_GET[num];$blacklist [ , \t, \r, \n,\, ", , \[, \]…

Win11下无法打开丛林之狐,提示未检测到DirectX 8.1

新装的win11系统&#xff0c;打开丛林之狐提示未检测到DirectX 8.1. 运行dxdiag检查DirectX版本&#xff1a; DX版本已经是12了&#xff1a; 最终参考了这篇文章解决了&#xff1a; 罪恶都市出现XX-directx version 8.1处理方法 - 知乎 控制面板 > 程序 > 启用或关闭Wi…

蜂蜜配送销售商城小程序的作用是什么

蜂蜜是农产品中重要的一个类目&#xff0c;其受众之广市场需求量大&#xff0c;但由于非人人必需品&#xff0c;因此传统线下门店经营也面临着痛点&#xff0c;线上入驻平台也有很多限制难以打造自有品牌&#xff0c;无法管理销售商品及会员、营销等&#xff0c;缺少自营渠道&a…

力扣 -- 718. 最长重复子数组

解题步骤&#xff1a; 参考代码&#xff1a; class Solution { public:int findLength(vector<int>& nums1, vector<int>& nums2) {int m nums1.size();int n nums2.size();//多开一行&#xff0c;多开一列vector<vector<int>> dp(m 1, ve…

【中秋国庆不断更】OpenHarmony多态样式stateStyles使用场景

Styles和Extend仅仅应用于静态页面的样式复用&#xff0c;stateStyles可以依据组件的内部状态的不同&#xff0c;快速设置不同样式。这就是我们本章要介绍的内容stateStyles&#xff08;又称为&#xff1a;多态样式&#xff09;。 概述 stateStyles是属性方法&#xff0c;可以根…

【数据库——MySQL】(13)过程式对象程序设计——存储函数、错误处理以及事务管理

目录 1. 存储函数2. 存储函数的应用3. 错误处理4. 抛出异常5. 事务处理6. 事务隔离级7. 应用实例参考书籍 1. 存储函数 要 创建 存储函数&#xff0c;需要用到 CREATE 语句&#xff1a; CREATE FUNCTION 存储函数名([参数名 类型, ...])RETURNS 类型[存储函数体]注意&#xff1…

【计算机网络】DNS原理介绍

文章目录 DNS提供的服务DNS的工作机理DNS查询过程DNS缓存 DNS记录和报文DNS记录DNS报文针对DNS服务的攻击 DNS提供的服务 DNS&#xff0c;即域名系统(Domain Name System) 提供的服务 一种实现从主机名到IP地址转换的目录服务&#xff0c;为Internet上的用户应用程序以及其他…

最快的包管理器--pnpm创建vue项目完整步骤

1.用npm全局安装pnpm npm install -g pnpm 2.在要创建vue项目的包下进入cmd&#xff0c;输入&#xff1a; pnpm create vue 3.输入项目名字&#xff0c;选择Router,Pinia,ESLint,Prettier之后点确定 4.cd到创建好的项目 &#xff0c;安装依赖 cd .\刚创建好的项目名称\ p…

Redis配置和优化

Redis配置和优化 一 、Redis介绍二、关系数据库和非关系数据库2.1、关系型数据库2.2、 非关系型数据库2.3、 非关系型数据库的产生背景2.4、 关系型数据库和非关系型数据库区别2.5、 总结 三、缓存概念3.1、系统缓存3.2、 缓存保存位置及分层结构3.2.1、DNS缓存3.2.2、 应用层缓…

笔试练习day01

目录 一、选择题 1、格式化输出 2、逻辑判断--短路原则 3、赋值语句 4、左移、异或 二、编程题 1、组队竞赛 2、删除公共字符 一、选择题 1、格式化输出 知识点&#xff1a;格式化输出&#xff0c;%m.ns 2、逻辑判断--短路原则 知识点&#xff1a; else和最近的if匹…

第一次作业题解

第一次作业题解 P5717 【深基3.习8】三角形分类 思路 考的是if()的使用,还要给三条边判断大小 判断优先级&#xff1a; 三角形&#xff1f;直角、钝角、锐角等腰等边 判断按题给顺序来 代码 #include <stdio.h> int main() {int a 0, b 0, c 0, x 0, y 0, z 0…

排序篇(二)----选择排序

排序篇(二)----选择排序 1.直接选择排序 基本思想&#xff1a; 每一次从待排序的数据元素中选出最小&#xff08;或最大&#xff09;的一个元素&#xff0c;存放在序列的起始位置&#xff0c;直到全部待排序的数据元素排完 。 直接选择排序: ​ 在元素集合array[i]–array[…

pytorch函数reshape()和view()的区别及张量连续性

目录 1.view() 2.reshape() 3.引用和副本&#xff1a; 4.区别 5.总结 在PyTorch中&#xff0c;tensor可以使用两种方法来改变其形状&#xff1a;view()和reshape()。这两种方法的作用是相当类似的&#xff0c;但是它们在实现上有一些细微的区别。 1.view() view()方法是…

C++指针常量,常量指针以及, 引用和指针的区别

const修饰指针有三种情况 1. const修饰指针 --- 常量指针 2. const修饰常量 --- 指针常量 3. const即修饰指针&#xff0c;又修饰常量 c int main() {int a 10;int b 10;//const修饰的是指针&#xff0c;常量指针&#xff0c;指针指向可以改&#xff0c;指针指向的值不…

分享10个必备的VS Code技巧和窍门,提高你的开发效率

目录 前言 1. 时间线视图&#xff1a;本地源代码控制 2. 自动保存&#xff1a;不再需要按Ctrl S 3. 使用命令面板进行任何操作 4、快速转到文件 5. 快速跳转指定行 6. 快速删除该行 7. 享受使用流畅的光标进行打字 8. 快速格式化代码 9. 使用多光标编辑功能节省时间…

数据计算-第15届蓝桥杯第一次STEMA测评Scratch真题精选

[导读]&#xff1a;超平老师的《Scratch蓝桥杯真题解析100讲》已经全部完成&#xff0c;后续会不定期解读蓝桥杯真题&#xff0c;这是Scratch蓝桥杯真题解析第154讲。 第15届蓝桥杯第1次STEMA测评已于2023年8月20日落下帷幕&#xff0c;编程题一共有6题&#xff0c;分别如下&a…

详解Avast Driver Updater:电脑驱动更新工具的利器还是多余的软件?

亲爱的读者朋友们&#xff0c;你是不是经常为电脑的驱动问题而烦恼&#xff1f;如果是的话&#xff0c;你可能会对这款软件——Avast Driver Updater 电脑驱动更新工具感兴趣。但在你决定尝试之前&#xff0c;不妨先和我一起深入探讨一下它的优点、缺点以及它适用的使用场景。 …

pytorch第一天(tensor数据和csv数据的预处理)lm老师版

tensor数据&#xff1a; import torch import numpyx torch.arange(12) print(x) print(x.shape) print(x.numel())X x.reshape(3, 4) print(X)zeros torch.zeros((2, 3, 4)) print(zeros)ones torch.ones((2,3,4)) print(ones)randon torch.randn(3,4) print(randon)a …