Com o ng-bind-html-unsafe removido, como injeto HTML?


265

Estou tentando usar o $sanitizeprovedor e a ng-bind-htm-unsafediretiva para permitir que meu controlador injete HTML em um DIV.

No entanto, não consigo fazê-lo funcionar.

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

Eu descobri que é porque foi removido do AngularJS (obrigado).

Mas sem ng-bind-html-unsafe, eu recebo este erro:

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


Existe uma solução simples para a versão 1.2.23+, veja post
— John Henckel

Respostas:


123
  1. Você precisa garantir que o sanitize.js esteja carregado. Por exemplo, carregue-o em https://ajax.googleapis.com/ajax/libs/angularjs/[LAST_VERSION}/angular-sanitize.min.js
  2. você precisa incluir o ngSanitizemódulo no seu app exemplo:var app = angular.module('myApp', ['ngSanitize']);
  3. você só precisa vincular com ng-bind-htmlo htmlconteúdo original . Não há necessidade de fazer mais nada no seu controlador. A análise e conversão são feitas automaticamente pela ngBindHtmldiretiva. (Leia a How does it workseção sobre isso: $ sce ). Então, no seu caso <div ng-bind-html="preview_data.preview.embed.html"></div>, faria o trabalho.

3
É a opção mais limpa para fazer isso com segurança. Ele veio com mais dependências, mas é sobre segurança, então não hesite!
— Pierre Maoui

Usando esta com iônica 1.0.0-beta.13
— jasonflaherty

3
Isso não funciona com algumas tags, como entrada. Claro que não há uma maneira fácil de contornar isso. Realmente frustrante.
— Casey #

Maneira mais comum e segura. Prefira isso se você planeja usar o bind-html em diferentes visualizações.
— Eduardobursa

350

Em vez de declarar uma função no seu escopo, conforme sugerido por Alex, você pode convertê-la em um filtro simples:

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

Então você pode usá-lo assim:

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

E aqui está um exemplo de trabalho: http://jsfiddle.net/leeroy/6j4Lg/1/


3
Eu tenho uma pequena coleção de ferramentas úteis para angular no github , incluirei esse filtro nessas ferramentas, se você não se importar. Esta é IMHO a melhor solução quando você confia no html.
— Capaj

@Capaj Não tem problema, mas se você adicionar um link para esta resposta, isso seria muito apreciado. :-) stackoverflow.com/a/21254635 #
— Leeroy Brun

Muito agradável. isso funciona como um encanto em repetições aninhadas!
— Jelle Verzijden

Parece uma solução MUITO melhor do que a codificação para cada controlador. Apenas um filtro rápido e pronto! Usei-o com repetição de linhas da tabela, simples como torta .... <td ng-bind-html="representative.primary | to_trusted"></td>
— Phil Nicholas

2
angular.module ('myApp'). filter ('trustAsHtml', ['$ sce', função ($ sce) {return $ sce.trustAsHtml}]);
— Bradw2k 11/11/2015

275

Você indicou que está usando o Angular 1.2.0 ... como um dos outros comentários indicados, ng-bind-html-unsafefoi preterido.

Em vez disso, você deve fazer algo assim:

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

No seu controlador, injete o $sceserviço e marque o HTML como "confiável":

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

Observe que você deseja usar o 1.2.0-rc3 ou mais recente. (Eles corrigiram um bug no rc3 que impedia que "observadores" funcionassem corretamente em HTML confiável.)


2
Eu tentei usar o acima, mas ele quebra meu código. Parece que você precisa acrescentar '$ scope' antes da definição da função - talvez tenha sido "entendida" de uma vez, mas não mais. O seguinte deve funcionar:myApp.controller('myCtrl', ['$scope', '$sce', function($scope, $sce) {
— Dexygen

4
Você pode procurar mais informações sobre $ sce aqui apenas para buscar curiosidade! ;)
— genuinefafa

5
Observe que isso provavelmente causará um problema de segurança XSS no seu código. Veja a resposta sugerida ngSanitizeabaixo ( stackoverflow.com/a/25679834/22227 ) para uma solução alternativa e mais segura.
— Martin Probst

Por que essa é uma péssima idéia: docs.google.com/presentation/d/…
— user857990

trustAsHtmlfaz o que diz, ele confia em qualquer código de entrada html, o que pode resultar em Scripting (XSS) ataques Cross-Site
— Aleksey Solovey

112

Para mim, a solução mais simples e flexível é:

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

E adicione função ao seu controlador:

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

Não se esqueça de adicionar $sceà inicialização do seu controlador.


Parece mais simples de ter o controlador devolveu o html confiança em $ âmbito
— meffect

1
Isso pode gerar loop infinito em $ sce, faça 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
Toda solução que envolve abençoar o HTML como confiável apresenta uma vulnerabilidade XSS. Consulte a resposta sugerindo ngSanitize abaixo (stackoverflow.com/a/25679834/22227) para uma solução mais segura.
— Michele Spagnuolo 22/02

65

A melhor solução para isso, na minha opinião, é esta:

  1. Crie um filtro personalizado que possa estar em um arquivo common.module.js, por exemplo - usado em seu aplicativo:

    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>

Agora - não vejo por que a diretiva ng-bind-htmlnão faz trustAsHtmlparte de sua função - me parece um pouco tolo que não

Enfim - é assim que eu faço - 67% das vezes, funciona sempre.


Você pode usar o seguinte regex para localizar e substituir: regex: ng-bind-html-unsafe = "((? :( ?!").) *) "Substituição: ng-bind-html =" ($ 1) | html "com o filtro acima.
— George Donev 23/12/15

