Почему использование JavaScript-функции eval - плохая идея?

Вот макрос, который я использую для этой цели. Он будет генерировать конструктор из полей и свойств, имеющих частный сеттер.

Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports EnvDTE90a
Imports EnvDTE100
Imports System.Diagnostics
Imports System.Collections.Generic

Public Module Temp

    Sub AddConstructorFromFields()
        DTE.UndoContext.Open("Add constructor from fields")

        Dim classElement As CodeClass, index As Integer
        GetClassAndInsertionIndex(classElement, index)

        Dim constructor As CodeFunction
        constructor = classElement.AddFunction(classElement.Name, vsCMFunction.vsCMFunctionConstructor, vsCMTypeRef.vsCMTypeRefVoid, index, vsCMAccess.vsCMAccessPublic)

        Dim visitedNames As New Dictionary(Of String, String)
        Dim element As CodeElement, parameterPosition As Integer, isFirst As Boolean = True
        For Each element In classElement.Children
            Dim fieldType As String
            Dim fieldName As String
            Dim parameterName As String

            Select Case element.Kind
                Case vsCMElement.vsCMElementVariable
                    Dim field As CodeVariable = CType(element, CodeVariable)
                    fieldType = field.Type.AsString
                    fieldName = field.Name
                    parameterName = field.Name.TrimStart("_".ToCharArray())

                Case vsCMElement.vsCMElementProperty
                    Dim field As CodeProperty = CType(element, CodeProperty)
                    If field.Setter.Access = vsCMAccess.vsCMAccessPrivate Then
                        fieldType = field.Type.AsString
                        fieldName = field.Name
                        parameterName = field.Name.Substring(0, 1).ToLower() + field.Name.Substring(1)
                    End If
            End Select

            If Not String.IsNullOrEmpty(parameterName) And Not visitedNames.ContainsKey(parameterName) Then
                visitedNames.Add(parameterName, parameterName)

                constructor.AddParameter(parameterName, fieldType, parameterPosition)

                Dim endPoint As EditPoint
                endPoint = constructor.EndPoint.CreateEditPoint()
                endPoint.LineUp()
                endPoint.EndOfLine()

                If Not isFirst Then
                    endPoint.Insert(Environment.NewLine)
                Else
                    isFirst = False
                End If

                endPoint.Insert(String.Format(MemberAssignmentFormat(constructor.Language), fieldName, parameterName))

                parameterPosition = parameterPosition + 1
            End If
        Next

        DTE.UndoContext.Close()

        Try
            ' This command fails sometimes '
            DTE.ExecuteCommand("Edit.FormatDocument")
        Catch ex As Exception
        End Try
    End Sub
    Private Sub GetClassAndInsertionIndex(ByRef classElement As CodeClass, ByRef index As Integer, Optional ByVal useStartIndex As Boolean = False)
        Dim selection As TextSelection
        selection = CType(DTE.ActiveDocument.Selection, TextSelection)

        classElement = CType(selection.ActivePoint.CodeElement(vsCMElement.vsCMElementClass), CodeClass)

        Dim childElement As CodeElement
        index = 0
        For Each childElement In classElement.Children
            Dim childOffset As Integer
            childOffset = childElement.GetStartPoint(vsCMPart.vsCMPartWholeWithAttributes).AbsoluteCharOffset
            If selection.ActivePoint.AbsoluteCharOffset < childOffset Or useStartIndex Then
                Exit For
            End If
            index = index + 1
        Next
    End Sub
    Private ReadOnly Property MemberAssignmentFormat(ByVal language As String) As String
        Get
            Select Case language
                Case CodeModelLanguageConstants.vsCMLanguageCSharp
                    Return "this.{0} = {1};"

                Case CodeModelLanguageConstants.vsCMLanguageVB
                    Return "Me.{0} = {1}"

                Case Else
                    Return ""
            End Select
        End Get
    End Property
End Module
507
задан Nisarg 3 March 2018 в 14:03
поделиться

