Как удалить HTML, если удалить ng-bind-html-unsafe?

265

Я пытаюсь использовать $sanitizeпровайдера и ng-bind-htm-unsafeдирективу, чтобы позволить моему контроллеру вводить HTML в DIV.

Тем не менее, я не могу заставить его работать.

<div ng-bind-html-unsafe="{{preview_data.preview.embed.html}}"></div>

Я обнаружил, что это потому, что он был удален из AngularJS (спасибо).

Но без ng-bind-html-unsafe, я получаю эту ошибку:

http://errors.angularjs.org/undefined/$sce/unsafe

metalaureate
источник
Есть простое решение для 1.2.23+, см. Пост
Джон Хенкель

Ответы:

123
  1. Вы должны убедиться, что sanitize.js загружен. Например, загрузите его с https://ajax.googleapis.com/ajax/libs/angularjs/[LAST_VERSION]/angular-sanitize.min.js
  2. Вы должны включить ngSanitizeмодуль, app например:var app = angular.module('myApp', ['ngSanitize']);
  3. вам просто нужно связать с ng-bind-htmlоригинальным htmlконтентом. Не нужно ничего делать в вашем контроллере. Разбор и преобразование автоматически выполняется ngBindHtmlдирективой. (Прочтите этот How does it workраздел: $ sce ). Таким образом, в вашем случае <div ng-bind-html="preview_data.preview.embed.html"></div>будет делать работу.
p.matsinopoulos
источник
3
Это самый чистый способ сделать это безопасно. У него было больше зависимостей, но речь идет о безопасности, поэтому не стесняйтесь!
Пьер Мауи
Используя это с ionic 1.0.0-beta.13
jasonflaherty
3
Это не работает с некоторыми тегами, такими как ввод. Конечно, нет простого способа обойти это. Действительно расстраивает.
Кейси
Самый распространенный и безопасный способ. Предпочитайте это, если вы планируете использовать bind-html в разных представлениях.
eduardobursa
350

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

angular.module('myApp')
    .filter('to_trusted', ['$sce', function($sce){
        return function(text) {
            return $sce.trustAsHtml(text);
        };
    }]);

Тогда вы можете использовать это так:

<div ng-bind-html="preview_data.preview.embed.html | to_trusted"></div>

И вот рабочий пример: http://jsfiddle.net/leeroy/6j4Lg/1/

Leeroy Brun
источник
3
У меня есть небольшая коллекция полезных инструментов для angular на github , я включу этот фильтр в эти инструменты, если вы не возражаете. Это ИМХО лучшее решение, когда вы доверяете HTML.
Капай
@Capaj Нет проблем, но если вы добавите ссылку на этот ответ, это будет с благодарностью. :-) stackoverflow.com/a/21254635
Leeroy Brun
Очень хорошо. это работает как шарм на вложенных повторениях!
Jelle Verzijden
Это кажется НАМНОГО лучшим решением, чем кодирование для каждого контроллера. Просто быстрый фильтр и готово! Я использовал это с повторяющимися строками таблицы, просто как пирог ... <td ng-bind-html="representative.primary | to_trusted"></td>
Фил Николас
2
angular.module ('myApp'). filter ('trustAsHtml', ['$ sce', function ($ sce) {return $ sce.trustAsHtml}]));
bradw2k
275

Вы указали, что используете Angular 1.2.0 ..., поскольку один из других указанных комментариев ng-bind-html-unsafeустарел.

Вместо этого вы захотите сделать что-то вроде этого:

<div ng-bind-html="preview_data.preview.embed.htmlSafe"></div>

В вашем контроллере внедрите $sceслужбу и пометьте HTML как «доверенный»:

