ด้วยการลบ ng-bind-html-unsafe ฉันจะฉีด HTML ได้อย่างไร


265

ฉันพยายามใช้$sanitizeผู้ให้บริการและng-bind-htm-unsafeคำสั่งเพื่อให้ตัวควบคุมของฉันแทรก HTML ลงใน DIV

อย่างไรก็ตามฉันไม่สามารถใช้งานได้

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

ฉันค้นพบว่าเป็นเพราะมันถูกลบออกจาก AngularJS (ขอบคุณ)

แต่ถ้าไม่มีng-bind-html-unsafeฉันจะได้รับข้อผิดพลาดนี้:

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


มีวิธีแก้ปัญหาง่ายๆสำหรับ 1.2.23+ ดูโพสต์
John Henckel

คำตอบ:


123
  1. คุณต้องตรวจสอบให้แน่ใจว่าโหลด sanitize.js แล้ว ตัวอย่างเช่นโหลดจากhttps://ajax.googleapis.com/ajax/libs/angularjs/ [คัดลอกอย่างรวดเร็ว _ ย้อนกลับไปยังด้านบนสุดของหน้า / นาที]
  2. คุณต้องรวมngSanitizeโมดูลไว้กับคุณapp เช่น:var app = angular.module('myApp', ['ngSanitize']);
  3. คุณเพียงแค่ต้องผูกกับเนื้อหาng-bind-htmlต้นฉบับ htmlไม่จำเป็นต้องทำอะไรอย่างอื่นในคอนโทรลเลอร์ของคุณ การแยกและการแปลงจะทำโดยอัตโนมัติโดยngBindHtmlคำสั่ง (อ่านHow does it workหัวข้อนี้: $ sce ) ดังนั้นในกรณีของคุณ<div ng-bind-html="preview_data.preview.embed.html"></div>จะทำงาน

3
มันเป็นตัวเลือกที่สะอาดที่สุดที่จะทำอย่างปลอดภัย มันมาพร้อมกับการพึ่งพามากขึ้น แต่มันเกี่ยวกับความปลอดภัยจึงไม่ลังเล!
Pierre Maoui

ใช้สิ่งนี้กับ ionic 1.0.0-beta.13
jasonflaherty

3
สิ่งนี้ใช้ไม่ได้กับแท็กบางตัวเช่นอินพุต แน่นอนว่าไม่มีวิธีง่าย ๆ ในการหลีกเลี่ยงปัญหานี้ น่าผิดหวังจริงๆ
Casey

วิธีที่พบมากที่สุดและปลอดภัย ต้องการสิ่งนี้หากคุณวางแผนที่จะใช้ bind-html ในมุมมองที่ต่างกัน
eduardobursa

350

แทนที่จะประกาศฟังก์ชั่นในขอบเขตของคุณตามที่ Alex แนะนำคุณสามารถแปลงเป็นตัวกรองอย่างง่าย:

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

จากนั้นคุณสามารถใช้สิ่งนี้:

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

และนี่คือตัวอย่างการทำงาน: http://jsfiddle.net/leeroy/6j4Lg/1/


3
ฉันมีคอลเล็กชั่นเครื่องมือที่มีประโยชน์สำหรับแองกูลาร์บนgithubฉันจะรวมตัวกรองนี้ในเครื่องมือเหล่านั้นหากคุณไม่สนใจ นี่คือ IMHO ทางออกที่ดีที่สุดเมื่อคุณเชื่อถือ html
Capaj

@Capaj ไม่มีปัญหา แต่ถ้าคุณเพิ่มลิงค์ไปยังคำตอบนี้จะได้รับการชื่นชมอย่างมาก :-) stackoverflow.com/a/21254635
Leeroy Brun

ดีมาก. งานนี้มีเสน่ห์เหมือนซ้ำ ๆ ซ้อน ๆ !
Jelle Verzijden

ดูเหมือนว่าจะเป็นทางออกที่ดีกว่าการเข้ารหัสสำหรับคอนโทรลเลอร์แต่ละตัว เพียงแค่ตัวกรองที่รวดเร็วและทำ! ฉันใช้มันด้วยซ้ำแถวตารางที่เรียบง่ายเป็นวงกลม .... <td ng-bind-html="representative.primary | to_trusted"></td>
ฟิลนิโคลัส

2
angular.module ('myApp'). ตัวกรอง ('trustAsHtml', ['$ sce', ฟังก์ชัน ($ sce) {กลับ $ sce.trustAsHtml}]);
bradw2k

275

คุณระบุว่าคุณกำลังใช้ Angular 1.2.0 ... เป็นหนึ่งในความคิดเห็นอื่น ๆ ที่ระบุว่าng-bind-html-unsafeเลิกใช้แล้ว

คุณจะต้องทำสิ่งนี้แทน:

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

