ng-bind-html doesn't prevent cross site scripting - javascript

I used ng-bind-html in order to prevent cross site scripting,
read about sanitize and found this discussion and another good discussion.
Although, i did't work for me, can you please help me in figure out why?
HTML:
<p class="big-text" ng-bind-html="to_trusted(message)">
JS:
$scope.to_trusted = function(html_code) {
return $sce.trustAsHtml(html_code);
};
when i'm adding the following line
<img src="x" onerror="alert('cross')">
and adding it to a message i can see it rendered in the DOM, and when i'm refreshing the page i can see the message.
and the popup is shown:
can you please tell me what am i doing wrong?

First of all, it's not XSS on its own.
Second, $sce.trustAsHtml does exactly the opposite of what you thought - it, in fact, instructs Angular to "trust" that the HTML is safe - not to sanitize.
To sanitize, you need to add ngSanitize as a dependency to your app, and ng-bind-html directly to html_code (without to_trusted).
angular.module("myApp", ["ngSanitize"])
.controller("MainCtrl", function($scope){
$scope.html_code = '<img src="x" onerror="alert(\'cross\')">';
});
And in the HTML:
<div ng-bind-html="html_code"></div>

After using Sanitize i change my code and used getTrustedHtml instead trustAsHtml, it runs the sanitize on controller.
$scope.to_trusted = function(html_code) {
return $sce.getTrustedHtml(html_code);
};
And it solves my issue.

Related

Render html tag from string

I have some values as amount like 1000, 2000, <b>3000</b>, <4000>, <b>5000</b> inside JSON as an API response. I want to render this response inside a table. So I tried ng-bind-html. BUT it is showing only the value which are having tags like 3000,5000. I want to show all values , 1000,2000,4000 as a plain string and 3000,5000 in BOLD/or any other HTML tag.
angular.forEach($scope.arr2.test,function(item)
$scope.res=$sce.trustAsHtml(item.amount);
return $scope.res;
});
On HTML side, I have something like this
<td id="price" class="edit" ng-repeat="pro in d.procedure" ng-bind-html="valueCheck(d._id,pro._id,hos._id)"></td>
You can use ng-bind-html and ng-bind-html-unsafe for this. But please be mindful of the security concerns here.
You can find more details here
Do make sure you sanitize your strings, to prevent security vulnerabilities
First of all you need to download the ng-sanitize js
https://docs.angularjs.org/api/ngSanitize
and then inject ng-sanitize to angular module.
then you can use ng-bind-html and ng-bind-html-unsafe
you can use ng-sanitize module for the same - see here
var app = angular.module("myApp", ['ngSanitize']);

How to create a messaging service across application in Angular JS?

