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.