ในตัวควบคุมของคุณฉีด$sceบริการและทำเครื่องหมาย HTML เป็น "เชื่อถือได้":

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

โปรดทราบว่าคุณจะต้องใช้ 1.2.0-rc3 หรือใหม่กว่า (พวกเขาแก้ไขข้อผิดพลาดใน rc3 ที่ทำให้ "ผู้เฝ้าดู" ทำงานไม่ถูกต้องบน HTML ที่เชื่อถือได้)


2
ฉันลองใช้ข้างต้น แต่มันทำลายรหัสของฉัน ดูเหมือนว่าคุณต้องผนวก '$ scope' ไว้ก่อนหน้าคำจำกัดความของฟังก์ชั่น - บางทีมันอาจจะ "เข้าใจ" ในคราวเดียว แต่ก็ไม่นาน ต่อไปนี้ควรใช้งานได้:myApp.controller('myCtrl', ['$scope', '$sce', function($scope, $sce) {
Dexygen

4
คุณสามารถดูข้อมูลเพิ่มเติมเกี่ยวกับ $ sce ที่นี่เพียงเพื่อติดตามความอยากรู้! ;)
authenticfafa

5
โปรดทราบว่าสิ่งนี้อาจทำให้เกิดปัญหาความปลอดภัย XSS ในรหัสของคุณ ดูคำตอบที่แนะนำngSanitizeด้านล่าง ( stackoverflow.com/a/25679834/22227 ) สำหรับทางเลือกที่ปลอดภัยกว่า
Martin Probst

เหตุใดจึงเป็นความคิดที่ไม่ดี: docs.google.co.th/presentation/d/…
857990

trustAsHtmlทำในสิ่งที่กล่าวไว้หรือไม่และเชื่อถือรหัส html ใด ๆ ที่เข้ามาซึ่งอาจส่งผลให้เกิดการโจมตี Cross-Site Scripting (XSS)
Aleksey Solovey

112

สำหรับฉันทางออกที่ง่ายและยืดหยุ่นที่สุดคือ:

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

และเพิ่มฟังก์ชั่นให้กับคอนโทรลเลอร์ของคุณ:

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

อย่าลืมเพิ่มลง$sceในการเริ่มต้นของคอนโทรลเลอร์


ดูเหมือนตรงไปตรงมามากกว่าที่จะให้ตัวควบคุมคืนค่า html ที่เชื่อถือได้ในขอบเขต $
meffect

1
สิ่งนี้สามารถส่งการวนซ้ำไม่สิ้นสุดใน $ sce ทำสิ่งที่ต้องการ: $ scope.trusted = {}; $ scope.to_trusted = ฟังก์ชั่น (html_code) {ส่งคืน $ scope.trusted [html_code] || ($ scope.trusted [html_code] = $ sce.trustAsHtml (html_code)); };
AO_

1
ทุกวิธีแก้ปัญหาที่เกี่ยวข้องกับการให้พร HTML ในฐานะที่เชื่อถือได้นั้นจะทำให้เกิดช่องโหว่ XSS โปรดดูคำตอบที่แนะนำ ngSanitize ด้านล่าง (stackoverflow.com/a/25679834/22227) เพื่อการแก้ไขที่ปลอดภัยยิ่งขึ้น
Michele Spagnuolo

65

ทางออกที่ดีที่สุดสำหรับสิ่งนี้ในความคิดของฉันคือ:

  1. สร้างตัวกรองที่กำหนดเองซึ่งสามารถอยู่ในไฟล์ common.module.js ตัวอย่างเช่นใช้ผ่านแอพของคุณ:

    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. การใช้งาน:

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

ตอนนี้ - ฉันไม่เห็นว่าทำไมคำสั่งng-bind-htmlไม่ได้trustAsHtmlเป็นส่วนหนึ่งของฟังก์ชั่นของมัน - ดูเหมือนจะบ้าสำหรับฉันที่มันไม่ได้

อย่างไรก็ตาม - นั่นคือวิธีที่ฉันทำ - 67% ของเวลาใช้งานได้ตลอดเวลา


คุณสามารถใช้ regex ต่อไปนี้เพื่อทำการค้นหาและแทนที่: regex: ng-bind-html-unsafe = "((? :( ?!").) *) "แทน: ng-bind-html =" ($ 1) | html "พร้อมตัวกรองด้านบน
George Donev

2
ทุกวิธีแก้ปัญหาที่เกี่ยวข้องกับการให้พร HTML ในฐานะที่เชื่อถือได้นั้นจะทำให้เกิดช่องโหว่ XSS โปรดดูคำตอบที่แนะนำ ngSanitize ด้านล่าง (stackoverflow.com/a/25679834/22227) เพื่อการแก้ไขที่ปลอดภัยยิ่งขึ้น
Michele Spagnuolo

7

