Closed dnmd closed 7 years ago
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.
@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:">
@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(...)
}
]);
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;
}
}
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.
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 ?
@arberK Thanks, I updated the readme.
Have the same issue of @arberK. @viskin, how can the bypass be achieved?
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.
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.