17 ответов

  1. Неправильное использование оценка открывает Ваш код для инжекционных нападений

  2. , Отладка может быть более сложной (никакие номера строки, и т.д.)

  3. , код eval'd выполняется медленнее (никакая возможность компилировать/кэшировать код eval'd)

Редактирование: Как @Jeff Walden указывает в комментариях, № 3 менее верен сегодня, чем это было в 2008. Однако, в то время как некоторое кэширование скомпилированных сценариев может произойти, это будет только ограничено сценариями, которые являются eval'd, повторенным без модификации. Более вероятный сценарий - то, что Вы - eval'ing сценарии, которые подверглись небольшой модификации, каждый раз и как таковой не мог кэшироваться. Позвольте нам просто сказать, что НЕКОТОРЫЙ код eval'd выполняется более медленно.

370
ответ дан Joel Gritter 3 March 2018 в 14:03
поделиться

Это может стать большим количеством проблемы, поскольку следующее поколение браузеров выпускает некоторую разновидность компилятора JavaScript. Код, выполненный через Оценку, не может работать, а также остальная часть Вашего JavaScript против этих более новых браузеров. Кто-то должен сделать некоторое профилирование.

2
ответ дан Brian 3 March 2018 в 14:03
поделиться

Помимо возможных проблем безопасности, если Вы выполняете отправленный пользователями код, большую часть времени существует лучший путь, который не включает перепарсинг кода каждый раз, когда это выполняется. Анонимные функции или свойства объектов могут заменить большую часть использования оценки и намного более безопасны и быстрее.

2
ответ дан Matthew Crumley 3 March 2018 в 14:03
поделиться

Это значительно снижает Ваш уровень уверенности о безопасности.

4
ответ дан David Plumpton 3 March 2018 в 14:03
поделиться

Это не обязательно, что плохо, если Вы знаете, в каком контексте Вы используете его.

, Если Ваше приложение использует eval() для создания объекта из некоторого JSON, который возвратился из XMLHttpRequest к собственному сайту, созданному доверяемым серверным кодом, это - вероятно, не проблема.

Недоверяемый клиентский код JavaScript не может сделать так многого так или иначе. Если вещь, на которой Вы выполняетесь eval(), прибыла из разумного источника, Вы в порядке.

5
ответ дан Gokul Chandrasekaran 3 March 2018 в 14:03
поделиться

Если Вы не на 100% уверены, что оцениваемый код от надежного источника (обычно Ваше собственное приложение) тогда, это - безошибочный способ представить Вашу систему атаке с использованием кросс-сайтовых сценариев.

5
ответ дан John Topley 3 March 2018 в 14:03
поделиться

Если Вы не позволяете оценке () динамический контент (через cgi или вводите), это так же безопасно и твердо как весь другой JavaScript на Вашей странице.

11
ответ дан Thevs 3 March 2018 в 14:03
поделиться

Одна вещь иметь в виду состоит в том, что можно часто использовать оценку () для выполнения кода в иначе ограниченной среде - сайты социальных сетей, что блок, определенные функции JavaScript можно иногда дурачить путем разбивания их в блоке оценки -

eval('al' + 'er' + 't(\'' + 'hi there!' + '\')');

Поэтому, если Вы надеетесь выполнять некоторый код JavaScript, где это не могло бы иначе быть позволено ( Myspace, я смотрю на Вас...) тогда оценка () может быть полезным приемом.

Однако по всем упомянутым выше причинам, Вы не должны использовать его для своего собственного кода, где Вы имеете полный контроль - это просто не необходимо, и богатое пониженный к 'хитрой полке' взломов JavaScript.

13
ответ дан Qix 3 March 2018 в 14:03
поделиться

оценка является не всегда злом. Существуют времена, где это является совершенно соответствующим.

