第30天:安全开发-JS 应用NodeJS 指南原型链污染Express 框架功能实现审计0

news2025/1/11 19:51:33

时间轴:

演示案例:

环境搭建-NodeJS-解析安装&库安装

功能实现-NodeJS-数据库&文件&执行

安全问题-NodeJS-注入&RCE&原型链

案例分析-NodeJS-CTF 题目&源码审计

开发指南-NodeJS-安全 SecGuide 项目、

环境搭建-NodeJS-解析安装&库安装

node.js是运行在服务端的JavaScript。

0 、文档参考:
https://www.w3cschool.cn/nodejs/
1 Nodejs 安装
https://nodejs.org/en

作者安装的是18.16.0.安装好后重启电脑,让环境进行配置。 (只有这样才能使npm,node这些生效)

2 、三方库安装
express
Express 是一个简洁而灵活的 node.js Web 应用框架
body-parser
node.js 中间件,用于处理 JSON, Raw, Text URL 编码的数据。
cookie-parser
这就是一个解析 Cookie 的工具。通过 req.cookies 可以取到传过来的 cookie ,并把
它们转成对象。
multer
node.js 中间件,用于处理 enctype="multipart/form-data" (设置表单的 MIME
编码)的表单数据。
mysql
Node.js 来连接 MySQL 专用库,并对数据库进行操作。
安装命令:
npm i express
npm i body-parser
npm i cookie-parser
npm i multer
npm i mysql

案例导入:

在js文件中创建一个sql.js,将端口创建为3000
//express_demo.js 文件
var express = require('express');
var app = express();

app.get('/', function (req, res) {
   res.send('Hello World');
})

var server = app.listen(3000, function () {

  var host = server.address().address
  var port = server.address().port

  console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

使用node .\sql.js进行运行:

无法运行时需要安装express库。

npm i express (会得到node modules)

运行结果:(文字路径不能太多)

网页源代码:

只显示了Hello World,没有显示visual studio中的代码

看到结果是运行结果而不是源代码

功能实现-NodeJS-数据库&文件&执行

登录操作

1 Express 开发
2 、实现用户登录
3 、加入数据库操作
1.先创建一个sql.html:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>后台登录</title>
  <style>
    body {
      background-color: #f1f1f1;
    }
    .login {
      width: 400px;
      margin: 100px auto;
      background-color: #fff;
      border-radius: 5px;
      box-shadow: 0 0 10px rgba(0,0,0,0.3);
      padding: 30apx;
    }
    .login h2 {
      text-align: center;
      font-size: 2em;
      margin-bottom: 30px;
    }
    .login label {
      display: block;
      margin-bottom: 20px;
      font-size: 1.2em;
    }
    .login input[type="text"], .login input[type="password"] {
      width: 100%;
      padding: 10px;
      border: 1px solid #ccc;
      border-radius: 5px;
      font-size: 1.2em;
      margin-bottom: 20px;
    }
    .login input[type="submit"] {
      background-color: #2ecc71;
      color: #fff;
      border: none;
      padding: 10px 20px;
      border-radius: 5px;
      font-size: 1.2em;
      cursor: pointer;
    }
    .login input[type="submit"]:hover {
      background-color: #27ae60;
    }
  </style>
</head>
<body>
<div class="login" >
  <h2>后台登录</h2>
  <form action="http://127.0.0.1:3000/login" method="POST">
    <label for="username">用户名:</label>
    <input type="text" name="username" id="username" class="user" >
    <label for="password">密码:</label>
    <input type="password" name="password" id="password" class="pass" >
  <button>登录</button>
  </form>
</div>

2.创建一个sql.js(覆盖掉之前那一个)

sql.js:

const express= require('express');
const app=express();


//get路由
app.get('/login',function(req,res){  //req访问,res结果
  res.send('<hr>登录页面</hr>');
})


app.get('/',function(req,res){
  //res.send('<hr>首页页面</hr>');
  res.sendFile(__dirname+'/'+'sql.html');  //当前运行下的/sql.html(渲染为此页面)
})

const server = app.listen(3000,function(){
  console.log('web的3000端口已启动!');
})

运行结果:

以get路由来传参:

对sql.html进行修改:

<div class="login" >
  <h2>后台登录</h2>
  <form action="http://127.0.0.1:3000/login" method="GET">
    <label for="username">用户名:</label>
    <input type="text" name="username" id="username" class="user" >
    <label for="password">密码:</label>
    <input type="password" name="password" id="password" class="pass" >
  <button>登录</button>
  </form>
</div>

对sql.js进行修改:

const express= require('express');
const app=express();


//get路由
app.get('/login',function(req,res){
  const u = req.query.username   //获取sql.html中的username
  const p = req.query.password   //获取sql.html中的password
  console.log(u);
  console.log(p)
  if(u == 'admin' && p == '123456'){
    res.send("欢迎进入后台管理页面")
  }else{
    res.send('登录用户或密码错误!');
  }
})


app.get('/',function(req,res){
  //res.send('<hr>首页页面</hr>');
  res.sendFile(__dirname+'/'+'sql.html');
})

const server = app.listen(3000,function(){
  console.log('web的3000端口已启动!');
})

运行结果:(使用console.log()来查看是否定义成功)

以post路由来传参:

修改后的sql.js:

const express= require('express');
const bodyParser = require('body-parser');
const app=express();
// 创建 application/x-www-form-urlencoded 编码解析
var urlencodedParser = bodyParser.urlencoded({ extended: false })

//get路由
app.get('/login',function(req,res){
  const u = req.query.username   //query适用于get
  const p = req.query.password
  console.log(u);
  console.log(p)
  if(u == 'admin' && p == '123456'){
    res.send("欢迎进入后台管理页面")
  }else{
    res.send('登录用户或密码错误!');
  }
})

//post路由
app.post('/login',urlencodedParser,function(req,res){
  const u = req.body.username;  //body适用于post
  const p = req.body.password;
  console.log(u);
  console.log(p);
  if(u == 'admin' && p == '123456'){
    res.send("欢迎进入后台管理页面")
  }else{
    res.send('登录用户或密码错误!');
  }
})
app.get('/',function(req,res){
  //res.send('<hr>首页页面</hr>');
  res.sendFile(__dirname+'/'+'sql.html');
})

const server = app.listen(3000,function(){
  console.log('web的3000端口已启动!');
})

在前面安装一个const bodyParser = require('body-parser');

在终端使用npm i body-parser安装库

使用:

// 创建 application/x-www-form-urlencoded 编码解析

var urlencodedParser = bodyParser.urlencoded({ extended: false })是为了使得在network里看到的数据username =111&password =111有一个规范的格式。

数据库管理:

数据库连接:


mysql连接代码:

var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'root',
  password : 'root',
  database : 'demo01'
});

