7

我正在客户端使用 Angular (1.2 RC2) 开发一个 CMS 驱动的网站。由于内容来自 CMS,不幸的是,我不得不在 JSON 字符串中使用接收 HTML。大多数 HTML 都被注入并渲染得很好,但是图像标签的 src 被剥离了。从我读过的内容来看,src 应该以“unsafe:”为前缀,如果这是 Angular 中的 XSS 安全问题,则不会完全删除......但我可能弄错了。

我在这个问题上已经有一段时间了,感觉我已经尝试了从合理到完全愚蠢的所有方法。将我的 CMS 网址列入白名单,将所有内容列入白名单,禁用$sce,强制 html通过 $sce.trustAsHtml()等等......到目前为止,还没有运气。由于该网站是由 CMS 驱动的,我很遗憾无法创建一个 plunker / fiddle,但我希望一个善良的灵魂无论如何都会尝试提供帮助。

更新:忘了提到我也试过ng-src,同样的效果。 更新二:如果我使用 HTTPS,src 属性仍然存在并显示图像。这是可以接受的,因为它将在生产环境中在 HTTPS 上运行,但我仍然想知道为什么禁用 $sce 不起作用。

浏览器看到的 HTML(slide.body 的内容)

<div class="row">
    <div class="col-md-6 visible-md visible-lg">
        <img alt="none" class="img-responsive">
    </div>
    <div class="col-xs-12 col-md-6">
        <div class="itx-article-header">
             <h1>Sulvat Quis 1</h1>

             <h2>– Nullam dictum ac enim</h2>

        </div>
        <p>Proin quis justo vel felis varius sodales sit amet ut diam.</p>
    </div>
</div>

玉 (HTML)

.my-carousel(ng-controller='CarouselCtrl')
    carousel(interval='myInterval')
        slide(ng-repeat='slide in slides', active='slide.active')
            .my-carousel-item(ng-bind-html='slide.body')

角度控制器

.controller('CarouselCtrl', ['$sce', 'Article', '$scope',
    function($sce, Article, $scope) {
        $scope.myInterval = -1;
        $scope.slides = Article.query(
            {category: 'carousel'},
            function(data){
                for (var i = 0; i < data.length; i++) {
                    $scope.slides[i].body = $sce.trustAsHtml(data[i].body);                     
                }
            },
            function() {
                // Fail
            });
    }])

示例 JSON 响应(幻灯片) 对不起,宽框,没有设法格式化它。

{
"cmarId": 16,
"corp": {
    "corpId": 2,
    "guiSelected": false
},
"createdAt": "Sep 27, 2013",
"articleTag": "slide-1",
"headline": "Slide 1",
"highlighted": false,
  "body": "\u003cdiv class\u003d\"container my-carousel-container-small\"\u003e\r\n\u003cdiv class\u003d\"row\"\u003e\r\n\u003cdiv class\u003d\"col-md-6 visible-md visible-lg\"\u003e\u003cimg ng-src\u003d\"img/illustrative/laptop.jpg\" alt\u003d\"none\" class\u003d\"img-responsive\" /\u003e\u003c/div\u003e\r\n\u003cdiv class\u003d\"col-xs-12 col-md-6\"\u003e\r\n\u003cdiv class\u003d\"my-article-header\"\u003e\r\n\u003ch1\u003eSulvat Quis 1\u003c/h1\u003e\r\n\u003ch2\u003e– Nullam dictum ac enim\u003c/h2\u003e\r\n\u003c/div\u003e\r\n\u003cp\u003eProin quis justo vel felis varius sodales sit amet ut diam. Fusce auctor sapien nec purus sagittis, in venenatis turpis luctus. Nullam dictum ac enim sed commodo. Vivamus et placerat sapien.\u003c/p\u003e\r\n\u003c/div\u003e\r\n\u003c/div\u003e\r\n\u003c/div\u003e",
"articlePriority": 0,
"category": {
    "cmcaId": 9,
    "corp": {
        "corpId": 2,
        "guiSelected": false
    },
    "name": "carousel",
    "visibleInMenu": false
},
"published": true

}

4

4 回答 4

9

您在这里缺少的部分是通过$sce.trustAsResourceURL();. 有关相关文档,请参见此处

编辑:此外,您似乎没有将 ng-src 值包含在引号中(以及作为 HTML 属性所需的引号)。那是行不通的——ng-src 期望一个 javascript 字符串作为表达式的最终结果,而你为它提供了一个无效的 javascript 文字。

于 2013-11-01T15:15:13.683 回答
2

参考: $sanitize的AngularJS 文档有一个演示。在此演示中,如果您使用src而不是ng-src函数ng-bind-html(从中返回对象),图像将按预期显示。$sce.trustAsHtml()


建议的编辑:我将首先替换ng-srcsrc.

然后我会改变

for (var i = 0; i < data.length; i++) {
    $scope.slides[i].body = $sce.trustAsHtml(data[i].body);                     
}

for (var i = 0; i < data.length; i++) {
    $scope.slides[i].body = function() {
        return $sce.trustAsHtml(data[i].body);
    };
}

最后,这

.my-carousel-item(ng-bind-html='slide.body')

会变成

.my-carousel-item(ng-bind-html='slide.body()')

我自己没有对此进行测试,但请让我知道这是否有效。


编辑 (2013-11-02): 错字修复——我添加return到函数示例中。代码现在应该可以按预期工作了。

于 2013-10-27T22:22:04.537 回答
2

请参阅有关 AngularUI 讨论的评论: https ://github.com/angular-ui/bootstrap/issues/813#issuecomment-25760432

这是一个指令,它重新实现了bind-html-unsafeAngularJS 1.2 之前的旧功能。最后,这将与上面建议的相同,但麻烦最少。因此,您可以ng-bind-html-unsafe通过在主代码中添加 $sce 绕过来使用而不是降低代码的可读性。

另请参阅这个 Stackoverflow 问题:How do you use $sce.trustAsHtml(string) to replicate ng-bind-html-unsafe in Angular 1.2+

于 2013-10-29T20:46:56.310 回答
2

经过数小时搜索如何显示通过所见即所得编辑器为我的 CMS 应用程序上传的图像后,我发现了这个

.filter('toTrusted', ['$sce', function($sce) {
    return function(text) {
        return $sce.trustAsHtml(text);
    };
}]);
<div ng-bind-html="data  | toTrusted"></div>

希望能帮助到你

于 2017-08-31T13:38:23.150 回答