假设您正在正确检查用户提供的操作数和运算符以确保它们包含您想要的数据而不是其他 javascript 可执行代码,您可以将两个操作数与中间的运算符连接起来并将其提供给 eval() 以执行它。
现在,eval() 是危险,因为它可以执行任何 JavaScript 代码。用户可以提供可执行的和可能是恶意的 JavaScript 代码作为操作员,eval() 将对其进行评估。因此,当您进行连接时,您应该在验证操作数是安全的之后再进行。为了强调这一点,我将用大字体写出计算机安全最重要的原则之一:
除非证明不是这样,否则所有输入都是邪恶的。
另外,请注意eval() 调用 JavaScript 解释器来解释、编译和执行您的代码。这很慢。如果您只是偶尔使用eval(),您可能不会注意到任何可观察到的性能问题,但如果您非常频繁地调用eval(),例如在每个关键事件上,您可能会注意到性能问题。
考虑到eval() 的这些缺点,您可能希望采用一种更简洁的解决方案,例如 Felix Kling 发布的解决方案。但是,也可以使用eval() 以安全的方式解决此问题,如下所示:
function compare(a, op, b)
{
// Check that we have two numbers and an operator fed as a string.
if (typeof a != 'number' || typeof b != 'number' || typeof op != 'string')
return
// Make sure that the string doesn't contain any executable code by checking
// it against a whitelist of allowed comparison operators.
if (['<', '>', '<=', '>=', '==', '!='].indexOf(op) == -1)
return
// If we have reached here, we are sure that a and b are two integers and
// op contains a valid comparison operator. It is now safe to concatenate
// them and make a JavaScript executable code.
if (eval(a + op + b))
doSomething();
}
请注意,根据白名单验证输入几乎总是比根据黑名单验证输入更好。请参阅https://www.owasp.org/index.php/Input_Validation_Cheat_Sheet#White_List_Input_Validation 进行简要讨论。
这里是这个解决方案的演示:http://jsfiddle.net/YrQ4C/(代码也在下面转载):
function doSomething()
{
alert('done something!')
}
function compare(a, op, b)
{
if (typeof a != 'number' || typeof b != 'number' || typeof op != 'string')
return
if (['<', '>', '<=', '>=', '==', '!='].indexOf(op) == -1)
return
if (eval(a + op + b))
doSomething();
}
// Positive test cases
compare(2, '<', 3)
compare(2, '<=', 3)
// Negative test cases
compare(2, '>', 3)
compare(2, '>=', 3)
// Attack tests
compare('alert(', '"attack!"', ')')
// Edit: Adding a new attack test case given by Jesse
// in the comments below. This function prevents this
// attack successfully because the whitelist validation
// for the second argument would fail.
compare(1, ';console.log("executed code");2==', 2)
编辑:包含 Jesse 测试用例的演示:http://jsfiddle.net/99eP2/