#javascript #ajax #eval
#javascript #ajax #оценка
Вопрос:
Допустим, я получаю ответ на запрос о загрузке данных AJAX с использованием сочетания JavaScript и HTML, например:
<script>window.alert('Hello World!');</script>
<p>This is a paragraph. Lorem ipsum dolor sit amet...</p>
Если я просто помещаю этот ответ в div
или другой контейнер, скрипт не выполняется автоматически. Я знаю, что это можно сделать с помощью eval()
функции (как указано в примере ниже), но eval
это зло, так как я могу сделать это правильно? Примечание: я не использую jQuery.
Ниже приведен пример загрузчика AJAX:
function Load(id,url){
var ajax=new XMLHttpRequest();
ajax.onreadystatechange=function(){
if(ajax.readyState!=4)return;
var obj=document.getElementById(id);
if(!obj)return;
obj.innerHTML=ajax.responseText;
// load any scripts
var s=obj.getElementsByTagName('script');
for(var i=0;i<s.length; i)window.eval(s[i].innerHTML); // <-- bad
}
ajax.open("GET",url,true);
ajax.send(null);
}
Комментарии:
1. В этом случае вам придется перейти на темную сторону, если вы хотите выполнить JavaScript таким образом
2. этот вопрос задавался и на него было получено множество ответов на SO
3. @user85569: Я действительно надеюсь, что это неправда. Я использовал пример загрузчика для тестирования, и он работает. Я просто испытываю забавное чувство, используя
eval
то же самое чувство, которое я испытываю, используяgoto
в c4. @david: Я не смог найти решение, которое сработало бы для меня, но когда я искал, их было много, и большинство использовали jQuery.
5. jQuery с открытым исходным кодом, вы могли бы просто посмотреть, как они это делают.
Ответ №1:
Пожалуйста, обратите внимание, что вы принимаете входные данные от пользователя и запускаете их в контексте скрипта на вашем сайте. Таким образом, скрипт может делать все, на что способен JavaScript, запущенный в вашем браузере / домене (включая кражу файлов cookie, XSS, вредоносное ПО drive-by и т.д.).
Единственное, что вы можете реально сделать, чтобы снизить риски, — это не использовать eval() для пользовательского контента. Я бы предложил рассмотреть следующие альтернативы:
- Используйте iframe в качестве среды для запуска пользовательского скрипта: http://dean.edwards.name/weblog/2006/11/sandbox
- Используйте Caja. Это позволяет веб-сайтам безопасно внедрять веб-приложения DHTML от третьих сторон и обеспечивает эффективное взаимодействие между страницей внедрения и встроенными приложениями. Он использует объектно-ориентированную модель безопасности, позволяющую использовать широкий спектр гибких политик безопасности. http://code.google.com/p/google-caja
Комментарии:
1. Реально, эта функция загружает URL-адреса только в том же домене, поэтому она должна быть надежной … верно? На самом деле, если я правильно понимаю,
XMLHttpRequest
в любом случае не может загружаться с других доменов.2. @steveo225 вокруг eval много шума, если вы знаете, что данные, заслуживающие доверия, которые вы отправляете клиенту, можно использовать eval, подумал, что это может стать немного медленным.
3. Это неправда. Он не загружает «ввод от пользователя» — функция вызывается программистом с URL, который программист ей дал. Файл, на который он ссылается, является статическим файлом JavaScript, обслуживаемым сервером программиста. Нигде нет пользовательского ввода! Таким образом, использовать eval таким образом совершенно безопасно. Когда вы встраиваете скрипт, используя тег script, он также выполняется в глобальной области видимости — здесь нет разницы. Вы не должны вызывать eval для содержимого, которое генерируется пользователем (полностью или частично), Но это совершенно безопасно для любого другого варианта использования.
Ответ №2:
eval не является особенно злым в этом сценарии, он не сильно отличается, скажем, от динамического добавления тега script, который извлекает файл .js и запускает его. Тем не менее, есть и другие варианты, например, вы можете динамически создавать тег script, создавать текстовый узел с содержимым тега script, который вы извлекли, и добавлять его в документ. В отличие от метода innerHTML, который фактически запускает содержимое. Единственное преимущество перед eval, на самом деле, заключается в том, что вы можете получить более значимую трассировку стека и т.д., Если он выходит из строя или содержит синтаксическую ошибку.
var newScriptTag = document.createElement('script');
newScriptTag.appendChild(document.createTextNode(
origScriptTag.innerHTML)
document.body.appendChild(newScriptTag);
Ответ №3:
Я решил это сегодня, поместив свой JavaScript в нижней части HTML-ответа.
У меня был запрос AJAX, который вернул кучу HTML, которая была отображена в виде наложения. Мне нужно было прикрепить событие click к кнопке в возвращенном HTML-ответе / overlay. На обычной странице я бы обернул свой JavaScript в «window.onload» или «$ (document).готово «, чтобы он прикрепил обработчик события к объекту DOM после того, как DOM для нового наложения был отрисован, но поскольку это был ответ AJAX, а не загрузка новой страницы, это событие так и не произошло, браузер так и не выполнил мой JavaScript, мой обработчик событий так и не был прикреплен к элементу DOM, и моя новая часть функциональности не работала. Опять же, я решил свою «проблему с выполнением JavaScript в ответе AJAX», не используя «$ (document).готово» в начале документа, но путем размещения моего JavaScript в конце документа и запуска его после отображения HTML / DOM.