Con ng-bind-html-inseguro eliminado, ¿cómo puedo inyectar HTML?

265

Estoy tratando de usar el $sanitizeproveedor y elng-bind-htm-unsafe directiva para permitir que mi controlador inyecte HTML en un DIV.

Sin embargo, no puedo hacer que funcione.

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

Descubrí que es porque fue eliminado de AngularJS (gracias).

Pero sin ng-bind-html-unsafe, me sale este error:

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

metalaureato
fuente
Hay una solución simple para 1.2.23+, ver post
John Henckel

Respuestas:

123
  1. Debe asegurarse de que sanitize.js esté cargado. Por ejemplo, cárguelo desde https://ajax.googleapis.com/ajax/libs/angularjs/[LAST_VERSIONfont>/angular-sanitize.min.js
  2. necesitas incluir un ngSanitizemódulo en tuapp p. ej .:var app = angular.module('myApp', ['ngSanitize']);
  3. solo necesitas unirte ng-bind-htmlal htmlcontenido original . No es necesario hacer nada más en su controlador. El análisis y la conversión se realizan automáticamente por la ngBindHtmldirectiva. (Lea la How does it worksección sobre esto: $ sce ). Entonces, en su caso <div ng-bind-html="preview_data.preview.embed.html"></div>haría el trabajo.
p.matsinopoulos
fuente
3
Es la opción más limpia para hacerlo de forma segura. Llegó con más dependencias, pero se trata de seguridad, así que no dudes.
Pierre Maoui
Usando esto con iónico 1.0.0-beta.13
jasonflaherty
3
Esto no funciona con algunas etiquetas, como la entrada. Por supuesto, no hay una manera fácil de evitar esto. Muy frustrante
Casey
La forma más común y segura. Prefiera esto si planea usar bind-html en diferentes vistas.
eduardobursa
350

En lugar de declarar una función en su alcance, como lo sugiere Alex, puede convertirla en un filtro simple:

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

Entonces puedes usarlo así:

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

Y aquí hay un ejemplo de trabajo: http://jsfiddle.net/leeroy/6j4Lg/1/

Leeroy Brun
fuente
3
Tengo una pequeña colección de herramientas útiles para angular en github , incluiré este filtro en esas herramientas si no le importa. Esta es, en mi humilde opinión, la mejor solución cuando confías en el html.
Capaj
@Capaj No hay problema, pero si agrega un enlace a esta respuesta, sería muy apreciado. :-) stackoverflow.com/a/21254635
Leeroy Brun
Muy agradable. ¡Esto funciona de maravilla en repeticiones anidadas!
Jelle Verzijden
Esto parece una solución MUCHO mejor que la codificación para cada controlador. ¡Solo un filtro rápido y listo! Lo utilicé repitiendo filas de la tabla, simple como un pastel ... <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

Indicaste que estás usando Angular 1.2.0 ... como uno de los otros comentarios indicados, ng-bind-html-unsafeha quedado en desuso.

En cambio, querrás hacer algo como esto:

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

En su controlador, inyecte el $sceservicio y marque el HTML como "confiable":

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

Tenga en cuenta que querrá usar 1.2.0-rc3 o más reciente. ( Arreglaron un error en rc3 que impedía que los "observadores" funcionaran correctamente en HTML de confianza).

ijprest
fuente
2
Intenté usar lo anterior pero rompe mi código. Parece que debe anteponer '$ scope' antes de la definición de la función; tal vez se "entendió" al mismo tiempo, pero ya no. Lo siguiente debería funcionar:myApp.controller('myCtrl', ['$scope', '$sce', function($scope, $sce) {
Dexygen
44
¡Puedes buscar más información sobre $ sce aquí solo por curiosidad! ;)
genuinefafa
55
Tenga en cuenta que esto probablemente causará un problema de seguridad XSS en su código. Consulte la respuesta que sugiere a ngSanitizecontinuación ( stackoverflow.com/a/25679834/22227 ) para obtener una solución alternativa más segura.
Martin Probst
Por qué es una mala idea: docs.google.com/presentation/d/…
user857990
trustAsHtmlhace lo que dice, confía en cualquier código html entrante, lo que puede resultar en ataques de Cross-Site Scripting (XSS)
Aleksey Solovey
112

Para mí, la solución más simple y flexible es:

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

Y agregue la función a su controlador:

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

No olvide agregar $scea la inicialización de su controlador.

Alex
fuente
Parece más sencillo hacer que el controlador devuelva el html de confianza en $ scope
efectivo el
1
Esto puede arrojar un bucle infinito en $ sce, hacer algo como: $ scope.trusted = {}; $ scope.to_trusted = function (html_code) {return $ scope.trusted [html_code] || ($ scope.trusted [html_code] = $ sce.trustAsHtml (html_code)); };
AO_
1
Cada solución que implica bendecir el HTML como confiable introduce una vulnerabilidad XSS. Consulte la respuesta que sugiere ngSanitize a continuación (stackoverflow.com/a/25679834/22227) para obtener una solución más segura.
Michele Spagnuolo
65

La mejor solución para esto en mi opinión es esta:

  1. Cree un filtro personalizado que pueda estar en un archivo common.module.js, por ejemplo, utilizado en toda su aplicación:

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

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

Ahora, no veo por qué la directiva ng-bind-htmlnotrustAsHtml forma parte de su función, me parece un poco tonto que no

De todos modos, así es como lo hago, el 67% de las veces funciona siempre.

Pablo
fuente
Puede usar la siguiente expresión regular para buscar y reemplazar: expresión regular: ng-bind-html-unsafe = "((? :( ?!").) *) "Reemplazo: ng-bind-html =" ($ 1) El | html "con el filtro anterior.
George Donev
2
Cada solución que implica bendecir el HTML como confiable introduce una vulnerabilidad XSS. Consulte la respuesta que sugiere ngSanitize a continuación (stackoverflow.com/a/25679834/22227) para obtener una solución más segura.
Michele Spagnuolo
7

