< img > : 在资源 URL 上下文中使用的不安全值

自从升级到最新的 Angular 2候选版本,我的 img标签:

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

正在抛出浏览器错误:

原始异常: 错误: 资源 URL 上下文中使用的不安全值

Url 的值是:

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

编辑:

我已经尝试了在另一个解决方案中提出的建议,这个问题应该是一个副本,但我得到了同样的错误。

我在控制器中添加了以下代码:

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);
}

我仍然收到相同的错误消息。

编辑2:

我还将 html 更改为:

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

我仍然得到相同的错误消息

245405 次浏览

您可以向视图公开消毒程序,也可以公开转发调用以绕过 SecurityTrustUrl 的方法

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

烟斗

    // 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);
}
}
}

模板

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

就是这样!

注意: 您不应该需要它,但这里是管道的组件使用

      // 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');
}

我使用 rc.4,这个方法适用于 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);
}
}

在 HTML:

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

使用一个函数可以确保在清理后值不会发生变化。还要注意,您使用的消毒功能取决于上下文。

对于图像,bypassSecurityTrustUrl可以工作,但对于其他用途,您需要参考文档 :

Https://angular.io/docs/ts/latest/api/platform-browser/index/domsanitizer-class.html

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.

解决这个问题的最优雅的方法是: 使用管道。所以你可以简单地使用 url | safe管道来绕过安全。

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

有关详细信息,请参阅 npm 上的文档: https://www.npmjs.com/package/safe-pipe

我通常像下面这样添加单独的 safe pipe可重用组件

# 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>

用安全管修理。

  • 如果你没有安全的管道,那就创建一个。

    ng g pipe safe

  • 在 app.module.ts 中添加安全管道

    declarations: [SafePipe]

  • 在你的帐篷里申报安全管道

进口 Dom 消毒剂和安全管道,安全访问网址

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);
}
}
  • 使用 src url 添加 safe

    < img width = “900”height = “500”[ src ] = “ link | safe”/>

默认情况下,Angular 将所有值视为不受信任。当一个值通过属性、属性、样式、类绑定或插值从模板插入到 DOM 中时,Angular 会清除并转义不受信任的值。

因此,如果您直接操作 DOM 并在其中插入内容,则需要对其进行消毒,否则 Angular 将抛出错误。

我已经为此创建了管道 消毒管

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);
}
}

这就是你如何利用

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

如果您想添加 HTML,那么 清洁管道可以提供帮助

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);
}
}

阅读更多关于角安全 给你

为了避免 unsafe url错误,可以将图像设置为背景图像:

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

CSS:

.show-image {
width: 100px;
height: 100px;
border-radius: 50%;
background-size: cover;
}
<img class='photo-img' [hidden]="!showPhoto1" src="data:image/jpeg;base64,\{\{theMediaItem.photoURL1}}">

这里有一个经过测试的更好的安全管道:

import { Pipe, PipeTransform, SecurityContext } from '@angular/core';
import {
DomSanitizer,
SafeHtml,
SafeResourceUrl,
SafeScript,
SafeStyle,
SafeUrl,
SafeValue,
} from '@angular/platform-browser';


@Pipe({
name: 'safe',
})
export class SafePipe implements PipeTransform {
constructor(private readonly domSanitizer: DomSanitizer) {}


transform(
value: string | undefined,
type: string,
bypass: boolean
):
| SafeHtml
| SafeStyle
| SafeScript
| SafeUrl
| SafeResourceUrl
| SafeValue
| null {
if (!value) {
return null;
}
switch (type) {
case 'style':
return bypass
? this.domSanitizer.bypassSecurityTrustStyle(value)
: this.domSanitizer.sanitize(SecurityContext.STYLE, value);
case 'script':
return bypass
? this.domSanitizer.bypassSecurityTrustScript(value)
: this.domSanitizer.sanitize(SecurityContext.SCRIPT, value);
case 'url':
return bypass
? this.domSanitizer.bypassSecurityTrustUrl(value)
: this.domSanitizer.sanitize(SecurityContext.URL, value);
case 'resourceUrl':
return bypass
? this.domSanitizer.bypassSecurityTrustResourceUrl(value)
: this.domSanitizer.sanitize(SecurityContext.RESOURCE_URL, value);
default:
return bypass
? this.domSanitizer.bypassSecurityTrustHtml(value)
: this.domSanitizer.sanitize(SecurityContext.HTML, value);
}
}
}






import { DomSanitizer } from '@angular/platform-browser';
import { SafePipe } from './safe.pipe';


const mockDomSanitizer = ({
sanitize: jest.fn(),
bypassSecurityTrustHtml: jest.fn(),
bypassSecurityTrustStyle: jest.fn(),
bypassSecurityTrustUrl: jest.fn(),
bypassSecurityTrustResourceUrl: jest.fn(),
bypassSecurityTrustScript: jest.fn(),
} as unknown) as DomSanitizer;


describe('SafePipe', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('should return null value when value received is undefined', () => {
const pipe = new SafePipe(mockDomSanitizer);
expect(pipe.transform(undefined, 'style', true)).toBeNull();
});
test.each([
{ a: 'style', b: true, expected: 'bypassSecurityTrustStyle' },
{ a: 'script', b: true, expected: 'bypassSecurityTrustScript' },
{ a: 'url', b: true, expected: 'bypassSecurityTrustUrl' },
{ a: 'resourceUrl', b: true, expected: 'bypassSecurityTrustResourceUrl' },
{ a: 'html', b: true, expected: 'bypassSecurityTrustHtml' },
])('should call the correspondent method', ({ a, b, expected }) => {
const pipe = new SafePipe(mockDomSanitizer);
pipe.transform('value', a, b);
const domSanitizer = mockDomSanitizer as never;
expect(domSanitizer[expected]).toHaveBeenCalled();
});


test.each([
{ a: 'style', b: false, expected: 'sanitize' },
{ a: 'script', b: false, expected: 'sanitize' },
{ a: 'url', b: false, expected: 'sanitize' },
{ a: 'resourceUrl', b: false, expected: 'sanitize' },
{ a: 'html', b: false, expected: 'sanitize' },
])('should call the correspondent method', ({ a, b, expected }) => {
const pipe = new SafePipe(mockDomSanitizer);
pipe.transform('value', a, b);
const domSanitizer = mockDomSanitizer as never;
expect(domSanitizer[expected]).toHaveBeenCalled();
});
});