Что конкретно представляют опасности eval (parse (...))?
Существует несколько вопросов о том, как избежать использования eval(parse(...))
Что вызывает вопросы:
- Почему конкретно следует избегать
eval(parse())
?
- И самое главное, Каковы опасности?
- Есть ли опасность, если код не используется в производстве? (Я думаю, любая опасность вернуть непредвиденные результаты. Ясно, что если вы не будете осторожны в том, что вы разбираете, у вас будут проблемы. Но разве это опаснее, чем быть неаккуратным с
get()
?)
Ответы
Ответ 1
Большинство аргументов против eval(parse(...))
возникают не из-за проблем с безопасностью, ведь претензии не предъявляются к тому, что R является безопасным интерфейсом для публикации в Интернете, а скорее потому, что такой код обычно выполняет то, что может быть выполнено используя менее неясные методы, то есть методы, которые являются более быстрыми и более человечными. Предполагается, что R-язык является высокоуровневым, поэтому предпочтение cognoscenti (и я не считаю себя в этой группе) заключается в том, чтобы видеть компактный и выразительный код.
Таким образом, опасность состоит в том, что eval(parse(..))
- это бэкдор-метод преодоления недостатка знаний, и надежда на повышение этого барьера заключается в том, что люди улучшат использование языка R. Дверь остается открытой, но надеемся на более выразительное использование других функций. вопрос Carl Witthoft ранее сегодня, не зная, что функция get
доступна, и вопрос который он связал с выявлено непонимание того, как функционировала функция [[
(и как $
была более ограниченной, чем [[
). В обоих случаях можно было бы построить решение eval(parse(..))
, но оно было clunkier и менее понятно, чем альтернатива.
Ответ 2
Проблемы с безопасностью действительно возникают только в том случае, если вы начинаете называть eval для строк, которые другой пользователь вам передал. Это очень важно, если вы создаете приложение, которое запускает R в фоновом режиме, но для анализа данных, в котором вы пишете код, который будет запускаться самостоятельно, тогда вам не нужно беспокоиться о влиянии eval
на безопасность.
Некоторые другие проблемы с eval(parse(
хотя.
Во-первых, код, использующий eval-parse, обычно намного сложнее отлаживать, чем не проанализированный код, что является проблематичным, поскольку программное обеспечение для отладки вдвое сложнее как запись его в первую очередь.
Здесь функция с ошибкой в ней.
std <- function()
{
mean(1to10)
}
Глупый я, я забыл о операторе двоеточия и неправильно создал свой вектор. Если я попытаюсь использовать эту функцию, тогда R замечает проблему и выдает ошибку, указывая на мою ошибку.
Здесь версия eval-parse.
ep <- function()
{
eval(parse(text = "mean(1to10)"))
}
Это будет источник, потому что ошибка внутри допустимой строки. Только позже, когда мы приходим, чтобы запустить код, который вызывается ошибкой. Таким образом, используя eval-parse, мы потеряли возможность проверки исходных ошибок.
Я также думаю, что эту вторую версию функции гораздо труднее прочитать.
Другая проблема с eval-parse заключается в том, что она намного медленнее, чем непосредственно исполняемый код. Сравнить
system.time(for(i in seq_len(1e4)) mean(1:10))
user system elapsed
0.08 0.00 0.07
и
system.time(for(i in seq_len(1e4)) eval(parse(text = "mean(1:10)")))
user system elapsed
1.54 0.14 1.69
Ответ 3
Обычно существует лучший способ "вычисления на языке", чем работа с кодовыми строками; По моему опыту, тяжелый код evalparse требует много надежной защиты, чтобы гарантировать разумную производительность.
Та же задача обычно может быть решена путем непосредственного взаимодействия с R-кодом как языкового объекта; Хэдли Уикхем имеет полезное руководство по метапрограмме в R здесь:
Функция defmacro() в библиотеке gtools - мой любимый заменитель (не предполагаемый R-кадр) для конструкции evalparse
require(gtools)
# both action_to_take & predicate will be subbed with code
F <- defmacro(predicate, action_to_take, expr =
if(predicate) action_to_take)
F(1 != 1, action_to_take = print('arithmetic doesnt work!'))
F(pi > 3, action_to_take = return('good!'))
[1] 'good!'
# the raw code for F
print(F)
function (predicate = stop("predicate not supplied"), action_to_take = stop("action_to_take not supplied"))
{
tmp <- substitute(if (predicate) action_to_take)
eval(tmp, parent.frame())
}
<environment: 0x05ad5d3c>
Преимущество этого метода заключается в том, что вам гарантированно получить синтаксически-правовой R-код. Подробнее об этой полезной функции можно найти здесь:
Надеюсь, что это поможет!
Ответ 4
В некоторых языках программирования eval()
- это функция, которая оценивает строка, как будто это выражение и возвращает результат; в другие, он выполняет несколько строк кода, как если бы они были вместо строки, включая eval. Вход для eval не обязательно строка; в языках, поддерживающих синтаксические абстракции (например, Lisp), вкладка eval будет состоять из абстрактных синтаксических форм. http://en.wikipedia.org/wiki/Eval
Есть все виды эксплойтов, которые можно использовать, если eval используется неправильно.
Злоумышленник может предоставить программу с помощью строки msgstr "session.update(authenticated = True)" в качестве данных, которые будут обновлять чтобы установить аутентифицированный ключ в значение True. К исправлению это, все данные, которые будут использоваться с eval, должны быть экранированы или должен выполняться без доступа к потенциально опасным функциям. http://en.wikipedia.org/wiki/Eval
Другими словами, наибольшая опасность eval()
- это возможность ввода кода в ваше приложение. Использование eval()
также может вызвать проблемы с производительностью на некоторых языках в зависимости от того, для чего используется.
В частности, в R, вероятно, потому, что вы можете использовать get()
вместо eval(parse())
, и ваши результаты будут одинаковыми, не прибегая к eval()