Po usunięciu ng-bind-html-unsafe, jak wstrzyknąć HTML?

265

Próbuję użyć $sanitizedostawcy i ng-bind-htm-unsafedyrektywy, aby umożliwić mojemu kontrolerowi wstrzykiwanie HTML do DIV.

Nie mogę go jednak uruchomić.

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

Odkryłem, że dzieje się tak, ponieważ został usunięty z AngularJS (dzięki).

Ale bez ng-bind-html-unsafetego pojawia się ten błąd:

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

metalaureat
źródło
Istnieje proste rozwiązanie dla wersji 1.2.23+, patrz post
John Henckel,

Odpowiedzi:

123
  1. Musisz się upewnić, że plik sanitize.js jest załadowany. Na przykład załaduj go z https://ajax.googleapis.com/ajax/libs/angularjs/[LAST_VERSION]/angular-sanitize.min.js
  2. musisz dołączyć ngSanitizemoduł na app np .:var app = angular.module('myApp', ['ngSanitize']);
  3. wystarczy powiązać z ng-bind-htmloryginalną htmltreścią. Nie musisz nic więcej robić w kontrolerze. Analiza i konwersja są wykonywane automatycznie przez ngBindHtmldyrektywę. (Przeczytaj How does it worksekcję na ten temat: $ sce ). Więc w twoim przypadku <div ng-bind-html="preview_data.preview.embed.html"></div>wykona pracę.
p.matsinopoulos
źródło
3
Jest to najczystsza opcja, aby zrobić to bezpiecznie. Przyszedł z większą liczbą zależności, ale chodzi o bezpieczeństwo, więc nie wahaj się!
Pierre Maoui,
Używanie tego z jonem 1.0.0-beta.13
jasonflaherty
3
To nie działa z niektórymi tagami, takimi jak input. Oczywiście nie ma łatwego sposobu na obejście tego. Naprawdę frustrujące.
Casey,
Najpopularniejszy i najbezpieczniejszy sposób. Preferuj to, jeśli planujesz używać bind-html w różnych widokach.
eduardobursa
350

Zamiast deklarować funkcję w swoim zakresie, jak sugeruje Alex, możesz przekonwertować ją na prosty filtr:

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

Następnie możesz użyć tego w następujący sposób:

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

A oto działający przykład: http://jsfiddle.net/leeroy/6j4Lg/1/

Leeroy Brun
źródło
3
Mam niewielką kolekcję przydatnych narzędzi do kątowania na github , włączę ten filtr do tych narzędzi, jeśli nie masz nic przeciwko. To jest IMHO najlepsze rozwiązanie, jeśli ufasz HTML.
Capaj,
@Capaj Nie ma problemu, ale jeśli dodasz link do tej odpowiedzi, będzie to bardzo mile widziane. :-) stackoverflow.com/a/21254635
Leeroy Brun
Bardzo dobrze. działa to jak urok na zagnieżdżonych powtórzeniach!
Jelle Verzijden
To wydaje się DUŻO lepsze rozwiązanie niż kodowanie dla każdego kontrolera. Szybki filtr i gotowe! Użyłem go z powtarzającymi się wierszami tabeli, prostymi jak ciasto .... <td ng-bind-html="representative.primary | to_trusted"></td>
Phil Nicholas
2
angular.module ('myApp'). filter ('trustAsHtml', ['$ sce', function ($ sce) {return $ sce.trustAsHtml}]);
bradw2k
275

Wskazałeś, że używasz Angulara 1.2.0 ... ponieważ jeden z pozostałych wskazanych komentarzy ng-bind-html-unsafezostał wycofany.

Zamiast tego będziesz chciał zrobić coś takiego:

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

Wstrzyknij $sceusługę do kontrolera i oznacz HTML jako „zaufany”:

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

Pamiętaj, że będziesz chciał używać wersji 1.2.0-rc3 lub nowszej. (Naprawiono błąd w rc3, który uniemożliwiał „obserwatorom” poprawne działanie na zaufanym HTML.)