myApp.controller('myCtrl', ['$scope', '$sce', function($scope, $sce) {
  // ...
  $scope.preview_data.preview.embed.htmlSafe = 
     $sce.trustAsHtml(preview_data.preview.embed.html);
}

Обратите внимание, что вы захотите использовать 1.2.0-rc3 или новее. (Они исправили ошибку в rc3, из-за которой «наблюдатели» не могли корректно работать с доверенным HTML.)

ijprest
источник
2
Я пытался использовать выше, но это нарушает мой код. Кажется, вам нужно добавить предопределение «$ scope» перед определением функции - возможно, это было «понято» за один раз, но не больше. Следующее должно работать:myApp.controller('myCtrl', ['$scope', '$sce', function($scope, $sce) {
Dexygen
4
Вы можете посмотреть больше информации о $ sce здесь, просто чтобы заняться любопытством! ;)
Genuinefafa
5
Обратите внимание, что это может вызвать проблему безопасности XSS в вашем коде. Посмотрите ответ, предлагающий ngSanitizeниже ( stackoverflow.com/a/25679834/22227 ) для альтернативного, более безопасного решения.
Мартин Пробст
Почему это плохая идея: docs.google.com/presentation/d/…
user857990
trustAsHtmlделает то, что говорит, он доверяет любому входящему html-коду, что может привести к атакам межсайтового скриптинга (XSS)
Алексей Соловей
112

Для меня самое простое и гибкое решение:

<div ng-bind-html="to_trusted(preview_data.preview.embed.html)"></div>

И добавьте функцию в свой контроллер:

$scope.to_trusted = function(html_code) {
    return $sce.trustAsHtml(html_code);
}

Не забудьте добавить $sceк инициализации вашего контроллера.

Alex
источник
Кажется более простым, чтобы контроллер возвратил доверенный html в $ scope
эффект
1
Это может создать бесконечный цикл в $ sce, сделать что-то вроде: $ scope.trusted = {}; $ scope.to_trusted = function (html_code) {вернуть $ scope.trusted [html_code] || ($ scope.trusted [html_code] = $ sce.trustAsHtml (html_code)); };
AO_
1
Каждое решение, которое включает в себя благословение HTML как доверенного, представляет собой уязвимость XSS. Пожалуйста, смотрите ответ, предлагающий ngSanitize ниже (stackoverflow.com/a/25679834/22227) для более безопасного решения.
Мишель Спаньуоло
65

На мой взгляд, лучшее решение этого:

  1. Создайте пользовательский фильтр, который может быть, например, в файле common.module.js, который будет использоваться в вашем приложении:

    var app = angular.module('common.module', []);
    
    // html filter (render text as html)
    app.filter('html', ['$sce', function ($sce) { 
        return function (text) {
            return $sce.trustAsHtml(text);
        };    
    }])
  2. Использование:

    <span ng-bind-html="yourDataValue | html"></span>

Теперь - я не понимаю, почему директива ng-bind-htmlнеtrustAsHtml является частью ее функции - мне кажется немного глупым, что она не делает

Во всяком случае - так я и делаю - в 67% случаев это работает всегда.

Павел
источник
Вы можете использовать следующее регулярное выражение для поиска и замены: regex: ng-bind-html-unsafe = "((? :( ?!").) *) "Replace: ng-bind-html =" ($ 1) | html "с вышеуказанным фильтром.
Георгий Донев
2
Каждое решение, которое включает в себя благословение HTML как доверенного, представляет собой уязвимость XSS. Пожалуйста, смотрите ответ, предлагающий ngSanitize ниже (stackoverflow.com/a/25679834/22227) для более безопасного решения.
Мишель Спаньуоло
7

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

App.directive('simpleHtml', function() {
  return function(scope, element, attr) {
    scope.$watch(attr.simpleHtml, function (value) {
      element.html(scope.$eval(attr.simpleHtml));
    })
  };
})
Джейсон Гомаат
источник
Не может ли эта директива также использовать $sce.trustAsHtml?
Контур
5

Вам не нужно использовать {{}} внутри ng-bind-html-unsafe:

<div ng-bind-html-unsafe="preview_data.preview.embed.html"></div>

Вот пример: http://plnkr.co/edit/R7JmGIo4xcJoBc1v4iki?p=preview

Оператор {{}} по сути является просто сокращением для ng-bind, поэтому то, что вы пытались сделать, равнозначно привязке внутри привязки, которая не работает.

ksimons
источник
Однако, если я удаляю это, мне ничего не вводят. И документы высоко запутанным, используя один} docs-angularjs-org-dev.appspot.com/api/...
metalaureate
Очень странно. Я только что проверил это, чтобы быть уверенным, и для меня это работало как ожидалось. Я согласен, что один {} немного запутывает в документах, но они предназначены для представления выражения, а не литералов в строке. Я обновил свой ответ рабочим планом.
ksimons
Также, если вы уже используете 1.2.0, просмотрите комментарии здесь, так как ng-bind-html-unsafe был удален: docs.angularjs.org/api/ng.directive:ngBindHtml
ksimons
2
Я использую 1.2. :( Grrr! Как можно внедрить небезопасный HTML? Я получаю эту ошибку без него: errors.angularjs.org/undefined/$sce/unsafe
метауреат
{{}}Оператор вызывает мой вопрос с обязательным упущением, спасибо за подсказку!
Кэмпбелн
2

У меня была похожая проблема. Все еще не могу получить контент из моих файлов уценки, размещенных на github.

После настройки белого списка (с добавленным доменом github) для $ sceDelegateProvider в app.js он работал как чудо.

Описание: использование белого списка вместо переноса в список доверенных, если вы загружаете контент из других URL-адресов.

Документы: $ sceDelegateProvider и ngInclude (для извлечения, компиляции и включения внешнего HTML-фрагмента)

Lahmizzar
источник
2

Строгое контекстуальное экранирование может быть полностью отключено, что позволяет вводить html с помощью ng-html-bind. Это небезопасный вариант, но полезный при тестировании.

Пример из документации AngularJS по$sce :

angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
  // Completely disable SCE.  For demonstration purposes only!
  // Do not use in new projects.
  $sceProvider.enabled(false);
});

Присоединение приведенного выше раздела конфигурации к вашему приложению позволит вам добавить html ng-html-bind, но, как отмечает документ:

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

Шон Фахи
источник
Полезно знать, но, безусловно, с этим нужно обращаться осторожно.
иконоборчество
2

Вы можете использовать фильтр, как это

angular.module('app').filter('trustAs', ['$sce', 
    function($sce) {
        return function (input, type) {
            if (typeof input === "string") {
                return $sce.trustAs(type || 'html', input);
            }
            console.log("trustAs filter. Error. input isn't a string");
            return "";
        };
    }
]);

использование

<div ng-bind-html="myData | trustAs"></div>

он может использоваться для других типов ресурсов, например, ссылки на источник для iframes и других типов, объявленных здесь

BotanMan
источник