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


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.

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/


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).


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.


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.


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

¿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.


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)


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.


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í

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.