connection.connect();
const sql = 'select * from admin ';
console.log(sql);
connection.query(sql,function(error,data){
  if(error){
      console.log('数据库连接失败!');
  }
      console.log(data);
})

效果展示:

与数据库相同

数据库与登录逻辑结合:
//post路由
app.post('/login',urlencodedParser,function(req,res){
  const u = req.body.username;
  const p = req.body.password;
  console.log(u);
  console.log(p);
  var connection = mysql.createConnection({
      host     : 'localhost',
      user     : 'root',
      password : 'root',
      database : 'demo01'
  });

  connection.connect();
  const sql = 'select * from admin where username="'+u+'" and password="'+p+'"';  
  console.log(sql);
  connection.query(sql,function(error,data){
      if(error){
          console.log('数据库连接失败!');
      }
      try{  //报错测试
          if(u==(data[0]['username']) && p==data[0]['password']){  
//data[0]的意思是取第一行数据['username']是取里面的username值
              res.send('欢迎进入后台管理页面');
          }
      }catch{
          res.send('错误');
      };
    })
  })

  
app.get('/',function(req,res){
  //res.send('<hr>首页页面</hr>');
  res.sendFile(__dirname+'/'+'sql.html');
})

const server = app.listen(3000,function(){
  console.log('web的3000端口已启动!');
})

效果展示:

使用永“真”语句注入的话,无论前面是什么都会全部回显。(or)

在页面注入:

测试下来后没有往后面运行:

证明前面的代码if(u==(data[0]['username']) && p==data[0]['password'])对其进行了过滤:

