最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Partial HTML string escaping in Angular.js - Stack Overflow

programmeradmin1浏览0评论

I have read about angular's way of escaping everything by default and $sce, so I white-list data with $sce.trustAsHtml() through filter (since $sce is not working in service), like this:

<sup class="ng-binding" ng-bind-html="row|logEntry"></sup>

But the problem is, that I don't trust some parts of HTML.

To dive into details - I have translations that have HTML in it, but they have replaceable tokens/variables in them. So translations support HTML, but I don't want provided tokens to include HTML.

My filter logEntry internally looks like this:

var translated = $translate('Log.' + msg.context.entity_type) + '.' + msg.context.action, {
        'object_name': msg.context.object_name,
        'user': msg.context.user_name
});
return $sce.trustAsHtml(translated);

For example I can have translation about userX changing article, but I don't want result text to trigger alert() if user's name includes <script>alert('evilname')</script>

$translate by itself is not relevant, it can be any HTML string where I want some parts to be replaced with regular JS .replace() with content staying "as text".

So my question is - how can I escape parts of HTML? Do I have to resort to slicing it in parts inside of a view? Or do I have to resort to custom escaping ( Fastest method to escape HTML tags as HTML entities? )? Is there a preferred practice for such things?

I have read about angular's way of escaping everything by default and $sce, so I white-list data with $sce.trustAsHtml() through filter (since $sce is not working in service), like this:

<sup class="ng-binding" ng-bind-html="row|logEntry"></sup>

But the problem is, that I don't trust some parts of HTML.

To dive into details - I have translations that have HTML in it, but they have replaceable tokens/variables in them. So translations support HTML, but I don't want provided tokens to include HTML.

My filter logEntry internally looks like this:

var translated = $translate('Log.' + msg.context.entity_type) + '.' + msg.context.action, {
        'object_name': msg.context.object_name,
        'user': msg.context.user_name
});
return $sce.trustAsHtml(translated);

For example I can have translation about userX changing article, but I don't want result text to trigger alert() if user's name includes <script>alert('evilname')</script>

$translate by itself is not relevant, it can be any HTML string where I want some parts to be replaced with regular JS .replace() with content staying "as text".

So my question is - how can I escape parts of HTML? Do I have to resort to slicing it in parts inside of a view? Or do I have to resort to custom escaping ( Fastest method to escape HTML tags as HTML entities? )? Is there a preferred practice for such things?

Share Improve this question edited May 23, 2017 at 12:00 CommunityBot 11 silver badge asked Nov 21, 2014 at 12:22 Artjom KurapovArtjom Kurapov 6,1554 gold badges33 silver badges43 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 5

Let's start by restructuring your logEntry to separate out the interpolateParams

var translationId = 'Log.' + msg.context.entity_type) + '.' + msg.context.action;
var interpolateParams = {
        'object_name': msg.context.object_name,
        'user': msg.context.user_name
};
var translated = $translate(translationId, interpolateParams);
return $sce.trustAsHtml(translated);

You want to escape all HTML from interpolateParams but leave any HTML in your translation templates. Use this code to copy the object, iterate over its values and replace with escaped HTML.

var safeParams = angular.copy(interpolateParams);    
angular.forEach(safeParams, function(value, key, obj) {     
  obj[key] = encodeEntities(value)
  // if you want safe/sanitized HTML, use this instead
  // obj[key] = $sanitize(value);
});
var translated = $translate(translationId, safeParams);

Lastly, the encodeEntities functionality of angular isn't exposed, so we had to borrow the source from angular-sanitize.js

var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
    // Match everything outside of normal chars and " (quote character)
    NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g;
function encodeEntities(value) {
  return value.
    replace(/&/g, '&amp;').
    replace(SURROGATE_PAIR_REGEXP, function(value) {
      var hi = value.charCodeAt(0);
      var low = value.charCodeAt(1);
      return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';';
    }).
    replace(NON_ALPHANUMERIC_REGEXP, function(value) {
      return '&#' + value.charCodeAt(0) + ';';
    }).
    replace(/</g, '&lt;').
    replace(/>/g, '&gt;');
}

Update: After updating to angular-translate 2.7.0 this message appeared:

pascalprecht.translate.$translateSanitization: No sanitization strategy has been configured. This can have serious security implications. See http://angular-translate.github.io/docs/#/guide/19_security for details.

Sp instead of the trustlate answer above, angular-translate can acplish the same result with:

$translateProvider.useSanitizeValueStrategy('escapeParameters');

See the docs for more Sanitize Value Strategies

In your app add

$translateProvider.useSanitizeValueStrategy('escapeParameters');

So that, your code looks like this :

myApp.config(function ($translateProvider) {

    //...whatever

  $translateProvider.useSanitizeValueStrategy('escapeParameters');

});
发布评论

评论列表(0)

  1. 暂无评论