Поясните, пожалуйста, зачем выкладывать «расковырянную» версию и почему то, что лежит сейчас на github нереальные исходники? )
Исходники — предпочтительная для внесения изменений форма программы. Вам же самому удобнее вносить изменения в «расковыренную» версию, а эту вы собираете (или я не так понял?). Остальные люди тоже обычно не любят ковырять файлы на 10 тысяч строк, а разбивают на более мелкие куски.
Следовательно, исходники — именно «расковырянная» версия.
Ещё замечание: у вас в единственном файле исходника количество строчек почти дошло до 10 тысяч (9820).
Наверное, надо что-то разбить на более мелкие файлы и затем собирать их в один.
И да — даже глобальная галочка будет являться проблемой для новичков, если экранирование будет по умолчанию выключено.
В допущении, что фреймворк станет популярным — появятся люди, которые будут забывать её включать в своём проекте и будут наступать на грабли.
Поэтому, пожалуйста, сделайте подстановку значений в шаблон безопасной из коробки =).
Кроме того, вы легко можете это и предотвратить средствами шаблонизатора, добавив обработчик к соответствующей модели.
Неверно (если речь действительно про конкретную модель, а не про включение глобального флага «экранировать всё везде»).
Так можно предотвратить только частный случай, но это не решает проблемы в целом — рано или поздно у вас в проекте окажется какая-то модель, где вы забыли поставить условную галочку «убрать xss» (как в этом примере).
Это та же самая причина, по которой никогда не стоит использовать ручную конкатенацию для построения SQL запросов — люди ошибаются, и в проекте больше хелловорлда у вас с достаточно большой вероятностью будет уязвимость.
Категорично — именно поэтому. Для реальных проектов это нельзя использовать как минимум пока не будет исправлена эта проблема (выше я написал, почему). «На данный момент» — потому что я всё-таки надеюсь, что вы проблему исправите =).
А по поводу архитектуры — в таких случая можно сделать opt-out из автоматического экранирования, например по коду шаблона или по типу передаваемой переменной (по-разному делают).
вне strict mode бросит исключение на втором console.log, а в strict mode — на первом.
Вы мне написали, что он выводит два раза 10, и сказали что я пытаюсь вас ввести в заблуждение:
Во-вторых, думаете, что я не проверю ваш код
Очевидно, вы не ожидаете увидеть там исключения. На самом деле — оно там есть, проверьте ещё раз.
Скорее всего, вы неправильно что-то сделали, когда проверяли первый раз (например, заранее объявили глобальный y равный 10) — отсюда и неверные выводы. Попробуйте назвать переменную yyy, например.
Я сказал, что поведение вас удивляет ровно потому, что вы не согласились с копипастой из командрой строки, решили, что я вас ввожу в заблуждение, и показали мне свой результат неправильной проверки с заверениями, что так и должно быть. Так как поведение вас удивляет — у вас неверное понимание того, как это работает.
var z = 20;
function x() {
z = 10;
eval('var z');
console.log(z);
}
x();
console.log(z);
Угадаете, что будет?
Это, кстати, пример того, почему eval нельзя считать полностью равноценным вставке кода в тело функции — вызов eval изменил привязку (примечание для всех: пожалуйста, не делайте так в реальном коде).
Во-первых, вы не ответили на вопрос, в чём вы выполняете код, что он даёт такие результаты, как у вас выше. Или вы в этом всё-таки ошиблись?
Во-вторых, в вашем примере var x = new Function(тыры-пыры); вообще не выполняет код внутри функции, как несложно увидеть. Пока мы её не вызовем, конечно. Не верите — напишите там console.log, что ли. Не верите в console.log — напишите там долгий цикл.
Во-третьих, я советую вам разобрать именно по шагам все приведённые примеры, и понять, что вы ожидаете в них получить следуя вашей логике. Как минимум в одном случае вы уже явно удивились результату — когда сказали «думаете, что я не проверю ваш код».
Как видно из примера, eval наследует текущий режим strict mode, а new Function — нет.
Ещё раз — eval и new Function не одинаковые, они имеют разное влияние на окружение, они выполняются в разных режимах, они наследуют разные области видимости.
В чём выполняете, если не секрет? Я не могу воспроизвести такого поведения, как у вас, независимо от браузера или режима. Вы точно очистили окружение после предыдущей команды (в которой вы задали глобальный y в 10)?
Поведение eval действительно зависит от режима, и в strict mode он ведёт себя несколько не так — объявленные в нём переменные не добавляются в окружающий контекст. Но и совсем не так, как вы показали. И это не решает всех его проблем.
Зависимость поведения eval от strict mode — ещё один повод не использовать eval, кстати говоря.
Когда это eval стал наследовать текущую область видимости? Он использует глобальную область.
> var x; (function() { var x; eval('x=10'); console.log(x)})(); console.log(x);
10
undefined
x в какой области поменялся? В текущей (той, из которой был вызван). А вы сказали — в глобальной.
> (function() { eval('var y=10;'); console.log(y)})(); console.log(y);
10
ReferenceError: y is not defined
y объявился в какой области видимости? В текущей (той, из которой был вызван). А вы сказали — в глобальной. И это явно не просто использование переменной, на которое вы ссылаетесь тут:
new Function отличается от eval только тем, что он не может использовать переменные из области видимости, в которой он был вызван.
И да, то, что через eval можно сэмулировать поведениеnew Function — верно: засунув туда new Function, например. Но я не вижу никаких разумных причин вызывать eval вместо new Function — используя new Function, вы можете быть уверены, что у вас не захватится текущая область видимости, без дополнительных костылей.
Плюс не забывайте про оптимизации — eval всегда вызывает деоптимизацию функции, которая его содержит (угадайте, почему).
Читайте внимательнее — задания будут раздаваться партнёрами (коих несколько сотен) и фраза «например, нужно будет закачать приложение или написать положительный комментарий на сайте отзывов» присутствует в статье.
Даже если приложение самого оператора будет нормальным, партнёры смогут попросить загрузить что угодно.
Знаете, а я мог ошибиться с процентами — это стоит перепроверить на более адекватном бенчмарке.
Сейчас посмотрел ещё раз — разброс сам по себе очень большой, хоть он и говорит о том, что точность ±1-2%.
Выделение нагруженной части в нативный аддон автоматически выигрыша в скорости не приносит — его надо ещё тщательно оптимизировать, чтобы оказаться быстрее JITа. При этом ошибки в нативном аддоне могут обойтись дороже, из-за ручной работы с памятью.
На тестовых задачах с числодробилками — да, возможно. Но в реальной жизни такое случается не так часто, обычно время уходит не на алгоритмы, стоящие за логикой работы сервера.
Другое дело — может быть полезной выделение какой-то части в асинхронную нить, но этого можно добиться и не выходя из JS.
И да, стоимость переписывания на нативный код и поддержки нативного аддона в человеко-часах в большинстве случаев будет больше, чем стоимость сэкономленных ресурсов. Кроме случаев очень больших компаний со множеством серверов (Facebook, вон, предпочёл форкнуть PHP). Если можно добавить в код волшебный костыль для ускорения работы какого-то нагруженного места на порядок и забыть про это — почему бы и нет. Переписывать всё на нативном — зачем?
В целом — в большей части случаев не стоит связываться, а когда стоит — вы в этом уже точно будете уверены и перепробуете все остальные способы.
Исходники — предпочтительная для внесения изменений форма программы. Вам же самому удобнее вносить изменения в «расковыренную» версию, а эту вы собираете (или я не так понял?). Остальные люди тоже обычно не любят ковырять файлы на 10 тысяч строк, а разбивают на более мелкие куски.
Следовательно, исходники — именно «расковырянная» версия.
Edit: промазал с ответом, извините. Переношу на нужный уровень.
Ну так выложите на гитхаб реальные исходники и скрипт для сборки из них тогда =).
Ещё замечание: у вас в единственном файле исходника количество строчек почти дошло до 10 тысяч (9820).
Наверное, надо что-то разбить на более мелкие файлы и затем собирать их в один.
Если вы про https://github.com/DmitryAstafyev/Patterns/commit/3cdd1ba89, то этого будет недостаточно — вы экранируете только
<
и>
.Ничто не мешает
<input value="{{value}}" />
превратиться в<input value="" onmouseover="…">
, если я правильно понимаю.И ещё — этот коммит сломал поля ввода: когда я тут в поле набираю
<3
и убираю фокус, видимое содержимое поля превращается в<3
.Вы точно хорошо подумали над архитектурой?
И да — даже глобальная галочка будет являться проблемой для новичков, если экранирование будет по умолчанию выключено.
В допущении, что фреймворк станет популярным — появятся люди, которые будут забывать её включать в своём проекте и будут наступать на грабли.
Поэтому, пожалуйста, сделайте подстановку значений в шаблон безопасной из коробки =).
Неверно (если речь действительно про конкретную модель, а не про включение глобального флага «экранировать всё везде»).
Так можно предотвратить только частный случай, но это не решает проблемы в целом — рано или поздно у вас в проекте окажется какая-то модель, где вы забыли поставить условную галочку «убрать xss» (как в этом примере).
Это та же самая причина, по которой никогда не стоит использовать ручную конкатенацию для построения SQL запросов — люди ошибаются, и в проекте больше хелловорлда у вас с достаточно большой вероятностью будет уязвимость.
Категорично — именно поэтому. Для реальных проектов это нельзя использовать как минимум пока не будет исправлена эта проблема (выше я написал, почему). «На данный момент» — потому что я всё-таки надеюсь, что вы проблему исправите =).
А по поводу архитектуры — в таких случая можно сделать opt-out из автоматического экранирования, например по коду шаблона или по типу передаваемой переменной (по-разному делают).
Извините, но это всё, что надо знать о вашем шаблонизаторе на данный момент.
Переделывайте архитектуру — все подставляемые переменные должны экранироваться по умолчанию, как минимум.
Так. Давайте заново. Я утверждаю, что этот код в условии чистого окружения (в котором не было заранее объявлено переменной
y
):вне strict mode бросит исключение на втором
console.log
, а в strict mode — на первом.Вы мне написали, что он выводит два раза
10
, и сказали что я пытаюсь вас ввести в заблуждение:Очевидно, вы не ожидаете увидеть там исключения. На самом деле — оно там есть, проверьте ещё раз.
Скорее всего, вы неправильно что-то сделали, когда проверяли первый раз (например, заранее объявили глобальный
y
равный 10) — отсюда и неверные выводы. Попробуйте назвать переменнуюyyy
, например.Я сказал, что поведение вас удивляет ровно потому, что вы не согласились с копипастой из командрой строки, решили, что я вас ввожу в заблуждение, и показали мне свой результат неправильной проверки с заверениями, что так и должно быть. Так как поведение вас удивляет — у вас неверное понимание того, как это работает.
Вот вам ещё пример с
eval
, для размышлений:Угадаете, что будет?
Это, кстати, пример того, почему eval нельзя считать полностью равноценным вставке кода в тело функции — вызов
eval
изменил привязку (примечание для всех: пожалуйста, не делайте так в реальном коде).Во-первых, вы не ответили на вопрос, в чём вы выполняете код, что он даёт такие результаты, как у вас выше. Или вы в этом всё-таки ошиблись?
Во-вторых, в вашем примере
var x = new Function(тыры-пыры);
вообще не выполняет код внутри функции, как несложно увидеть. Пока мы её не вызовем, конечно. Не верите — напишите тамconsole.log
, что ли. Не верите вconsole.log
— напишите там долгий цикл.Во-третьих, я советую вам разобрать именно по шагам все приведённые примеры, и понять, что вы ожидаете в них получить следуя вашей логике. Как минимум в одном случае вы уже явно удивились результату — когда сказали «думаете, что я не проверю ваш код».
Вот вам ещё один пример, с режимами, кстати:
выдаёт
Как видно из примера,
eval
наследует текущий режим strict mode, аnew Function
— нет.Ещё раз —
eval
иnew Function
не одинаковые, они имеют разное влияние на окружение, они выполняются в разных режимах, они наследуют разные области видимости.В чём выполняете, если не секрет? Я не могу воспроизвести такого поведения, как у вас, независимо от браузера или режима. Вы точно очистили окружение после предыдущей команды (в которой вы задали глобальный
y
в10
)?Поведение
eval
действительно зависит от режима, и в strict mode он ведёт себя несколько не так — объявленные в нём переменные не добавляются в окружающий контекст. Но и совсем не так, как вы показали. И это не решает всех его проблем.Зависимость поведения
eval
от strict mode — ещё один повод не использоватьeval
, кстати говоря.x
в какой области поменялся? В текущей (той, из которой был вызван). А вы сказали — в глобальной.y
объявился в какой области видимости? В текущей (той, из которой был вызван). А вы сказали — в глобальной. И это явно не просто использование переменной, на которое вы ссылаетесь тут:И да, то, что через eval можно сэмулировать поведение
new Function
— верно: засунув тудаnew Function
, например. Но я не вижу никаких разумных причин вызыватьeval
вместоnew Function
— используяnew Function
, вы можете быть уверены, что у вас не захватится текущая область видимости, без дополнительных костылей.Плюс не забывайте про оптимизации —
eval
всегда вызывает деоптимизацию функции, которая его содержит (угадайте, почему).И да, см. http://www.ecma-international.org/ecma-262/6.0/#sec-eval-x и http://www.ecma-international.org/ecma-262/6.0/#sec-function-constructor.
Читайте внимательнее — задания будут раздаваться партнёрами (коих несколько сотен) и фраза «например, нужно будет закачать приложение или написать положительный комментарий на сайте отзывов» присутствует в статье.
Даже если приложение самого оператора будет нормальным, партнёры смогут попросить загрузить что угодно.
Кстати, да. В галереях название картины обычно вешается рядом на не особо приметной табличке, к которой можно подойти и посмотреть, если надо.
Но никак не в четверть самой картины по размеру.
Знаете, а я мог ошибиться с процентами — это стоит перепроверить на более адекватном бенчмарке.
Сейчас посмотрел ещё раз — разброс сам по себе очень большой, хоть он и говорит о том, что точность ±1-2%.
На всякий случай: я — не автор поста.
Его приняли уже. И он есть в вебките (что в следующем сафари) из коробки и в v8 за флагом.
Выделение нагруженной части в нативный аддон автоматически выигрыша в скорости не приносит — его надо ещё тщательно оптимизировать, чтобы оказаться быстрее JITа. При этом ошибки в нативном аддоне могут обойтись дороже, из-за ручной работы с памятью.
На тестовых задачах с числодробилками — да, возможно. Но в реальной жизни такое случается не так часто, обычно время уходит не на алгоритмы, стоящие за логикой работы сервера.
Другое дело — может быть полезной выделение какой-то части в асинхронную нить, но этого можно добиться и не выходя из JS.
И да, стоимость переписывания на нативный код и поддержки нативного аддона в человеко-часах в большинстве случаев будет больше, чем стоимость сэкономленных ресурсов. Кроме случаев очень больших компаний со множеством серверов (Facebook, вон, предпочёл форкнуть PHP). Если можно добавить в код волшебный костыль для ускорения работы какого-то нагруженного места на порядок и забыть про это — почему бы и нет. Переписывать всё на нативном — зачем?
В целом — в большей части случаев не стоит связываться, а когда стоит — вы в этом уже точно будете уверены и перепробуете все остальные способы.