u==(data[0]['username']是用来判断键值是否相同,正常应该是数据库取出的行数进行判断,而不是data中取的值。

安全方法:

使用sql预编译进行写比较安全(secguide-main)

文件管理功能:

创建file.js:(记得npm i fs)

const fs=require('fs');
const express = require('express');
const app = express();

app.get('/file', function (req, res) {
    const dir=req.query.dir;   //接受dir
    console.log(dir);          //调试dir
    filemanage(dir);           //执行dir
})

var server = app.listen(3000, function () {
    console.log('web应用3000端口已启动!')
})

function filemanage(dir){
    fs.readdir(dir,function(error,files){
        console.log(files);
})};

运行结果:使用node .\file.js(在网址后面加上/file?dir=)

命令执行功能:

文件操作

1、Express开发
2、实现自录读取
3、加入传参接受
一命令执行(RCE)
1、eval
2、exec & spawnSyn

创建一个rce.js:(npm i child_process)

const rce=require('child_process');

//nodejs 调用系统命令执行
//rce.exec('notepad');
//rce.spawnSync('calc');

//nodejs 调用代码命令执行 把字符串当做代码解析
eval('require("child_process").exec("calc");');

node.js判断:


安全问题-NodeJs-注入&RCE&原型链


1、SQL注入&文件操作
2、RCE执行&原型链污染
2、NodeJS黑盒无代码分析

实战测试NodeJs安全
判断:参考前期的信息收集

黑盒:通过对各种功能和参数进行payload测试

白盒:通过对代码中写法安全进行审计分析


原型链污染


如果攻击者控制·并修改了一个对象的原型,(_proto_)那么将可以影响所有和这个对象来自同一个类、父祖类的对象。

// // foo是一个简单的JavaScript对象
// let foo = {bar: 1} //解释:1=1 0 __proto__= x
// // 原型链污染
// // foo.bar 此时为1
// console.log(foo.bar)

// // 修改foo的原型(即Object)
// foo.__proto__.bar = 'x'

// // // 由于查找顺序的原因,foo.bar仍然是1
// console.log(foo.bar)

// // // 此时再用Object创建一个空的zoo对象
// let zoo = {}

// // 查看zoo.bar,此时bar为2
// console.log(zoo.bar)


let foo = {bar: 1};

console.log(foo.bar);

foo.__proto__.bar = 'require(\'child_process\').execSync(\'calc\');'

console.log(foo.bar);

let zoo = {};

console.log(eval(zoo.bar));

运行结果:

案例分析-NodeJS-CTF题目&源码审计


1、CTFSHOW几个题日

https://ctfshow/Web334-344
https://f1veseven.github.io/2022/04/03/ctf-nodejs-zhi-yi-xie-xiao-zhi-shi/

CTFSHOW-334:

1.打开zip发现是pk开头:

证明是zip文件:使用winzip或者别的解压软件打开(Bandzip):

打开后由login.js和user.js:

(引用文章:Ctfshow web入门 nodejs篇 web334-web344-阿里云开发者社区)

login.js:

//login.js

var express = require('express');              //引入各个模块
var router = express.Router();
var users = require('../modules/user').items;   //引入用户模块(user.js)
 
var findUser = function(name, password){          //定义函数
  return users.find(function(item){
    return name!=='CTFSHOW' && item.username === name.toUpperCase() && item.password === password;
  });       //如果name不等于CTFSHOW,并且将name都转为大写与item.name(CTFSHOW)相同,password=123456。则findUser返回true  //toUpperCase()是javascript中将小写转换成大写的函数。
};

/* GET home page. */
router.post('/', function(req, res, next) {                 //POST请求的处理函数
  res.type('html');                                //设置响应(res)的内容类型为html
  var flag='flag_here';
  var sess = req.session;
  var user = findUser(req.body.username, req.body.password);
 
  if(user){
    req.session.regenerate(function(err) {
      if(err){
        return res.json({ret_code: 2, ret_msg: '登录失败'});        
      }
       
      req.session.loginUser = user.username;
      res.json({ret_code: 0, ret_msg: '登录成功',ret_flag:flag});   //登录成功返回flag
    });
  }else{
    res.json({ret_code: 1, ret_msg: '账号或密码错误'});
  }  
  
});

module.exports = router;   //通过module.exports将该路由模块导出,以便在其他文件中引入和使用

user.js: 

//user.js

module.exports = {
  items: [
    {username: 'CTFSHOW', password: '123456'}
  ]
};

//这段代码是一个模块文件,通过`module.exports`将一个对象导出。
//在这个模块中,导出的对象是一个包含一个属性`items`的对象。`items`属性是一个数组,包含了一个用户对象。这个用户对象有两个属性:`username`表示用户名为"CTFSHOW",`password`表示密码为"123456"。

//通过这种方式,其他文件可以引入该模块并访问`items`数组中的用户对象,用于验证用户的登录信息。

突破点:

1.2 nodejs语言的缺点

1.2.1 大小写特性

toUpperCase()
toLowerCase()

对于toUpperCase(): 字符"ı""ſ" 经过toUpperCase处理后结果为 "I""S"
对于toLowerCase(): 字符"K"经过toLowerCase处理后结果为"k"(这个K不是K)

var findUser = function(name, password){          //定义函数
  return users.find(function(item){
    return name!=='CTFSHOW' && item.username === name.toUpperCase() && item.password === password;
  });       //如果name不等于CTFSHOW,并且将name都转为大写与item.name(CTFSHOW)相同,password=123456。则findUser返回true  //toUpperCase()是javascript中将小写转换成大写的函数。
};

payload:

name:ctfshow

password:123456

result:


2、YApi管理平台漏洞
https://blog.csdn.net/weixin_42353842/article/details/127960229


开发指南-NodeJs-安全SecGuide项目:

https://github.com/Tencent/secguide

本文章由李豆豆喵和番薯小羊卷~共同完成。

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

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

相关文章

LongVU:用于长视频语言理解的空间时间自适应压缩

晚上闲暇时间看到一种用于长视频语言理解的空间时间自适应压缩机制的研究工作LongVU&#xff0c;主要内容包括&#xff1a; 背景与挑战&#xff1a;多模态大语言模型&#xff08;MLLMs&#xff09;在视频理解和分析方面取得了进展&#xff0c;但处理长视频仍受限于LLM的上下文长…

Observability:用 OpenTelemetry 自动检测 Python 应用程序

作者&#xff1a;来自 Elastic Bahubali Shetti 了解如何使用 OpenTelemetry 自动检测 Python 应用程序。使用 Docker 文件中的标准命令&#xff0c;可以快速检测应用程序&#xff0c;而无需在多个位置编写代码&#xff0c;从而实现快速更改、扩展和更轻松的管理。 更多阅读&a…

JVM, JRE 和 JDK

JRE: Java Runtime Environment, Java 运行环境. JDK: Java Development Kit, Java 开发工具包. JRE JVM 核心类库 运行工具 JDK JVM 核心类库 开发工具 JVM: Java Virtual Machine, Java 虚拟机. 核心类库: Java 已经写好的东西, 直接拿来用即可. 开发工具: 包括 …

Ubuntu 22.04.5 + kubeadm:Kubernetes v1.28.2集群部署企业实战

文章目录 Ubuntu 22.04.5 kubeadm&#xff1a;Kubernetes v1.28.2集群部署企业实战一、环境准备1.1 机器规划1.2 环境配置1.2.1 设置主机名1.2.2 安装依赖工具1.2.3 配置时间同步1.2.4 关闭swap分区1.2.5 停止和禁用防火墙1.2.6 配置内核转发及网桥过滤1.2.7 安装配置ipset及i…

Mac环境下brew安装LNMP

安装不同版本PHP 在Mac环境下同时运行多个版本的PHP&#xff0c;同Linux环境一样&#xff0c;都是将后台运行的php-fpm设置为不同的端口号&#xff0c;下面将已php7.2 和 php7.4为例 添加 tap 目的&#xff1a;homebrew仅保留最近的php版本&#xff0c;可能没有你需要的版本…

【Python网络爬虫笔记】8- (BeautifulSoup)抓取电影天堂2024年最新电影,并保存所有电影名称和链接

目录 一. BeautifulSoup的作用二. 核心方法介绍2.1 构造函数2.2 find()方法2.3 find_all()方法2.4 select()方法 三. 网络爬虫中使用BeautifulSoup四、案例爬取结果 一. BeautifulSoup的作用 解析HTML/XML文档&#xff1a;它可以将复杂的HTML或XML文本转换为易于操作的树形结构…

解决LED显示屏水波纹的方法

在拍摄LED显示屏时&#xff0c;水波纹和扫描线的出现常常让人误以为是显示屏质量问题&#xff0c;但实际上这些现象往往与拍摄角度和焦距有关。本文将探讨水波纹的成因&#xff0c;并提供一些有效的解决方法。 1. 水波纹与扫描线现象的区别 水波纹通常呈现无规则的弧形扩散状态…

【MySQL — 数据库基础】深入理解数据库服务与数据库关系、MySQL连接创建、客户端工具及架构解析

目录 1. 数据库服务&#xff06;数据库&#xff06;表之间的关系 1.1 复习 my.ini 1.2 MYSQL服务基于mysqld启动而启动 1.3 数据库服务的具体含义 1.4 数据库服务&数据库&表之间的关系 2. 客户端工具 2.1 客户端连接MySQL服务器 2.2 客…

记录关于阿里云智能媒体预览pdf文件的问题

pdf仅支持预览&#xff0c;不支持编辑&#xff0c;需要将权限设置成只读。 readonly参数一定要传&#xff0c;不能不传&#xff01;&#xff01;&#xff01;&#xff01; readonly的设置一定要用示例提供的方法&#xff01;&#xff01;&#xff01;&#xff01; 用WebofficeP…

FlyHttp 的设计思想:前端 API 自动化构建工具

FlyHttp的相关文章&#xff1a; FlyHttp 的诞生&#xff1a;从认识各种网络请求开始 FlyHttp 的设计思想&#xff1a;前端 API 自动化构建工具 FlyHttp 的使用&#xff1a;如何高效使用 FlyHttp&#xff0c;支持 JS、TS 项目 FlyHttp 的最佳实践&#xff1a;加速项目级 API…

WHLUG丨deepin、华中科技大学开放原子开源俱乐部、 RustSBI 和清华大学开源操作系统训练营共话开源新生代成长之路

2024年11月30日下午&#xff0c;由 deepin&#xff08;深度&#xff09;社区联合华中科技大学开放原子开源俱乐部、 RustSBI 开源社区和清华大学开源操作系统训练营共同举办的WHLUG&#xff08;武汉Linux用户组&#xff09;线下沙龙在华中科技大学成功举办。 本次活动聚集了50余…

K8S离线部署Nacos集群【Oracle作外部数据源】

一、前言 由于公司的要求下要使Nacos集群以Oracle作为外部数据源&#xff0c;前期咱们已经阐述了如何在本地搭建&#xff08;Nacos集群搭建【Oracle作外部数据源】&#xff09;&#xff0c;本次将带领大家在k8s上部署Nacos集群并以Oracle作为外部数据源。 二、软件包 nacos-f…

MperReduce学习笔记下

自定义InputFormat合并小文件 案例需求 无论hdfs还是mapreduce&#xff0c;对于小文件都有损效率&#xff0c;实践中&#xff0c;又难免面临处理大量小文件的场景&#xff0c;此时&#xff0c;就需要有相应解决方案。 案例分析 小文件的优化无非以下几种方式&#xff1a; …

Junit5 单元测试入门

基础知识 常用注解含义 Test&#xff1a;标记一个方法为测试方法BeforeEach&#xff1a;标记的方法会在每个测试方法执行前执行AfterEach&#xff1a;标记的方法会在每个测试方法执行后执行BeforeAll&#xff1a;标记的方法会在所有测试方法执行前执行一次AfterAll&#xff1…

【CSS in Depth 2 精译_065】第四部分:CSS 视觉增强技术 + 第 11 章 颜色与对比概述 + 11.1 通过对比进行交流

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第四部分 视觉增强技术 ✔️【第 11 章 颜色与对比】 ✔️ 11.1 通过对比进行交流 ✔️ 11.1.1 模式的建立 ✔️11.1.2 还原设计稿 ✔️ 11.2 颜色的定义 文章目录 第四部分 视觉增强技术 Visual e…

Java项目实战II基于微信小程序的作品集展示(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 随着移动互联网技术的飞速…

基于rpcapd与wireshark的远程实时抓包的方法

基于rpcapd与wireshark的远程实时抓包的方法 服务端安装wireshark侧设置 嵌入式设备或服务器上没有图形界面&#xff0c;通常使用tcpdump抓包保存为pcap文件后&#xff0c;导出到本地使用wireshark打开分析&#xff0c;rpcapd可与wireshark配合提供一种远程实时抓包的方案&…

记录一个Flutter 3.24单元测试点击事件bug

哈喽&#xff0c;我是老刘 这两天发现一个Flutter 3.24版本的单元测试的一个小bug&#xff0c;提醒大家注意一下。 老刘自己写代码十多年了&#xff0c;写Flutter也6年多了&#xff0c;没想到前两天在一个小小的BottomNavigationBar 组件上翻了车。 给大家分享一下事件的经过。…

JVM 类加载器有哪些?双亲委派机制的作用是什么?如何自定义类加载器?

类加载器分类 大家好&#xff0c;我是码哥&#xff0c;可以叫我靓仔&#xff0c;《Redis 高手心法》畅销书作者。 先回顾下&#xff0c;在 Java 中&#xff0c;类的初始化分为几个阶段: 加载、链接&#xff08;包括验证、准备和解析&#xff09;和 初始化。 而 类加载器&#x…

视频监控汇聚平台Liveweb视频安防监控实时视频监控系统操作方案

Liveweb国标GB28181视频平台是一种基于国标GB/T28181协议的安防视频流媒体能力平台。它支持多种视频功能&#xff0c;包括实时监控直播、录像、检索与回看、语音对讲、云存储、告警以及平台级联等功能。该平台部署简单、可扩展性强&#xff0c;支持全终端、全平台分发接入的视频…