我在服务器中安全地使用 eval() 吗?

Am i using eval() safely in server?

提问人:Kostas Xafis 提问时间:12/5/2020 更新时间:12/5/2020 访问量:295

问:

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

JavaScript Express 安全 评估 服务器端

评论

0赞 M-Chen-3 12/5/2020
取决于用户是否可以创建 Cookie。
0赞 Kosh 12/5/2020
请分享您的网站网址 =))
0赞 jfriend00 12/5/2020
@M-Chen-3 - 任何恶意用户都可以创建他们想要的任何 cookie,并将其附加到进入您服务器的请求中。
0赞 M-Chen-3 12/5/2020
@jfriend00哎呀。很高兴知道。这是我第一次害怕饼干。
0赞 Kostas Xafis 12/5/2020
@Kosh所以我的网站是:DoYouUseStackOverflow.ToAttackOthers.huh 继续试一试(●'◡'●)

答:

3赞 jfriend00 12/5/2020 #1

那么问题来了:从任何不需要的字符串(名称)中过滤数组是否足够安全,以对抗 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]()

在本例中,是包含有效名称及其相应函数的查找表:validateCookiecookie

 // cookie processing lookup table
 const validateCookie = {
      cookieName1: validateCookieName1,
      cookieName2: validateCookieName2
 };

像这样的查找表通常是避免尝试制造函数名称和字符串并用于调用它的方式。这还增加了安全功能,即此代码无法调用不在查找表中的任何函数。eval()

评论

0赞 M-Chen-3 12/5/2020
不相关,但我在我的 CS50 计算器中使用是否安全,因为我控制用户可以输入的内容?链接到我的个人资料中。eval
0赞 jfriend00 12/5/2020
@M-Chen-3 - 我没有研究你的代码,但来自客户端的任何内容都是不安全的。它可以被任何恶意攻击者欺骗或控制。您可以控制在网页中键入的内容,但无法控制某些攻击者在对您的服务器发出的制造请求中输入的内容。因此,在来自客户端的任意字符串上使用是不安全的。我们必须查看您的服务器代码以及您用于何处/用途才能进一步发表评论。这应该是一个新问题,而不是捎带这个问题。eval()eval()
0赞 M-Chen-3 12/5/2020
公平地说,我会问一个新问题。
0赞 Kostas Xafis 12/5/2020
🧡@jfriend00 非常感谢您的帮助和见解🧡,我完全误判了网络可以提供的欺骗数量......尽管 validationCookie 函数仅将字符串作为参数,然后使用我制作的 cookie 的本地数据库进行检查,但我很确定您提供的答案实际上更简单、更安全 10 倍。
1赞 traktor 12/5/2020 #2

不,代码不安全,不是因为它没有清理验证方法的名称,而是因为它在扩展字符串模板文本时将上传的文本评估为 JavaScript:

 `... ${req.cookies[cookie]} ...`

我刚刚使用精心制作的字符串值测试并注入了代码,我将避免在此处发布。req.cookies[cookie]

在不扩展数据字符串的情况下评估验证调用可能稍微安全一些,如

`validateCookie${cookie}` + "(req.cookies[cookie])"

这会将上传的文本传递到验证例程,而无需将评估作为代码进行评估,但完全避免的安全性保持不变。通过使用按函数名称键控的验证函数对象值的查找表,可以很容易地避免。evaleval