Puede crear su propio enlace html inseguro simple, por supuesto, si utiliza la entrada del usuario, podría ser un riesgo de seguridad.

App.directive('simpleHtml', function() {
  return function(scope, element, attr) {
    scope.$watch(attr.simpleHtml, function (value) {
      element.html(scope.$eval(attr.simpleHtml));
    })
  };
})
Jason Goemaat
fuente
¿No podría esta directiva usar también el $sce.trustAsHtml?
kontur
5

No necesita usar {{}} dentro de ng-bind-html-inseguro:

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

Aquí hay un ejemplo: http://plnkr.co/edit/R7JmGIo4xcJoBc1v4iki?p=preview

El operador {{}} es esencialmente una abreviatura de ng-bind, por lo que lo que estaba intentando equivale a un enlace dentro de un enlace, que no funciona.

ksimons
fuente
Sin embargo, si lo elimino, no me inyectan nada. Y los documentos son muy confusos, usando un solo} docs-angularjs-org-dev.appspot.com/api/…
metalaureate
Muy raro. Lo acabo de probar para estar seguro y para mí funcionó como se esperaba. Estoy de acuerdo en que los simples {} son un poco confusos en los documentos, pero están destinados a ser una representación de una expresión, no como literales en la cadena. He actualizado mi respuesta con un golpe de trabajo.
ksimons
Además, si ya está utilizando 1.2.0, vea los comentarios aquí ya que ng-bind-html-inseguro se ha eliminado: docs.angularjs.org/api/ng.directive:ngBindHtml
ksimons
2
Estoy usando 1.2. :( Grrr! ¿Cómo se puede inyectar HTML inseguro? Me sale este error sin él: errors.angularjs.org/undefined/$sce/unsafe
metalaureate
El {{}}operador estaba causando mi problema con el error de enlace, ¡gracias por la pista!
Campbeln
2

He tenido un problema similar Todavía no pude obtener contenido de mis archivos de descuento alojados en github.

Después de configurar una lista blanca (con dominio github agregado) al $ sceDelegateProvider en app.js, funcionó de maravilla.

Descripción: uso de una lista blanca en lugar de ajustar como confiable si carga contenido de diferentes URL.

Documentos: $ sceDelegateProvider y ngInclude (para buscar, compilar e incluir fragmentos HTML externos)

Lahmizzar
fuente
2

Escape contextual estricto se puede deshabilitar por completo, lo que le permite inyectar html usando ng-html-bind. Esta es una opción insegura, pero útil cuando se realizan pruebas.

Ejemplo de la documentación de AngularJS sobre$sce :

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

Adjuntar la sección de configuración anterior a su aplicación le permitirá inyectar html ng-html-bind, pero como señala el documento:

SCE le brinda muchos beneficios de seguridad por poca sobrecarga de codificación. Será mucho más difícil tomar una aplicación deshabilitada de SCE y asegurarla por su cuenta o habilitar SCE en una etapa posterior. Puede tener sentido deshabilitar SCE para los casos en que tiene mucho código existente que se escribió antes de que se introdujera SCE y está migrando un módulo a la vez.

Sean Fahey
fuente
Es bueno saberlo, pero definitivamente es algo que debe manejarse con cuidado.
iconoclasta
2

Puedes usar filtros como este

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

uso

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

se puede usar para otros tipos de recursos, por ejemplo, el enlace de origen para iframes y otros tipos declarados aquí

BotanMan
fuente