ijprest
źródło
2
Próbowałem użyć powyższego, ale psuje mój kod. Wydaje się, że musisz wstawić „$ scope” przed definicją funkcji - być może była ona kiedyś „zrozumiana”, ale już nie. Następujące elementy powinny działać:myApp.controller('myCtrl', ['$scope', '$sce', function($scope, $sce) {
Dexygen
4
Możesz poszukać więcej informacji na temat $ sce tutaj, aby zdobyć ciekawość! ;)
Genuinefafa
5
Pamiętaj, że prawdopodobnie spowoduje to problem bezpieczeństwa XSS w twoim kodzie. Zobacz odpowiedź sugerującą ngSanitizeponiżej ( stackoverflow.com/a/25679834/22227 ), aby uzyskać alternatywną, bezpieczniejszą poprawkę.
Martin Probst
Dlaczego to zły pomysł: docs.google.com/presentation/d/…
user857990
trustAsHtmlrobi to, co mówi, ufa wszelkiemu przychodzącemu kodowi HTML, który może prowadzić do ataków XSS (Cross-Site Scripting)
Aleksey
112

Dla mnie najprostszym i najbardziej elastycznym rozwiązaniem jest:

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

I dodaj funkcję do kontrolera:

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

Nie zapomnij dodać $scedo inicjalizacji kontrolera.

Alex
źródło
Łatwiej wydaje się, aby kontroler zwrócił zaufany HTML w $ scope
meffect
1
Może to rzucić nieskończoną pętlę na $ sce, zrobić coś takiego: $ scope.trusted = {}; $ scope.to_trusted = function (html_code) {return $ scope.trusted [html_code] || ($ scope.trusted [html_code] = $ sce.trustAsHtml (html_code)); };
AO_
1
Każde rozwiązanie, które wymaga błogosławienia HTML jako zaufanego, wprowadza lukę w zabezpieczeniach XSS. Zobacz odpowiedź sugerującą ngSanitize poniżej (stackoverflow.com/a/25679834/22227), aby uzyskać bezpieczniejszą poprawkę.
Michele Spagnuolo
65

Moim zdaniem najlepszym rozwiązaniem tego jest:

  1. Utwórz niestandardowy filtr, który może znajdować się na przykład w pliku common.module.js - używany w Twojej aplikacji:

    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. Stosowanie:

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

Teraz - nie rozumiem, dlaczego dyrektywa ng-bind-htmltego nie robitrustAsHtml wchodzi w skład jej funkcji - wydaje mi się trochę głupia, że ​​tak nie jest

W każdym razie - w ten sposób to robię - 67% czasu, to działa zawsze.

Paweł
źródło
Możesz użyć następującego wyrażenia regularnego, aby znaleźć i zamienić: regex: ng-bind-html-unsafe = "((? :( ?!").) *) "Replace: ng-bind-html =" (1 $) | html ”z powyższym filtrem.
George Donev
2
Każde rozwiązanie, które wymaga błogosławienia HTML jako zaufanego, wprowadza lukę w zabezpieczeniach XSS. Zobacz odpowiedź sugerującą ngSanitize poniżej (stackoverflow.com/a/25679834/22227), aby uzyskać bezpieczniejszą poprawkę.
Michele Spagnuolo
7

Możesz utworzyć własne proste niebezpieczne wiązanie HTML, oczywiście jeśli użyjesz danych wprowadzonych przez użytkownika, może to stanowić zagrożenie bezpieczeństwa.

App.directive('simpleHtml', function() {
  return function(scope, element, attr) {
    scope.$watch(attr.simpleHtml, function (value) {
      element.html(scope.$eval(attr.simpleHtml));
    })
  };
})
Jason Goemaat
źródło
Czy ta dyrektywa nie mogłaby również używać $sce.trustAsHtml?
kontur
5

Nie musisz używać {{}} w ng-bind-html-unsafe:

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

Oto przykład: http://plnkr.co/edit/R7JmGIo4xcJoBc1v4iki?p=preview

Operator {{}} jest w zasadzie tylko skrótem dla ng-bind, więc to, czego próbujesz, sprowadza się do wiązania wewnątrz wiązania, które nie działa.

ksimons
źródło
Jednak jeśli go usunę, nic nie zostanie wstrzyknięte. Dokumenty
metalaureate
Bardzo dziwne. Właśnie to przetestowałem i dla mnie działało zgodnie z oczekiwaniami. Zgadzam się, że singiel {} jest nieco mylący w dokumentach, ale mają one na celu reprezentację wyrażenia, a nie literały w ciągu. Zaktualizowałem swoją odpowiedź działającym działaniem.
ksimons
Ponadto, jeśli używasz już wersji 1.2.0, zobacz komentarze tutaj, ponieważ ng-bind-html-unsafe został usunięty: docs.angularjs.org/api/ng.directive:ngBindHtml
ksimons
2
Używam 1.2. :( Grrr! Jak wstrzyknąć niebezpieczny kod HTML? Dostaję ten błąd bez niego: error.angularjs.org/undefined/$sce/unsafe
metalaureate
{{}}Operator był przyczyną mojego problemu z wiązaniem upadających, dzięki za podpowiedź!
Campbeln
2

Miałem podobny problem. Nadal nie mogłem pobrać treści z moich plików obniżki cen przechowywanych na github.

Po skonfigurowaniu białej listy (z dodaną domeną github) w $ sceDelegateProvider w app.js działało to jak urok.

Opis: używanie białej listy zamiast pakowania jako zaufanego, jeśli ładujesz zawartość z innych adresów URL.

Dokumenty: $ sceDelegateProvider i ngInclude (do pobierania, kompilowania i dołączania zewnętrznego fragmentu HTML)

Lahmizzar
źródło
2

Ścisłe przeskakiwanie kontekstowe można całkowicie wyłączyć, umożliwiając wstrzykiwanie html przy użyciu ng-html-bind. Jest to niebezpieczna opcja, ale pomocna podczas testowania.

Przykład z dokumentacji AngularJS na temat$sce :

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

Dołączenie powyższej sekcji konfiguracji do aplikacji pozwoli ci wstrzyknąć HTML do ng-html-bind, ale jak zauważa dokument:

SCE zapewnia wiele korzyści związanych z bezpieczeństwem przy niewielkim nakładzie kodowania. Znacznie trudniej będzie wziąć wyłączoną aplikację SCE i zabezpieczyć ją samodzielnie lub włączyć SCE na późniejszym etapie. Sensowne może być wyłączenie SCE w przypadkach, gdy masz dużo istniejącego kodu, który został napisany przed wprowadzeniem SCE i migrujesz je jednocześnie moduł.

Sean Fahey
źródło
Warto o tym wiedzieć, ale zdecydowanie należy się z nią obchodzić ostrożnie.
iconoclast
2

Możesz użyć takiego filtra

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 "";
        };
    }
]);

stosowanie

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

może być użyty do innych typów zasobów, na przykład link źródłowy dla ramek iframe i innych typów zadeklarowanych tutaj

BotanMan
źródło