คุณสามารถสร้างการผูก HTML ที่ไม่ปลอดภัยแบบง่ายของคุณเองได้แน่นอนถ้าคุณใช้การป้อนข้อมูลผู้ใช้อาจมีความเสี่ยงด้านความปลอดภัย

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

คำสั่งนี้ไม่สามารถใช้$sce.trustAsHtmlหรือไม่
Kontur

5

คุณไม่จำเป็นต้องใช้ {{}} ภายใน ng-bind-html-unsafe:

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

นี่คือตัวอย่าง: http://plnkr.co/edit/R7JmGIo4xcJoBc1v4iki?p=preview

ตัวดำเนินการ {{}} เป็นเพียงชวเลขสำหรับ ng-bind ดังนั้นสิ่งที่คุณพยายามที่จะรวมเข้าไปในการรวมภายในซึ่งไม่ได้ผล


อย่างไรก็ตามหากฉันลบออกไปฉันจะไม่ได้รับการฉีดยาใด ๆ และเอกสารมีความสับสนสูงโดยใช้} docs-angularjs-org-dev.appspot.com/api/
metalaureate

แปลกมาก. ฉันเพิ่งทดสอบเพื่อให้แน่ใจและสำหรับฉันก็ทำงานได้ตามที่คาดไว้ ฉันยอมรับว่า {} เดียวมีความสับสนเล็กน้อยในเอกสาร แต่พวกเขามีความหมายในฐานะตัวแทนของการแสดงออกไม่ใช่ตัวอักษรในสตริง ฉันได้อัปเดตคำตอบด้วยเสียงทุ้มแล้ว
ksimons

นอกจากนี้หากคุณใช้ 1.2.0 อยู่แล้วให้ดูความคิดเห็นที่นี่ว่า ng-bind-html-unsafe ถูกลบแล้ว: docs.angularjs.org/api/ng.directive:ngBindHtml
ksimons

2
ฉันใช้ 1.2 !? :( ฮึ่มวิธีการหนึ่งที่สามารถฉีดที่ไม่ปลอดภัย HTML ฉันได้รับข้อผิดพลาดนี้โดยไม่ได้: errors.angularjs.org/undefined/$sce/unsafe
metalaureate

{{}}ผู้ประกอบการที่เป็นสาเหตุของปัญหาที่มีผลผูกพันของฉันกับความล้มเหลวขอบคุณสำหรับคำแนะนำ!
Campbeln

2

ฉันมีปัญหาที่คล้ายกัน ยังไม่สามารถรับเนื้อหาจากไฟล์มาร์กอัปของฉันที่โฮสต์บน Github

หลังจากตั้งค่ารายการที่อนุญาต (พร้อมโดเมน github ที่เพิ่ม) ให้กับ $ sceDelegateProvider ใน app.js มันทำงานได้อย่างมีเสน่ห์

คำอธิบาย: การใช้รายการที่อนุญาตแทนการตัดคำที่เชื่อถือได้หากคุณโหลดเนื้อหาจาก URL อื่น

เอกสาร: $ sceDelegateProviderและngInclude (สำหรับการดึงการรวบรวมและการรวมส่วน HTML ภายนอก)


2

การปิดการใช้งานบริบทอย่างเข้มงวดสามารถปิดใช้งานได้ทั้งหมดช่วยให้คุณสามารถใช้ html ng-html-bindได้ นี่เป็นตัวเลือกที่ไม่ปลอดภัย แต่มีประโยชน์เมื่อทำการทดสอบ

ตัวอย่างจากเอกสารประกอบ AngularJS เมื่อ$sce :

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

แนบส่วนการตั้งค่าด้านบนเพื่อ app ของคุณจะช่วยให้คุณสามารถฉีดเข้าไปใน HTML ng-html-bindแต่เป็นข้อสังเกตเอกสาร:

SCE มอบสิทธิประโยชน์ด้านความปลอดภัยมากมายสำหรับค่าใช้จ่ายในการเข้ารหัสเล็กน้อย จะยากกว่ามากหากจะปิดใช้งานแอปพลิเคชัน SCE และอาจทำให้ปลอดภัยด้วยตัวคุณเองหรือเปิดใช้งาน SCE ในภายหลัง มันอาจสมเหตุสมผลที่จะต้องปิดการใช้งาน SCE สำหรับกรณีที่คุณมีรหัสที่มีอยู่จำนวนมากซึ่งเขียนขึ้นก่อนที่ SCE จะเปิดตัวและคุณกำลังโยกย้ายโมดูลในแต่ละครั้ง


เป็นการดีที่จะรู้ แต่สิ่งที่ควรจัดการด้วยความระมัดระวัง
iconoclast

2

คุณสามารถใช้ตัวกรองแบบนี้

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

การใช้

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

สามารถใช้สำหรับทรัพยากรประเภทอื่น ๆ เช่นลิงค์แหล่งข้อมูลสำหรับ iframes และประเภทอื่น ๆ ที่ประกาศไว้ที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.