Angular 2: sanitizing HTML stripped some content with div id - this is bug or feature?
Asked Answered
H

4

45

I use <div [innerHTML]="body"></div> to pass unescaped HTML to my template, and when I pass to body div with attribute id, Angular throw:

WARNING: sanitizing HTML stripped some content (see http://g.co/ng/security#xss). WARNING: sanitizing HTML stripped some content (see http://g.co/ng/security#xss). WARNING: sanitizing HTML stripped some content (see http://g.co/ng/security#xss).

See. plunker

So why it says this? What can be dangerous id in div? Could this bug?

Hammerfest answered 24/9, 2016 at 21:32 Comment(1)
Here's an explanation and a possible solution to the problem Angular docsSula
C
11

It is because id attribute is not safe.

This is not my answer but it will answer your question : https://security.stackexchange.com/questions/88973/why-do-id-attributes-need-stricter-validation


For id and name, these attributes are frequently used as reference points in the DOM.

If an attacker can spoof these reference points, she may be able trick existing scripts into getting and setting values from places other than designed, which may be dangerous depending on the context that is is used.


Note from me: The rest of his post talks about the name attribute, but you'll get the idea behind all this if you don't already by what's above


This also applies to HTML forms where name is used to identify the name/value pair. For example, if a website does not encode a particular form field when it is output, but since the form field is server generated and the form is protected against CSRF by the use of tokens it cannot be exploited by normal means. However, an attacker may be able to entice a user to visit a URL with a parameter that is used in name, containing an XSS payload to execute on submission of the form.

e.g. Normal use:

https://example.com/product?item_name=watch&qty=1

which renders a form

<form>

<input type="hidden" name="watch" value="1" />
<input type="hidden" name="shop_name" value="Bob's Supplies" />
<input type="hidden" name="anti-csrf" value="asdjasodhoai" />

<input type="submit" value="Click here to buy" />

</form>

And then gets output as

Thank you for buying from Bob's Supplies.

However, an attacker could send a link to the user like so:

https://example.com/product?item_name=shop_name&qty=<script>alert('xss')</script>

As the application is correctly HTML encoding at this point it renders the form as

<form>

<input type="hidden" name="shop_name" value="&lt;script&gt;alert(&#039;xss&#039;)&lt;/script&gt;" />
<input type="hidden" name="shop_name" value="Bob's Supplies" />
<input type="hidden" name="anti-csrf" value="asdjasodhoai" />

<input type="submit" value="Click here to buy" />

</form>

This then gets output as

Thank you for buying from <script>alert('xss')</script>.

since this page doesn't HTML encode the shop_name parameter because it is trusted and the application framework always takes the first value in case of duplicates. Very contrived, but it was the first thing that fell into my head to demonstrate the point.

Cannonball answered 24/9, 2016 at 22:29 Comment(1)
see also #39628507Incoming
A
101

Simple solution is to write pipe like

import { Pipe, PipeTransform } from "@angular/core";
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';

@Pipe({
  name: 'sanitizeHtml'
})
export class SanitizeHtmlPipe implements PipeTransform {

  constructor(private _sanitizer:DomSanitizer) {
  }

  transform(v:string):SafeHtml {
    return this._sanitizer.bypassSecurityTrustHtml(v);
  }
}

add in your html file add pipe like

  <td *ngIf="i>0" [innerHTML]="entry.attributes[i] | sanitizeHtml"></td>
Acantho answered 2/12, 2016 at 23:5 Comment(9)
together with the answer from Karl from this question: #39007630 a good fix for this problem with the SanitizerFalmouth
@Falmouth This works well sanatizing but I get undefined being displayed momenteraly before my [innerHTML] content is display. <div [innerHTML]="code | sanitizeHtml"></div>Implacable
SafeHtml? where it should be imported fromGoree
When writing the pipe don't forget to import DomSanitizer and SafeHtml. import { DomSanitizer, SafeHtml } from '@angular/platform-browser';Catchings
@Implacable you can add a null check to your code for example. <div [innerHTML]="user?.name | sanitizeHtml"></div>Auntie
i added the above code in my home.ts and home.html but it says Template parse errors: The pipe 'sanitizeHtml' could not be found (" what do i need to do ?Use
Getting WARNING: sanitizing HTML stripped some content (see http://g.co/ng/security#xss). There was mentioning elsewhere that this approach doesn't work inside ng-content so might be that case.Colloquium
If you get pipe 'sanitizeHtml' was not found you just make a pipe and put that code there. Angular cli: ng generate pipe <pipename> and edit the pipefile.ts generated and insert code there, and it will work.Daffy
Certainly not recommended, unless you are absolutely sure that you can trust your html.Cointon
C
11

It is because id attribute is not safe.

This is not my answer but it will answer your question : https://security.stackexchange.com/questions/88973/why-do-id-attributes-need-stricter-validation


For id and name, these attributes are frequently used as reference points in the DOM.

If an attacker can spoof these reference points, she may be able trick existing scripts into getting and setting values from places other than designed, which may be dangerous depending on the context that is is used.


Note from me: The rest of his post talks about the name attribute, but you'll get the idea behind all this if you don't already by what's above


This also applies to HTML forms where name is used to identify the name/value pair. For example, if a website does not encode a particular form field when it is output, but since the form field is server generated and the form is protected against CSRF by the use of tokens it cannot be exploited by normal means. However, an attacker may be able to entice a user to visit a URL with a parameter that is used in name, containing an XSS payload to execute on submission of the form.

e.g. Normal use:

https://example.com/product?item_name=watch&qty=1

which renders a form

<form>

<input type="hidden" name="watch" value="1" />
<input type="hidden" name="shop_name" value="Bob's Supplies" />
<input type="hidden" name="anti-csrf" value="asdjasodhoai" />

<input type="submit" value="Click here to buy" />

</form>

And then gets output as

Thank you for buying from Bob's Supplies.

However, an attacker could send a link to the user like so:

https://example.com/product?item_name=shop_name&qty=<script>alert('xss')</script>

As the application is correctly HTML encoding at this point it renders the form as

<form>

<input type="hidden" name="shop_name" value="&lt;script&gt;alert(&#039;xss&#039;)&lt;/script&gt;" />
<input type="hidden" name="shop_name" value="Bob's Supplies" />
<input type="hidden" name="anti-csrf" value="asdjasodhoai" />

<input type="submit" value="Click here to buy" />

</form>

This then gets output as

Thank you for buying from <script>alert('xss')</script>.

since this page doesn't HTML encode the shop_name parameter because it is trusted and the application framework always takes the first value in case of duplicates. Very contrived, but it was the first thing that fell into my head to demonstrate the point.

Cannonball answered 24/9, 2016 at 22:29 Comment(1)
see also #39628507Incoming
P
8

To mark a value as trusted, inject DomSanitizer and call one of the following methods:

bypassSecurityTrustHtml
bypassSecurityTrustScript
bypassSecurityTrustStyle
bypassSecurityTrustUrl
bypassSecurityTrustResourceUrl



import { DomSanitizer } from '@angular/platform-browser';

public sanitizer: DomSanitizer

[innerHtml]="sanitizer.bypassSecurityTrustHtml(content)"

https://angular.io/guide/security#xss

Picador answered 8/7, 2021 at 20:7 Comment(0)
T
1

You can also use NgDompurify library. It can sanitize your content better due DomPurify and solves all your problems with angular default sanitizer.

Tani answered 9/9, 2019 at 19:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.