I want to show messages to the end user, just like Google, at the top center of the web panel.
I don't want to include the HTML and related script everywhere in every form and list and chart that I have. I want to centralize this messaging functionality into a service (in Angular JS term) that can be used everywhere.
And just like Google, I want to be able to show rich text in my messages, that is, I want to include links and probably other HTML stuff there. For example instead of showing Customer is defined, I want to show Customer is defined, <a href='#/customer/addPhone'>Now add a phone</a> to guide the user.
What I've done is to place the messages HTML in the root layout of my single paged application:
<div class="appMessages">
<span ng-show="message" ng-click="clearMessage()" ng-bind-html="message"></span>
</div>
and in our controllers, we inject the $rootScope and try to set the message property on it.
Yet I get no results. Can you guide me please?
As a general best practice I would avoid using $rootScope to pass the messages but rather use a dedicated service to update the message,
On your case the problem might be that you need to use angular $sce service to mark your html as trusted.
or load ng-santizemodule instead (which is a seperate module you need to load see offical doc)
That is needed because angular security requires you to explicitly check the html, if the source of your messages are from your code only, and not users inupts you can use the trustAsHtml as you know for sure it a safe html.
On your controller inject $sce, and bind it to your scope, and then use the $sce.trustAsHtml(value) function.
<div class="appMessages">
<span ng-show="message" ng-click="clearMessage()" ng-bind-html="$sce.trustAsHtml(message)"></span>
</div>
angular.module('app', [])
.component('message', {
controller: function($sce, messagService){
this.messagService = messagService;
this.$sce = $sce;
},
template: '{{$ctrl.message}}<div ng-bind-html="$ctrl.$sce.trustAsHtml($ctrl.messagService.message)"></div>'
})
.service('messagService', function(){
this.message = '';
this.updateMessage = function(message){
this.message = message;
}
})
.controller('mainCtrl', function($scope, messagService){
$scope.updateMessage = function () {
messagService.updateMessage('wow <b style="color:yellow;">shiny</b> message');
};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div ng-controller="mainCtrl" ng-app="app">
<message></message>
<button type="button" ng-click="updateMessage()"> update message</button>
</div>

Angular: $scope.msg Appearing in Console, Not on DOM

I've ran into a bit of a problem, wherein I've created a $scope.msg and it's printing to my console just fine, but it won't render itself on the DOM. I'm using Browserify to require angular and bundle my js.
index.html
<body ng-app="zeroApp" ng-controller="MainCtrl">
<div class="container">
<div class="item">
<h1>{{ msg }}</h1>
</div>
</div>
<script src="./js/app.js"></script>
</body>
app.js
(function() {
'use strict';
var angular = require('angular');
angular.module('zeroApp', [])
.controller('MainCtrl', ['$scope', function($scope) {
$scope.msg = "Hello Angular!";
console.log($scope.msg);
}]);
})();
Any reason why this isn't being exposed to the DOM and my <h1> element is empty?
Any help is appreciated. Thanks in advance!
Unfortunately I'm not an Angular expert so I can't explain the details, but the problem is that Angular wont detect that change, and thus it wont be propagated into the view. There are other ways around it, but one rather simple fix is to wrap the message into an extra object. Instead of using $scope.msg, try using $scope.msg.txt and it should work.
Hopefully someone with more knowledge of Angular's inner workings can clarify this further.
Here's another Fiddle to demonstrate: http://jsfiddle.net/29Luq8ns/1/
Notice I'm using $timeout in it. That's another way you could work around the problem. By changing $scope.msg inside a $timeout function, it will work, even without a delay parameter.
Figured it out. I was using Swig in my gulpfile.js to do render my HTML templates. The mustache templating language of Swig must have been conflicting with Angular's templating lang. Took it out of my build process and it works like a charm.
Thanks for all the help.

In AngularJS, any inline javascript code that included in HTML templates doesn't work

In AngularJS, any inline javascript code that included in HTML templates doesn't work.
For Example:
main.html file:
<div ng-include="'/templates/script.html'"></div>
And script.html file:
<script type="text/javascript">
alert('yes');
</script>
When I open main page, I expect an alert message that say 'yes' but nothing happens. I think some security restrictions in the AngularJS is preventing inline scripts, but I couldn't find any workaround about that.
Note: I don't use jQuery or any other framework, only AngularJS 1.2.7.
jQlite does not support script tags. jQuery does, so the recommendation is to include jQuery if you need this functionality.
From Angular's Igor Minar in this discussion:
we looked into supporting script tags in jqlite, but what needs to be
done to get a cross-browser support involves a lot of black magic. For
this reason we decided that for now we are just going to recommend
that users use jquery along with angular in this particular case. It
doesn't make sense for us to rewrite one third of jquery to get this
working in jqlite.
Here's the related github issue jqLite should create elements in same way as jQuery where Igor sums up, before closing the issue, with this:
This is too much craziness for jqlite, so we are not going to do it.
Instead we are going to document that if you want have script elements
in ng:include or ng:view templates, you should use jquery.
demo plunker with jquery
Angular uses the $sanitize on ng-include directives which strips out scripts. A better approach for templates is to create a controller for that template.
It is better to use an individual controller for templates.
In template.html
<form role="form" ng-controller="LoginController">
<input type="text" placeholder="Email" ng-model="email">
<input type="password" placeholder="Password" ng-model="password">
<button class="btn btn-success" ng-click="login()">Sign in</button>
</form>
In the LoginController you can use whatever code you want
angular.module('myApp.controllers', []).
controller('LoginController', [function() {
alert('controller initialized');
}])
The event triggered when ng-include adds content is $includeContentLoaded. Your scripts should be included in this event:
For example (Plucker Demo):
function SettingsController($scope, $window) {
$scope.template={};
$scope.template.url = "demo.html";
$scope.$on('$includeContentLoaded', function(event){
$window.alert('content load');
});
}
Additionally you can set an init function using the onload attribute:
html
<div ng-include="template.url" onload="alertMe()" > </div>
</div>
Controller
$scope.alertMe=function(){
$window.alert('sending alert on load');
}
Include jQuery and change order of the angular.js and jquery.js. jQuery must be first, otherwise it does not work

What is the way to encode json template to html with angularJS?

I'm a beginner in AngularJS and I try to render a json in html with angularJS but html tags are not encoded. Is there a way to do that with an angularJS method ?
My HTML:
<p>{{template.title}}</p>
My JSON:
{
"title":"try a <br> to break line"
}
My JS:
$http.get(JSON).success(function (data) {
$scope.template = data;
});
Unfortunately, the render display the br tag
Angular wants to bind text as text by default.
In Angular <1.2.0 you need to bind the html unsafe (this can be dangerous):
<h1 ng-bind-html-unsafe="title"></h1>
In Angular 1.2.0 you need to bind the html:
<h1 ng-bind-html="title"></h1>
Dont forget to include ngSanitize to keep your server safe.
Overall, I recommend using Angular 1.2.0 rc2 or later versions as the ngSanitize will keep you safe.

Categories