2
Toda solução que envolve abençoar o HTML como confiável apresenta uma vulnerabilidade XSS. Consulte a resposta sugerindo ngSanitize abaixo (stackoverflow.com/a/25679834/22227) para uma solução mais segura.
— Michele Spagnuolo 22/02

7

Você pode criar sua própria ligação html insegura simples, é claro, se você usar a entrada do usuário, isso pode ser um risco à segurança.

App.directive('simpleHtml', function() {
  return function(scope, element, attr) {
    scope.$watch(attr.simpleHtml, function (value) {
      element.html(scope.$eval(attr.simpleHtml));
    })
  };
})

Esta diretiva não poderia também usar o $sce.trustAsHtml?
— kontur

5

Você não precisa usar {{}} dentro do ng-bind-html-unsafe:

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

Aqui está um exemplo: http://plnkr.co/edit/R7JmGIo4xcJoBc1v4iki?p=preview

O operador {{}} é essencialmente apenas uma abreviação para ng-bind, então o que você estava tentando equivale a uma ligação dentro de uma ligação, o que não funciona.


No entanto, se eu removê-lo, não recebo nada injetado. E os documentos são altamente confusos, usando um único} docs-angularjs-org-dev.appspot.com/api/…
— metalaureate

Muito estranho. Acabei de testá-lo para ter certeza e, para mim, funcionou como esperado. Eu concordo que o single {} seja um pouco confuso nos documentos, mas eles são feitos como uma representação de uma expressão, não como literais na string. Eu atualizei minha resposta com uma força de trabalho.
— ksimons

Além disso, se você já estiver usando o 1.2.0, veja os comentários aqui como ng-bind-html-unsafe foi removido: docs.angularjs.org/api/ng.directive:ngBindHtml
— ksimons

2
Estou usando o 1.2. :( Grrr! Como injetar HTML inseguro? Eu recebo esse erro sem ele: errors.angularjs.org/undefined/$sce/unsafe
— metalaureate

O {{}}operador estava causando meu problema com a ligação falha, obrigado pela dica!
— Campbeln

2

Eu tive um problema semelhante. Ainda não foi possível obter o conteúdo dos meus arquivos de remarcação hospedados no github.

Depois de configurar uma lista de permissões (com o domínio github adicionado) no $ sceDelegateProvider no app.js, funcionou como um encanto.

Descrição: use uma lista de permissões em vez de agrupar como confiável se você carregar conteúdo de URLs diferentes.

Docs: $ sceDelegateProvider e ngInclude (para buscar, compilar e incluir fragmento HTML externo)


2

O escape contextual estrito pode ser totalmente desativado, permitindo que você injete html usando ng-html-bind. Essa é uma opção insegura, mas útil ao testar.

Exemplo da documentação$sce do AngularJS sobre :

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

Anexar a seção de configuração acima ao seu aplicativo permitirá que você injete html ng-html-bind, mas como o documento observa:

O SCE oferece muitos benefícios de segurança por pouca sobrecarga de codificação. Será muito mais difícil usar um aplicativo desativado do SCE e protegê-lo por conta própria ou habilitar o SCE posteriormente. Pode fazer sentido desabilitar o SCE nos casos em que você tem muito código existente que foi gravado antes da introdução do SCE e você está migrando um módulo por vez.


É bom saber, mas definitivamente algo que deve ser tratado com cuidado.
— Iconoclast

2

Você pode usar filtro 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>

pode ser usado para outros tipos de recursos, por exemplo, link de origem para iframes e outros tipos declarados aqui

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.