<img>: Unsafe value used in a resource URL context

Angular

Angular Problem Overview


Since upgrading to the latest Angular 2 release candidate, my img tags:

<img class='photo-img' [hidden]="!showPhoto1" src='{{theMediaItem.photoURL1}}'>

are throwing a browser error:

> ORIGINAL EXCEPTION: Error: unsafe value used in a resource URL context

The value of the url is:

http://veeu-images.s3.amazonaws.com/media/userphotos/116_1464645173408_cdv_photo_007.jpg

EDIT:

I have tried the suggestion made in the other solution that this question is supposed to be a duplicate of but I am getting the same error.

I have added the following code to the controller:

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

@Component({
  templateUrl: 'build/pages/veeu/veeu.html'
})
export class VeeUPage {
  static get parameters() {
    return [[NavController], [App], [MenuController], [DomSanitizationService]];
  }

  constructor(nav, app, menu, sanitizer) {

    this.app = app;
    this.nav = nav;
    this.menu = menu;
    this.sanitizer = sanitizer;
    
    this.theMediaItem.photoURL1 = this.sanitizer.bypassSecurityTrustUrl(this.mediaItems[1].url);
  }
  
  

I am still getting the same error message.

EDIT2:

I have also changed the html to:

<img class='photo-img' [hidden]="!showPhoto1" [src]='theMediaItem.photoURL1'>

I still get the same error message

Angular Solutions


Solution 1 - Angular

Pipe

    // Angular
    import { Pipe, PipeTransform } from '@angular/core';
    import { DomSanitizer, SafeHtml, SafeStyle, SafeScript, SafeUrl, SafeResourceUrl } from '@angular/platform-browser';
    
    /**
     * Sanitize HTML
     */
    @Pipe({
      name: 'safe'
    })
    export class SafePipe implements PipeTransform {
      /**
       * Pipe Constructor
       *
       * @param _sanitizer: DomSanitezer
       */
      // tslint:disable-next-line
      constructor(protected _sanitizer: DomSanitizer) {
      }
    
      /**
       * Transform
       *
       * @param value: string
       * @param type: string
       */
      transform(value: string, type: string): SafeHtml | SafeStyle | SafeScript | SafeUrl | SafeResourceUrl {
        switch (type) {
          case 'html':
            return this._sanitizer.bypassSecurityTrustHtml(value);
          case 'style':
            return this._sanitizer.bypassSecurityTrustStyle(value);
          case 'script':
            return this._sanitizer.bypassSecurityTrustScript(value);
          case 'url':
            return this._sanitizer.bypassSecurityTrustUrl(value);
          case 'resourceUrl':
            return this._sanitizer.bypassSecurityTrustResourceUrl(value);
          default:
            return this._sanitizer.bypassSecurityTrustHtml(value);
        }
      }
    }

Template

{{ data.url | safe:'url' }}

That's it!

Note: You shouldn't need it but here is the component use of the pipe
      // Public properties
      itsSafe: SafeHtml;

      // Private properties
      private safePipe: SafePipe = new SafePipe(this.domSanitizer);
    
      /**
       * Component constructor
       *
       * @param safePipe: SafeHtml
       * @param domSanitizer: DomSanitizer
       */
      constructor(private safePipe: SafePipe, private domSanitizer: DomSanitizer) {
      }
    
      /**
       * On init
       */
      ngOnInit(): void {
        this.itsSafe = this.safePipe.transform('<h1>Hi</h1>', 'html');
      }

Solution 2 - Angular

I'm using rc.4 and this method works for ES2015(ES6):

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

@Component({
  templateUrl: 'build/pages/veeu/veeu.html'
})
export class VeeUPage {
  static get parameters() {
    return [NavController, App, MenuController, DomSanitizationService];
  }

  constructor(nav, app, menu, sanitizer) {

    this.app = app;
    this.nav = nav;
    this.menu = menu;
    this.sanitizer = sanitizer;    
  }
  
  photoURL() {
    return this.sanitizer.bypassSecurityTrustUrl(this.mediaItems[1].url);
  }
}

In the HTML:

<iframe [src]='photoURL()' width="640" height="360" frameborder="0"
    webkitallowfullscreen mozallowfullscreen allowfullscreen>
</iframe>

Using a function will ensure that the value doesn't change after you sanitize it. Also be aware that the sanitization function you use depends on the context.

For images, bypassSecurityTrustUrl will work but for other uses you need to refer to the documentation:

https://angular.io/docs/ts/latest/api/platform-browser/index/DomSanitizer-class.html

Solution 3 - Angular

The most elegant way to fix this: use pipe. Here is example (my blog). So you can then simply use url | safe pipe to bypass the security.

<iframe [src]="url | safe"></iframe>

Refer to the documentation on npm for details: https://www.npmjs.com/package/safe-pipe

Solution 4 - Angular

Use Safe Pipe to fix it.

