taibeihacker
Moderator
NodeJS 安全
1 NodeJS 基础
1.1 定义与原理
是一個開源的、跨平台的運行時環境,有了它,開發人員可以使用JavaScript 創建各種服務器端工具和應用程序。此運行時要用於瀏覽器上下文之外(即可以直接運行於計算機或服務器操作系統上)。1.2 常见框架
Express 是最流行的Node 框架,是許多其它流行Node 框架的底層庫。雖然Express 本身是極簡風格的,但是開發人員通過創建各類兼容的中間件包解決了幾乎所有的web 開發問題。這些庫可以實現cookie、會話、用戶登錄、URL 參數、POST 數據、安全頭等功能。特點:
為不同URL 路徑中使用不同HTTP 動詞的請求(路由)編寫處理程序。
集成了「視圖」渲染引擎,以便通過將數據插入模板來生成響應。
設置常見Web 應用設置,比如用於連接的端口,以及渲染響應模板的位置。
在請求處理管道的任何位置添加額外的請求處理「中間件」。
1.3 Node 环境
1.3.1 基础环境
下載地址:https://nodejs.org/en/從HelloWorld 程序開始
1
2
3
4
5
const http=require('http');
http.createServer((req, res)={
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(80);

1.3.2 Express 环境简介
安裝1
npm install express
從HelloWorld 程序開始
1
2
3
4
5
6
7
8
9
10
const express=require('express');
const app=express();
app.get('/hello', (req, res)={
res.send('Hello World');
});
app.listen(80, ()={
console.log('listen on 80');
});
2 Express 及其组件
2.1 路由模块
路由的作用就是解析URL,調用對應的控制器(的方法,並傳遞參數)。客戶端的請求是以URL 的形式傳遞給服務器的。傳統WEB 開發中,URL 對應服務器上某個目錄下的某個文件。 MVC 開發則改變了這種對應關係,WEB 服務器會截獲所有請求,不做資源存在性檢查,直接轉發給網站的路由程序。
路由器再調用相關的控制器。控制器調用相關的服務,並返回視圖對象。路由器再從視圖對像中提取生成好的網頁代碼返回給Web 服務器,最終返回給客戶端。
舉例:
download.js
1
2
3
4
5
6
7
8
9
10
11
const express=require('express');
const router=express.Router();
router.get('/', (req, res)={
res.send('download page');
});
router.get('/docs', (req, res)={
res.send('download page docs');
});
module.exports=router;
main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const express=require('express');
const app=express();
const download=require(__dirname + '/download.js');
app.use('/download', download);
app.get('/', (req, res)={
res.send('Hello World');
});
app.get('/news', (req, res)={
res.send('news page');
});
app.listen(80, ()={
console.log('listen on 80');
});
app.use 表示對所有路由,和所有方法都調用中間函數
app.get (’/’)表示對get 方法開頭的URL 調用中間函數
app.use(’/download’) 表示對/download 頭的所有,調用中間函數。

2.1 中间件
中間件在Express 應用中得到了廣泛使用。大多數應用會使用第三方中間件來簡化常見的web 開發任務,比如cookie、會話、用戶身份驗證、訪問請求POST 和JSON 數據,日誌記錄、壓縮HTTP 響應等等。一些中間件的引入順序很重要(例如,如果會話中間件依賴於cookie 中間件,則必須先添加cookie 處理器)。絕大多數情況下要先調用中間件後設置路由,否則路由處理器將無法訪問中間件的功能。 morgan 是一個日誌記錄的中間件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const express=require('express');
const app=express();
const download=require(__dirname + '/download.js');
const logger=require('morgan');
app.use(logger('dev'));
app.listen(80, ()={
console.log('listen on 80');
});
app.use('/download', download);
app.get('/', (req, res)={
res.send('Hello World');
});
app.get('/news', (req, res)={
res.send('news page');
});
中间件和路由函数是按照声明顺序调用的
2.2 渲染
PUG 模板引擎是一款健壯、靈活、功能豐富的HTML 模板引擎專門為Node 平台開發。 PUG 是由Jade 改名而來。Pug 通過縮進(表示標籤間的嵌套關係)的方式來編寫代碼的過程,在編譯的過程中,不需要考慮標籤是否閉合的問題。
pugDemo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const express=require('express');
const app=express();
const path=require('path');
app.listen(80, ()={
console.log('listening on 80');
});
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.get('/', function(req, res) {
res.render('index', {title: 'Hello', message: 'hello world pug engine'})
})
views/index.pug
1
2
3
4
5
html
head
title=title
body
h1=message

3 威胁分析
3.1 常见漏洞
代碼執行,命令執行,XSS,SQL 注入,SSRF,文件上傳nodejs 對一些經典web 漏洞,有一定防護,有的漏洞在其他語言中不明顯。但在nodejs 中比較突出。
require 鏈劫持(軟件投毒),正則表達式拒絕服務(ReDoS),不安全的包。
3.2 代码审计
3.2.1 项目结构

3.2.2 审计依赖
nsp 是檢測包依賴的工具,被收購後,在npm=6.0.0,使用如下指令:1
2
npm audit
npm audit fix

3.2.3 不安全的对象直接引用
12
3
4
5
6
7
8
9
function isAdmin(req, res, next) {
if(req.user.role=='admin') //檢測賬號用戶是否是admin
return next();
//如果不是,報錯
res.redirect('/403');
}
app.get('/admin', isAdmin, function(req, res) {
res.send('secret');
});
3.2.4 敏感信息泄露
12
3
app.use(function(err, req, res, next) {
res.status(500).send(err.stack);
})
3.2.5 未经验证的重定向和转发
SSRF1
2
3
4
5
6
7
app.use('/redirect', function(req, res) {
request(req.query.url, function(error, response, body){
if(err) {
return res.send(body);
}
})
})
3.3 安全配置
HelmetStrict-Transport-Security 強制實施與服務器的安全(http over SSL/TLS)連接X-Frame-Options 提供點擊劫持保護
XSS-Protection 支持在最新的Web 瀏覽器中內置的跨站點腳本(XSS)過濾器
X-Content-Type-Options 可防止瀏覽器從聲明的內容類型中嗅探響應
Content-Security-Policy 可防止各種攻擊,包括跨站點腳本和其他跨站點注入
4 常见问题
4.1 XSS
12
3
sudo docker pull registry.cn-shanghai.aliyuncs.com/yhskc/chatsys:latest
sudo docker run -d -p 0.0.0.0:32888:80 registry.cn-shanghai.aliyuncs.com/yhskc/chatsys
Pug XSS
练习一:

採用了轉義的方式進行輸出,因此無法繞過
练习二:

採用未轉義的方式,因此直接採用常規payload 即可

练习三:

在script 標籤中,因此直接採用行內閉合後拼接的方式可以XSS,payload:1;alert(1)

练习四:

仍然是未轉義模式,直接拼接即可

练习五:

發現其過濾了尖括號、alert、分號等敏感字符

利用JSFuck 繞過濾
1
[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[+[]]+(![]+[])[!+[]+!+[]+!+[]]+(![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[ ]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[+[]]+(![]+[])[!+[]+!+[]+!+[]]+(![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]]) [+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[+[]]+(![]+[])[!+[]+!+[]+!+[]]+(![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(![]+[])[+[]]+(![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[+[]]+(![]+[])[!+[]+!+[]+!+[]]+ (![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[+[]]+(![]+[])[!+[] +!+[]+!+[]]+(![]+[])[+!+[]]])[+!+[]+[+[]]]+(![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(![]+[])[+!+[]]+(![]+[])[+[] ]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[+[]]+(![]+[])[!+[]+!+[]+!+[]]+(![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+ []]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[+[]]+(![]+[])[!+[]+!+[]+!+[]]+(![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()
