multer中间件的安全问题

Heero.Luo发表于8年前,已被查看2017次

昨天备份本博客的时候发现,上传目录下多了几个奇怪的.asp和.php文件。这些文件并非我自己上传的,很可能是通过某个漏洞传到了服务器上。这会有什么危害呢?下面简单介绍一下。

假设某人把一个功能为删除站点下所有文件的evil.php通过漏洞传到了http://abc.com/upload/下,然后访问http://abc.com/upload/evil.php,那么:

  • 如果该站点不支持php脚本,是没什么危害的;
  • 如果该站点支持php脚本,它的全部文件就会被删除。

这里有两个关键点,一是主动访问该文件才会触发脚本执行,二是服务器支持该类型脚本才能执行。而本博客刚好不具备这两个条件(后面再详细说明),所以没有造成任何损失。即便如此,这漏洞还是要修复的,不然被无休止地上传文件迟早会占满硬盘空间。

本博客基于express框架开发,上传功能是通过multer中间件实现的,且只有管理后台存在文件上传的功能。因为后台页面、接口都设有权限验证,是不可能被绕过的。最后发现问题出在multer的调用上,而这问题又要归咎于官方文档的错误引导了:

app.use(multer({
	dest: './uploads/',
	rename: function (fieldname, filename) {
		return filename.replace(/\W+/g, '-').toLowerCase() + Date.now()
	}
}))
app.use(multer({
	dest: './public/upload/',
	rename: function () {
		var now = new Date();
		// 重命名为 年+月+日+时+分+秒+5位随机数
		return now.getFullYear() +
			( '0' + (now.getMonth() + 1) ).slice(-2) +
			( '0' + now.getDate() ).slice(-2) +
			( '0' + now.getHours() ).slice(-2) +
			( '0' + now.getMinutes() ).slice(-2) +
			( '0' + now.getSeconds() ).slice(-2) +
			parseInt(10000 + Math.random() * 90000);
	}
}))

上面第一段代码为官方文档的示例,第二段代码是我在博客程序中的调用方法。而这样写就意味着所有http访问(包括404的访问)都会经过multer这个中间件。所以只要某个http访问中包含文件,该文件就会被multer保存到指定目录(dest)下。

安全的用法应该是,只对指定路径调用multer中间件,并且增加权限验证:

// 权限检查
function addPermissionChecking(handler) {
	return function(req, res, next) {
		// 假设用户信息保存在req.currentUser中
		if (req.currentUser) {
			handler.apply(this, arguments);
		} else {
			next('权限不足');
		}
	};
}

app.use(
	'/upload',
	addPermissionChecking(
		multer({
			dest: './public/upload/',
			rename: function () {
				var now = new Date();
				// 重命名为 年+月+日+时+分+秒+5位随机数
				return now.getFullYear() +
					( '0' + (now.getMonth() + 1) ).slice(-2) +
					( '0' + now.getDate() ).slice(-2) +
					( '0' + now.getHours() ).slice(-2) +
					( '0' + now.getMinutes() ).slice(-2) +
					( '0' + now.getSeconds() ).slice(-2) +
					parseInt(10000 + Math.random() * 90000);
			}
		})
	)
);

就这样,问题解决了。最后再解释一下为什么本博客没有受到脚本文件的影响:

  • 上传的文件经过重命名,且新文件名中包含随机数,也就是说攻击者就算上传了脚本文件也无法获知文件名,也就不知道访问路径;
  • 在express中压根儿不支持ASP和PHP。

评论 (2条)

发表评论

(必填)

(选填,不公开)

(选填,不公开)

(必填)