首页 > 解决方案 > 我在服务器中安全地使用 eval() 吗?

问题描述

简而言之,我正在使用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 的可利用性?提前致谢

标签: javascriptexpresssecurityevalserver-side

解决方案


所以问题是:从任何不需要的字符串(名称)中过滤数组是否足够安全以对抗 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()用来调用它的方法。这还添加了此代码无法调用不在查找表中的任何函数的安全功能。


推荐阅读