Вот идея. Что делать, если вы использовали статический анализатор (что-то, что вы могли бы построить, например, с помощью esprima ), чтобы определить, какие внешние переменные использует код eval'd, и присвоить им псевдоним. Под «внешним кодом» я имею в виду переменные, в которых eval'd-код использует , но не объявляет . Вот пример:
eval(safeEval(
"var x = window.theX;"
+"y = Math.random();"
+"eval('window.z = 500;');"))
где safeEval возвращает строку javascript, измененную с контекстом, который блокирует доступ к внешним переменным:
";(function(y, Math, window) {"
+"var x = window.theX;"
+"y = Math.random();"
+"eval(safeEval('window.z = 500;');"
"})();"
Есть несколько вещей, которые вы можете теперь сделать с этим:
- Вы можете убедиться, что eval'd-код не может ни читать значения внешних переменных, ни записывать их (передавая
undefined
в качестве аргументов функции или не передавая аргументы). Или вы можете просто вызвать исключение в случаях небезопасного доступа к переменным.
- Вы также гарантируете, что переменные, созданные eval, не влияют на окружающую область видимости
- Вы можете разрешить eval создавать переменные в окружающей области видимости, объявив эти переменные вне замыкания, а не в качестве параметров функции
- Вы можете разрешить доступ только для чтения, копируя значения внешних переменных и используя их в качестве аргументов функции
- Вы можете разрешить доступ на чтение и запись к определенным переменным, сказав safeEval, чтобы они не называли эти конкретные имена
- Вы можете обнаружить случаи, когда eval не изменяет конкретную переменную и позволяет автоматически исключать ее из псевдонима (например, Math в этом случае не изменяется)
- Вы могли бы дать eval контекст для запуска, передав значения аргументов, которые могут отличаться от окружающего контекста
- Вы можете фиксировать изменения контекста, также возвращая аргументы функции из функции, чтобы вы могли просматривать их вне eval.
Обратите внимание, что использование eval
является особым случаем, поскольку по своей природе он не может быть включен в другую функцию (именно поэтому мы должны сделать eval(safeEval(...))
).
Конечно, выполнение всей этой работы может замедлить ваш код, но есть места, где попадание не имеет значения. Надеюсь, это кому-нибудь поможет. И если кто-нибудь создаст доказательство концепции, я хотел бы увидеть ссылку на него здесь; )