Однако оценка в настоящее время и исторически в широком масштабе злоупотребляется людьми, которые не знают то, что они делают. Это включает людей, пишущих учебные руководства JavaScript, к сожалению, и в некоторых случаях это может действительно иметь последствия безопасности - или, чаще, простые ошибки. Так, чем больше мы можем сделать для броска вопросительного знака по оценке, тем лучше. Любое время Вы используете оценку, Вам нужно к проверке работоспособности, что Вы делаете, потому что возможности - Вы, могло делать его лучший, более безопасный, более чистый путь.

, Чтобы дать слишком типичный пример, выбрать цвет элемента с идентификатором, сохраненным в переменном 'картофеле':

eval('document.' + potato + '.style.color = "red"');

, Если авторы вида кода выше подсказка об основах того, как JavaScript возражает работе, они поймут, что квадратные скобки могут использоваться вместо литеральных точечных имен, устраняя потребность в оценке:

document[potato].style.color = 'red';

..., который намного легче считать, а также менее потенциально ошибочный.

(Но тогда, кто-то, который/really/знал то, что они делали, скажет:

document.getElementById(potato).style.color = 'red';

, который более надежен, чем изворотливый старый прием доступа к элементам DOM прямо из объекта документа.)

343
ответ дан Lipis 3 March 2018 в 14:03
поделиться

Это - вообще только проблема при передаче ввода данных пользователем оценки.

18
ответ дан Mark Biek 3 March 2018 в 14:03
поделиться

Передающий ввод данных пользователем к оценке () является угрозой безопасности, но также и каждый вызов оценки () создает новый экземпляр интерпретатора JavaScript. Это может быть пожирателем ресурсов.

20
ответ дан Andrew Hedges 3 March 2018 в 14:03
поделиться

Главным образом намного более трудно поддержать и отладить. Это похоже goto. Можно использовать его, но это делает его тяжелее для нахождения проблем и тяжелее на людях, которые, возможно, должны внести изменения позже.

15
ответ дан Peter Mortensen 3 March 2018 в 14:03
поделиться

Я полагаю, что это - потому что это может выполнить любую функцию JavaScript от строки. Используя его облегчает для людей вводить код жулика в приложение.

37
ответ дан Peter Mortensen 3 March 2018 в 14:03
поделиться

Две точки приходят на ум:

  1. безопасность (но, пока Вы генерируете строку, которая будет оценена сами, это могло бы быть надуманным вопросом)

  2. Производительность: пока код, который будет выполняться, не неизвестен, он не может быть оптимизирован. (о JavaScript и производительности, конечно представление Steve Yegge )

26
ответ дан xtofl 3 March 2018 в 14:03
поделиться

Это - возможная угроза безопасности, это имеет различный объем выполнения и довольно неэффективно, поскольку это создает совершенно новую среду сценариев для выполнения кода. Посмотрите здесь еще для некоторой информации: оценка .

Это довольно полезно, тем не менее, и используемый с модерированием может добавить большую хорошую функциональность.

6
ответ дан Code Lღver 3 March 2018 в 14:03
поделиться

Сборка "мусора"

сборка "мусора" браузеров понятия не имеет, может ли код, это - eval'ed, быть удален из памяти, таким образом, это просто сохраняет сохраненным, пока страница не перезагружается. Не слишком плохо, если Ваши пользователи находятся только на Вашей странице вскоре, но это может быть проблема для веб-приложения.

Вот сценарий для демонстрации проблемы

https://jsfiddle.net/CynderRnAsh/qux1osnw /

document.getElementById("evalLeak").onclick = (e) => {
  for(let x = 0; x < 100; x++) {
    eval(x.toString());
  }
};

Что-то столь же простое, как вышеупомянутый код заставляет небольшой объем памяти быть хранилищем, пока приложение не умирает. Это хуже, когда evaled сценарий является гигантской функцией и обратился к интервалу.

0
ответ дан 22 November 2019 в 22:29
поделиться

Если вы хотите, чтобы пользователь вводил некоторые логические функции и выполнял операцию И, ИЛИ, тогда функция eval в JavaScript идеально подходит. Я могу принять две строки и eval (uate) string1 === string2 и т. Д.

4
ответ дан 22 November 2019 в 22:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: