标题:Node.js代码执行绕过的一些技巧汇总
一、概述
Node.js是一款非常流行的JavaScript运行环境,但在代码执行过程中可能也会出现漏洞使得攻击者可以执行一些不受欢迎的代码。本文将探讨几种绕过代码执行漏洞的技巧。
二、技巧汇总
- 绕过输入过滤
当从前端获取用户输入时,很重要的一步就是对数据进行输入检查。但只是检查数据的类型是不够的,因为攻击者可以使用一些特殊字符绕过检查。例如:
const input = req.body.input
fs.readFile('/var/www/html/' + input + '.html', function (err, data) {
if (err) {
console.log(err);
} else {
res.send(data);
}
});
攻击者可以使用../
字符来绕过input
变量的检查,从而获取文件系统中敏感文件的访问权限。此时可以在代码中对输入进行过滤,使用path.resolve
方法来限制访问文件的路径:
const path = require('path');
const input = path.resolve(req.body.input);
const fullPath = '/var/www/html/' + input + '.html';
fs.readFile(fullPath, function (err, data) {
if (err) {
console.log(err);
} else {
res.send(data);
}
});
- 绕过函数执行
时常存在通过eval()函数、Function()函数或从数据库中拿到函数文本执行等情况。例如:
let funcStr = 'console.log("Hello, world!")';
let func = new Function(funcStr);
func();
但攻击者可以将恶意脚本注入到函数字符串中来执行恶意代码:
let funcStr = 'console.log("Hello, world!");alert("You are hacked!");';
let func = new Function(funcStr);
func();
此时可以使用Function
的函数签名,在传递给函数前先将所有非字符元素删除:
let funcStr = 'console.log("Hello, world!");alert("You are hacked!");';
let sanitizedFuncStr = funcStr.replace(/[^-\w\s,'"]+/g, '');
let func = new Function(sanitizedFuncStr);
func();
三、示例说明
示例一:目录遍历漏洞
当程序对用户输入缺乏过滤和校验时,可能遭受到目录遍历漏洞攻击。例如以下web服务:
const http = require('http');
const fs = require('fs');
const server = http.createServer(function (req, res) {
if (req.url === '/') {
res.writeHead(200, {'Content-Type': 'text/html'});
fs.readFile(__dirname + '/index.html', function (err, data) {
res.end(data);
});
} else if (req.url === '/static') {
const fileName = __dirname + req.query.path;
fs.readFile(fileName, function (err, data) {
if (err) {
res.writeHead(404);
res.end('File not found.');
} else {
res.writeHead(200);
res.end(data);
}
});
} else {
res.writeHead(404);
res.end('Page not found.');
}
});
server.listen(8000);
console.log('Server running at http://127.0.0.1:8000/');
攻击者可以在请求url为/static
时通过修改path
参数来实现目录遍历攻击。
修改后的代码为:
const http = require('http');
const fs = require('fs');
const server = http.createServer(function (req, res) {
if (req.url === '/') {
res.writeHead(200, {'Content-Type': 'text/html'});
fs.readFile(__dirname + '/index.html', function (err, data) {
res.end(data);
});
} else if (req.url === '/static') {
const fileName = __dirname + req.query.path;
// 阻止目录遍历攻击
if (fileName.indexOf(__dirname) !== 0) {
res.writeHead(403);
res.end('Forbidden.');
return;
}
fs.readFile(fileName, function (err, data) {
if (err) {
res.writeHead(404);
res.end('File not found.');
} else {
res.writeHead(200);
res.end(data);
}
});
} else {
res.writeHead(404);
res.end('Page not found.');
}
});
server.listen(8000);
console.log('Server running at http://127.0.0.1:8000/');
当fileName
包含__dirname
(当前文件所在目录)时,才会执行读取文件操作,从而阻止目录遍历漏洞攻击。
示例二:代码注入漏洞
当程序加载用户提供的脚本时,可能产生代码注入漏洞攻击。例如以下web服务:
const express = require('express')
const app = express()
app.get('/user/:id', function (req, res, next) {
const id = req.params.id
const user = `User info: ${id}`
const script = `<script>alert('${user}')</script>`
res.send(`<p>${user}</p> ${script}`)
})
app.listen(3000, function () {
console.log('Server listening on port 3000!')
})
攻击者可以通过在url参数中注入脚本来实现XSS攻击。例如:
http://localhost:3000/user/123%3Cscript%3Ealert(%27hacked%27)%3C/script%3E
修改后的代码为:
const express = require('express')
const app = express()
const sanitizeHtml = require('sanitize-html');
app.get('/user/:id', function (req, res, next) {
const id = sanitizeHtml(req.params.id);
const user = `User info: ${id}`
const script = `<script>alert('${user}')</script>`
res.send(`<p>${user}</p> ${script}`)
})
app.listen(3000, function () {
console.log('Server listening on port 3000!')
})
使用sanitize-html
库可以对用户输入进行HTML过滤,从而防止代码注入漏洞攻击。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:nodejs代码执行绕过的一些技巧汇总 - Python技术站