Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CSP and Ionic 2 (Angular 2), 'Refused to load the image "unsafe:cdvphotolibrary"' #15

Closed
dnmd opened this issue Nov 16, 2016 · 9 comments

Comments

@dnmd
Copy link

dnmd commented Nov 16, 2016

Excellent plugin, I hope it becomes part of the native plugins soon, I'll contribute where possible (and will look into making the wrapper)!

Just a small issue, I think it is related to CSP and Angular 2 (thus Ionic 2), but I can't get thumbnails to be displayed without sanitizing the URL's. When doing so, the whole <meta> tag is not required anymore, therefore it feels wrong but it is the only way I got it working. Maybe I'm missing something... I posted my current solution below.

<!-- without sanitizing, the following error shows up in the console -->
Refused to load the image 'unsafe:cdvphotolibrary://thumbnail?...height=384&quality=0.8' because it violates the following Content Security Policy directive: "img-src 'self' data: blob: cdvphotolibrary:".
<!-- not required when sanitizing your URL's, therefore it feels "wrong" -->
  <meta http-equiv="Content-Security-Policy" 
        content="default-src 'self' data: gap: https://ssl.gstatic.com; 
                 style-src 'self' 'unsafe-inline'; 
                 img-src 'self' data: blob: cdvphotolibrary:"> 
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';

...

list: Array<string> = new Array();
constructor( private ds: DomSanitizer) { }

...

var self = this;
cordova.plugins.photoLibrary.getLibrary(
      function (library) {

        library.forEach(function (libraryItem) {
          // sanitize, else Angular 2 prepends: "unsafe:"
          let url: SafeUrl = self.ds.bypassSecurityTrustUrl(libraryItem.thumbnailURL);
          self.list.push(<string>url);
         
        });

      },
      function (err) { },
      {
        thumbnailWidth: 512,
        thumbnailHeight: 384,
        quality: 0.8
      }
);
@viskin
Copy link
Member

viskin commented Nov 16, 2016

Nice finding. I don't use ng2 in my current project, so I cannot tell exactly what's going on here, but...
It's interesting why DomSanitizer decides to add unsafe: prefix to cdvphotolibrary protocol? cordova-plugin-file uses cdvfile:// protocol, do you use it in your app? I wonder if cdvfile:// also needs to be manually trusted with ng2?
Anyway, if you will use PipeTransform to perform bypassSecurityTrustUrl on cdvphotolibrary urls, in a way described here, will it work and will it be convenient enough? If so, we can recommend this solution in README.

@metalaureate
Copy link

metalaureate commented Nov 17, 2016

@viskin Apologies if this is not the same issue--I'm using Angular 1.5 and I get this error when I try to construct the url:

Refused to load unsafe:cdvphotolibrary://photo?photoId=5F347FD6-7D84-4208-BA29-BD4C5735525D%2FL0%2F001 because it does not appear in the img-src directive of the Content Security Policy.

My CSP tag looks like:

<meta http-equiv="Content-Security-Policy"
         content="default-src 'self' data: gap: https://ssl.gstatic.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: cdvphotolibrary:">

@dnmd
Copy link
Author

dnmd commented Nov 17, 2016

@metalaureate, as explained, Angular 1 and 2 will always sanitize data that gets injected into the DOM, it will not respect any CSP rules present, thus also in Angular 1 you need to whitelist the cdvphotolibrary protocol like so:

var app = angular
    .module('myApp', [])
    .config([
        '$compileProvider',
        function ($compileProvider) {
            $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|cdvphotolibrary):/);
            // Angular before v1.2 uses $compileProvider.urlSanitizationWhitelist(...)
        }
    ]);

source

@dnmd
Copy link
Author

dnmd commented Nov 17, 2016

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 (source)

@viskin, the cdvfile:// and cdvphotolibrary:// 'prefixes' are (indeed) both treated as unsafe, I've tested both plugins. The CSP meta tag can be seen as the first layer of defense, but as we've seen, Angular has its own.

So as a note to the use of Ionic 2, one can construct a Pipe, to sanitize the URL's used in this plugin. Another solution might be returning a blob or ArrayBuffer (instead of URL's), as implemented in this cordova-plugin-photos.

@Pipe({name: 'safeUrl'})
export class Safe {
  constructor(private sanitizer:DomSanitizer){}

  transform(url) {
    return this.sanitizer.bypassSecurityTrustUrl(url);
  }
}
@Component({
   selector: 'app',
   template: '<img [src]="url | safeUrl"></div>',
   pipes: [
      SanitizeHtml
   ]
})

export class AppComponent{

    public url: string = 'placeholder.jpg';

    constructor() {
      // fetch thumbnail URL's
      this.url = libraryItem.thumbnailURL;
    }

} 

@dnmd dnmd closed this as completed Nov 17, 2016
@viskin
Copy link
Member

viskin commented Nov 17, 2016

Great, I will add this info to README.
Thank you.

@dnmd, we already support returning blob instead of url with photoLibrary.getThumbnail and photoLibrary.getPhoto.

@arberkryeziu
Copy link

I have some issues with sanatization. The guideline for Angular 2 in the Readme is not correct.
...
@Component({ selector: 'app', template: '<img [src]="url | safeUrl"></div>', pipes: [ SafeUrl ] })
...
With my little research , I saw that Pipes cannot be declared inside component anymore. They should be declared in NgModules . Notice also the closing tag inside template. It should be img instead of div.

However, even after doing that, I get SafeValue must use [property]=binding: cdvphotolibrary://photo?photoId=65E0377C-1838-4FC8-990F-34801BA0F6A9%2FL0%2F001 (see http://g.co/ng/security#xss)

Does anybody else has this issue in ios ?

@viskin
Copy link
Member

viskin commented Feb 22, 2017

@ArberK Thanks, I updated the readme.

@giacomodeliberali
Copy link

giacomodeliberali commented Feb 12, 2018

Have the same issue of @ArberK. @viskin, how can the bypass be achieved?

@pratikjain93
Copy link

Can anybody give the syntax for IONIC 1 i.e angular 1 as i have project running in Angular 1. Any help is highly appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants