柏鹭杯中关于NodeJS题的源代码详细分析
const express = require("express");
const fs = require("fs");
const app = express();
const PORT = process.env.PORT || 3456;
app.use((req, res, next) => {
if([req.body, req.headers, req.query].some(
(item) => item && JSON.stringify(item).includes("flag")//ban 掉了 flag
)) {
return res.send("bad hacker!");
}
next();
});
app.get("/", (req, res) => {
try {
res.setHeader("Content-Type", "text/html");
res.send(fs.readFileSync(req.query.file || "index.html").toString());
}
catch(err) {
console.log(err);
}
});
app.listen(PORT, () => console.log(`web/simplewaf listening on ${PORT}`));
首先来分析引用的模块的作用(类比python的import)
1.express
Express 是一个流行的 Node.js Web 应用程序框架,它简化了使用 Node.js 构建 Web 应用程序的过程。
路由和中间件:Express 提供了路由和中间件机制,使得请求的处理和路由非常灵活。您可以定义各种 HTTP 请求方法(GET、POST、PUT、DELETE 等)和对应的路由处理器,以及中间件函数来处理请求前、请求后的逻辑。这使得构建复杂的路由和处理请求的流程变得简单和可维护。
请求和响应处理:Express 提供了简化请求和响应处理的功能。您可以轻松地访问请求的参数、头部、正文等,并且可以设置响应的状态码、头部、正文等。
2.fs
fs
模块是 Node.js 核心模块之一,用于处理文件系统操作。它提供了一组丰富的方法,可以对文件进行读取、写入、删除、重命名等各种操作。
- 读取文件:使用
fs.readFile()
方法可以异步地读取文件的内容,并将内容作为回调函数的参数返回。如果需要同步读取文件,可以使用fs.readFileSync()
方法。 - 写入文件:使用
fs.writeFile()
方法可以异步地将数据写入文件。如果需要同步写入文件,可以使用fs.writeFileSync()
方法。 - 追加文件:使用
fs.appendFile()
方法可以异步地将数据追加到文件的末尾。如果需要同步追加文件,可以使用fs.appendFileSync()
方法。 - 删除文件:使用
fs.unlink()
方法可以异步地删除文件。如果需要同步删除文件,可以使用fs.unlinkSync()
方法。 - 重命名文件:使用
fs.rename()
方法可以异步地重命名文件或将文件移动到另一个目录。如果需要同步重命名文件,可以使用fs.renameSync()
方法。 - 检查文件状态:使用
fs.stat()
方法可以异步地获取文件的状态信息,如文件大小、创建时间等。如果需要同步获取文件状态,可以使用fs.statSync()
方法。 - 创建目录:使用
fs.mkdir()
方法可以异步地创建目录。如果需要同步创建目录,可以使用fs.mkdirSync()
方法。 - 读取目录:使用
fs.readdir()
方法可以异步地读取目录,并返回目录中的文件和子目录列表。如果需要同步读取目录,可以使用fs.readdirSync()
方法。 - 监听文件变化:使用
fs.watch()
方法可以异步地监听文件的变化,如文件的修改、删除等操作。
3.const app=express();
的作用
分析 const app = express();
通过调用 express()
创建一个 Express 应用程序实例。将创建的 Express 应用程序实例赋值给一个变量,这里使用 app
作为变量名。这样,后续的代码就可以通过 app
来访问和操作 Express 应用程序。
4.分析第一个函数app.use()
首先介绍一下中间件函数。简单提一嘴,中间件函数是 Express 框架中用于处理 HTTP 请求的函数.app.use()就是一个。
req、res 和 next 参数在 Express 中间件函数中是自动提供的,无需显式定义
req:代表请求对象,包含了请求的信息,如请求头、请求体、URL 参数等。
res:代表响应对象,用于发送响应给客户端,如设置响应头、发送响应体等。
next:是一个回调函数,用于将控制权传递给下一个中间件函数或路由处理器。通过调用 next(),Express 将执行后续的中间件或路由处理器。再去了解下NodeJS的回调函数吧。还是很有特色的、
然后把这三个参数放在了数组,调用了数组方法,继续介绍
some() 是 JavaScript 数组的方法,用于检查数组中是否至少有一个元素满足指定的条件。他是会遍历数组的。在这里,some() 方法用于检查 req.body、req.headers 和 req.query 数组中是否有任何一个元素包含了 "flag" 字符串。
箭头函数 (item) => item 的作用是将传入的参数原封不动地返回。 :
JSON.stringify() 是将 JavaScript 对象转换为 JSON 字符串的方法。在这里,它用于将 req.body、req.headers 和 req.query 转换为字符串,以便进行包含 "flag" 的检查。
如果没有包含 "flag",则调用 next(),将控制权传递给下一个中间件或路由处理器。
5. 二个函数
主要是接收GET请求,关键的地方
res.send(fs.readFileSync(req.query.file || "index.html").toString()):这行代码读取文件内容并将其作为响应发送给客户端。fs.readFileSync() 用于同步读取文件,req.query.file || "index.html" 表示从查询参数中获取 file 参数的值,如果没有提供默认为 "index.html"。.toString() 方法将文件内容转换为字符串。
剩下的攻击分析WP
req.query.file 是一个表达式,用于获取 Express 框架中请求对象 req 的查询参数中名为 "file" 的值。
在 Express 中,请求对象 req 的 query 属性是一个对象,它包含了客户端发送的查询参数。通过访问 req.query,您可以获取到一个包含查询参数的对象。
req.query.file 则是通过点 (.) 运算符从 req.query 对象中获取名为 "file" 的属性值。