Suponiendo que está comprobando correctamente los operandos y operadores proporcionados por el usuario para asegurarse de que contienen los datos que desea en lugar de otro código ejecutable de JavaScript, puede concatenar los dos operandos con el operador intermedio y alimentarlo al eval()
para obtener se ejecutó.
Ahora, eval()
es peligroso porque puede ejecutar cualquier código JavaScript. El usuario puede alimentar código JavaScript ejecutable y posiblemente malicioso como el operador y eval()
lo evaluaría. Por lo tanto, cuando realiza la concatenación, debe hacerlo después de validar que el operando es seguro. Para enfatizar este punto, escribiré uno de los principios más importantes de la seguridad informática en fuentes grandes:
Todas las entradas son malas hasta que se demuestre lo contrario.
Además, tenga en cuenta que eval()
llama al intérprete de JavaScript para interpretar, compilar y ejecutar su código. Esto es lento Si bien es posible que no observe ningún problema de rendimiento observable si solo está usando eval()
de vez en cuando, puede notar problemas de rendimiento si llama al eval()
con mucha frecuencia, por ejemplo, en cada evento.
Teniendo en cuenta estos inconvenientes de eval()
, es posible que desee ir a una solución más ordenada como la publicada por Felix Kling. Sin embargo, también es posible resolver este problema utilizando eval()
de una manera segura, como se muestra a continuación:
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();
}
Tenga en cuenta que la validación de la entrada en contra de una lista blanca es casi siempre una idea mejor que validarla contra una lista negra. Ver https://www.owasp.org/index.php/Input_Validation_Cheat_Sheet#White_List_Input_Validation para una breve discusión sobre el mismo.
Aquí es una demostración de esta solución: http://jsfiddle.net/YrQ4C/ (Código también se reproducen a continuación):
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)
Editar: Demostración de caso de prueba de Jesse incluye: http://jsfiddle.net/99eP2/
pues no, no se puede hacer eso en JS –