提问人:Kostas Xafis 提问时间:12/5/2020 更新时间:12/5/2020 访问量:295
我在服务器中安全地使用 eval() 吗?
Am i using eval() safely in server?
问:
简而言之,我正在使用 eval 动态调用用于验证客户端 cookie 的函数(所有函数前面都有相同的名称,最后一位不同)。
const cookie_names = ['cookiename_1', 'cookiename_2'];
exports.validateCookies = (req, res, next) => {
const cookie_types = filterUnknownCookies(Object.keys(req.cookies));
for(let cookie of cookie_types){
res.locals[cookie] = eval(`validateCookie${cookie}('${req.cookies[cookie]}')`);
}
next();
}
const filterUnknownCookies = (cookie_arr) => {
cookie_arr = cookie_arr.filter(name => cookie_names.findIndex( validnames => validnames === name) + 1);
return cookie_arr;
}
由于我知道使用 eval 函数可能很危险,所以我对有效的 cookie 名称进行了硬编码,并过滤了数组中与它们不匹配的任何内容。 那么问题来了:从任何不需要的字符串(名称)中过滤数组是否足够安全,以对抗 eval 的可利用性? 提前🧡🧡致谢
答:
那么问题来了:从任何不需要的字符串(名称)中过滤数组是否足够安全,以对抗 eval 的可利用性?
不。这是不安全的。事实上,它基本上没有保护你,因为你允许的cookie名称仍然完全没有保护和消毒。你所拥有的东西可能是不安全的,因为恶意客户端可以在该cookie中放入他们想要的任何东西,而你“希望”他们找不到会突破你拥有的字符串分隔符的东西。但是,可以通过终止字符串然后添加函数调用来突破该字符串分隔符。这可能会允许攻击者在您的服务器上执行任意代码。
你唯一应该使用的是来自你自己的服务器端代码的受信任字符串或来自外部的完全清理的字符串。但是,几乎总是,您不需要,因为还有另一种更安全的编码方式。eval()
eval()
在这里,您根本不需要使用。您可以只为要调用的合法函数创建一个查找表,然后将函数直接传递给它:eval()
try {
res.locals[cookie] = validateCookie[cookie](req.cookies[cookie]);
} catch(e) {
// either invalid cookie or exception in the function
// handle that here
}
而且,当然,你的函数也必须进行防御性编码,以知道它可能会被传递任何东西。您不会向我们展示该函数的代码,以便能够进一步对其进行注释。validateCookie[cookie]()
在本例中,是包含有效名称及其相应函数的查找表:validateCookie
cookie
// cookie processing lookup table
const validateCookie = {
cookieName1: validateCookieName1,
cookieName2: validateCookieName2
};
像这样的查找表通常是避免尝试制造函数名称和字符串并用于调用它的方式。这还增加了安全功能,即此代码无法调用不在查找表中的任何函数。eval()
评论
eval
eval()
eval()
不,代码不安全,不是因为它没有清理验证方法的名称,而是因为它在扩展字符串模板文本时将上传的文本评估为 JavaScript:
`... ${req.cookies[cookie]} ...`
我刚刚使用精心制作的字符串值测试并注入了代码,我将避免在此处发布。req.cookies[cookie]
在不扩展数据字符串的情况下评估验证调用可能稍微安全一些,如
`validateCookie${cookie}` + "(req.cookies[cookie])"
这会将上传的文本传递到验证例程,而无需将评估作为代码进行评估,但完全避免的安全性保持不变。通过使用按函数名称键控的验证函数对象值的查找表,可以很容易地避免。eval
eval
评论