  • Create a safe pipe if u haven't any.

    ng g pipe safe

  • add Safe pipe in app.module.ts

    declarations: [SafePipe]

  • declare safe pipe in your ts

Import Dom Sanitizer and Safe Pipe to access url safely

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

@Pipe({ name: 'safe' })

export class SafePipe implements PipeTransform {

constructor(private sanitizer: DomSanitizer) { }
transform(url) {
 return this.sanitizer.bypassSecurityTrustResourceUrl(url);
  }
}
  • Add safe with src url

Solution 5 - Angular

Either you can expose sanitizer to the view, or expose a method that forwards the call to bypassSecurityTrustUrl

<img class='photo-img' [hidden]="!showPhoto1" 
    [src]='sanitizer.bypassSecurityTrustUrl(theMediaItem.photoURL1)'>

Solution 6 - Angular

Angular treats all values as untrusted by default. When a value is inserted into the DOM from a template, via property, attribute, style, class binding, or interpolation, Angular sanitizes and escapes untrusted values.

So if you are manipulating DOM directly and inserting content it, you need to sanitize it otherwise Angular will through errors.

I have created the pipe SanitizeUrlPipe for this

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

@Pipe({
    name: "sanitizeUrl"
})
export class SanitizeUrlPipe implements PipeTransform {

    constructor(private _sanitizer: DomSanitizer) { }

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

and this is how you can use

<iframe [src]="url | sanitizeUrl" width="100%" height="500px"></iframe>

If you want to add HTML, then SanitizeHtmlPipe can help

import { PipeTransform, Pipe } 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);
    }
}

Read more about angular security here.

Solution 7 - Angular

> I usually add separate safe pipe reusable component as following

# Add Safe Pipe

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

@Pipe({name: 'mySafe'})
export class SafePipe implements PipeTransform {
    constructor(private sanitizer: DomSanitizer) {
    }

    public transform(url) {
        return this.sanitizer.bypassSecurityTrustResourceUrl(url);
    }
}

# then create shared pipe module as following 

import { NgModule } from '@angular/core'; 
import { SafePipe } from './safe.pipe';
@NgModule({
    declarations: [
        SafePipe
    ],
    exports: [
        SafePipe
    ]
})
export class SharedPipesModule {
}

# import shared pipe module in your native module

@NgModule({
    declarations: [],
    imports: [
        SharedPipesModule,
    ],
})
export class SupportModule {
}

<!-------------------
call your url (`trustedUrl` for me) and add `mySafe` as defined in Safe Pipe
---------------->
<div class="container-fluid" *ngIf="trustedUrl">
    <iframe [src]="trustedUrl | mySafe" align="middle" width="100%" height="800" frameborder="0"></iframe>
</div>

Solution 8 - Angular

import {DomSanitizationService} from '@angular/platform-browser';
@Component({
 templateUrl: 'build/pages/veeu/veeu.html'
 })
  export class VeeUPage {
     trustedURL:any;
      static get parameters() {
               return [NavController, App, MenuController, 
              DomSanitizationService];
        }
      constructor(nav, app, menu, sanitizer) {
        this.app = app;
        this.nav = nav;
        this.menu = menu;
        this.sanitizer = sanitizer;  
        this.trustedURL  = sanitizer.bypassSecurityTrustUrl(this.mediaItems[1].url);
        } 
 }



 <iframe [src]='trustedURL' width="640" height="360" frameborder="0"
   webkitallowfullscreen mozallowfullscreen allowfullscreen>
</iframe>


User property binding instead of function.

Solution 9 - Angular

It is possible to set image as background image to avoid unsafe url error:

<div [style.backgroundImage]="'url(' + imageUrl + ')'" class="show-image"></div>

CSS:

.show-image {
    width: 100px;
    height: 100px;
    border-radius: 50%;
    background-size: cover;        
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBill NobleView Question on Stackoverflow
Solution 1 - AngularPost ImpaticaView Answer on Stackoverflow
Solution 2 - AngularelkelkView Answer on Stackoverflow
Solution 3 - AngularFilip MolcikView Answer on Stackoverflow
Solution 4 - Angularsjsj15View Answer on Stackoverflow
Solution 5 - AngularNguyễn Việt TrungView Answer on Stackoverflow
Solution 6 - AngularSunil GargView Answer on Stackoverflow
Solution 7 - AngularJankiView Answer on Stackoverflow
Solution 8 - AngularaniView Answer on Stackoverflow
Solution 9 - AngularStepUpView Answer on Stackoverflow