/
githubmirror
/
angular
Обзор
Документация
Войти
/
githubmirror
/
angular
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/core/test/sanitization/sanitization_spec.ts
220 строк
9 KB
SkyZeroZx
fix(core): account for namespaces in host binding sanitization (#69558)
29 июл 2026, 18:36
29 июл 2026, 18:36
f57d5d5
Код
Авторство
О чём код?
/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ import {ENVIRONMENT, LView} from '../../src/render3/interfaces/view'; import {enterView, leaveView} from '../../src/render3/state'; import { bypassSanitizationTrustHtml, bypassSanitizationTrustResourceUrl, bypassSanitizationTrustScript, bypassSanitizationTrustStyle, bypassSanitizationTrustUrl, } from '../../src/sanitization/bypass'; import { getUrlSanitizer, ɵɵsanitizeHtml, ɵɵsanitizeResourceUrl, ɵɵsanitizeScript, ɵɵsanitizeStyle, ɵɵsanitizeUrl, ɵɵsanitizeUrlOrResourceUrl, ɵɵtrustConstantHtml, ɵɵtrustConstantResourceUrl, } from '../../src/sanitization/sanitization'; import {SECURITY_SCHEMA, SecurityContext} from '../../src/sanitization/dom_security_schema'; function fakeLView(): LView { const fake = [null, {}] as LView; fake[ENVIRONMENT] = {} as any; return fake; } describe('sanitization', () => { beforeEach(() => enterView(fakeLView())); afterEach(() => leaveView()); class Wrap { constructor(private value: string) {} toString() { return this.value; } } it('should sanitize html', () => { expect(ɵɵsanitizeHtml('<div></div>').toString()).toEqual('<div></div>'); expect(ɵɵsanitizeHtml(new Wrap('<div></div>')).toString()).toEqual('<div></div>'); expect(ɵɵsanitizeHtml('<img src="javascript:true">').toString()).toEqual( '<img src="unsafe:javascript:true">', ); expect(ɵɵsanitizeHtml(new Wrap('<img src="javascript:true">')).toString()).toEqual( '<img src="unsafe:javascript:true">', ); expect(() => ɵɵsanitizeHtml(bypassSanitizationTrustUrl('<img src="javascript:true">')), ).toThrowError(/Required a safe HTML, got a URL/); expect( ɵɵsanitizeHtml(bypassSanitizationTrustHtml('<img src="javascript:true">')).toString(), ).toEqual('<img src="javascript:true">'); }); it('should not sanitize html sinks on concrete hosts with no HTML context', () => { const html = '<script>evil</script><p>safe</p>'; expect(ɵɵsanitizeHtml(html, 'div', 'srcdoc')).toBe(html); expect(ɵɵsanitizeHtml(html, 'iframe', 'srcdoc').toString()).toBe('<p>safe</p>'); }); it('should sanitize url', () => { expect(ɵɵsanitizeUrl('http://server')).toEqual('http://server'); expect(ɵɵsanitizeUrl(new Wrap('http://server'))).toEqual('http://server'); expect(ɵɵsanitizeUrl('javascript:true')).toEqual('unsafe:javascript:true'); expect(ɵɵsanitizeUrl(new Wrap('javascript:true'))).toEqual('unsafe:javascript:true'); expect(() => ɵɵsanitizeUrl(bypassSanitizationTrustHtml('javascript:true'))).toThrowError( /Required a safe URL, got a HTML/, ); expect(ɵɵsanitizeUrl(bypassSanitizationTrustUrl('javascript:true'))).toEqual('javascript:true'); }); it('should sanitize resourceUrl', () => { const ERROR = /NG0904: unsafe value used in a resource URL context.*/; expect(() => ɵɵsanitizeResourceUrl('http://server')).toThrowError(ERROR); expect(() => ɵɵsanitizeResourceUrl('javascript:true')).toThrowError(ERROR); expect(() => ɵɵsanitizeResourceUrl(bypassSanitizationTrustHtml('javascript:true')), ).toThrowError(/Required a safe ResourceURL, got a HTML/); expect( ɵɵsanitizeResourceUrl(bypassSanitizationTrustResourceUrl('javascript:true')).toString(), ).toEqual('javascript:true'); }); it('should sanitize style', () => { expect(ɵɵsanitizeStyle('red')).toEqual('red'); expect(ɵɵsanitizeStyle(new Wrap('red'))).toEqual('red'); expect(ɵɵsanitizeStyle('url("http://server")')).toEqual('url("http://server")'); expect(ɵɵsanitizeStyle(new Wrap('url("http://server")'))).toEqual('url("http://server")'); expect(() => ɵɵsanitizeStyle(bypassSanitizationTrustHtml('url("http://server")'))).toThrowError( /Required a safe Style, got a HTML/, ); expect(ɵɵsanitizeStyle(bypassSanitizationTrustStyle('url("http://server")'))).toEqual( 'url("http://server")', ); }); it('should sanitize script', () => { const ERROR = 'NG0905: unsafe value used in a script context'; expect(() => ɵɵsanitizeScript('true')).toThrowError(ERROR); expect(() => ɵɵsanitizeScript('true')).toThrowError(ERROR); expect(() => ɵɵsanitizeScript(bypassSanitizationTrustHtml('true'))).toThrowError( /Required a safe Script, got a HTML/, ); expect(ɵɵsanitizeScript(bypassSanitizationTrustScript('true')).toString()).toEqual('true'); }); it('should select correct sanitizer for URL props', () => { // making sure security schema we have on compiler side is in sync with the `getUrlSanitizer` // runtime function definition const schema = SECURITY_SCHEMA(); const sanitizerNameByContext: Map<number, Function> = new Map([ [SecurityContext.URL, ɵɵsanitizeUrl], [SecurityContext.RESOURCE_URL, ɵɵsanitizeResourceUrl], ]); for (const [prop, nsSchema] of Object.entries(schema)) { for (const [ns, tagSchema] of Object.entries(nsSchema)) { // `getUrlSanitizer` resolves namespaces from the selected runtime `TNode`, so direct // unit tests only cover non-namespaced schema entries. Namespaced host bindings are // covered by acceptance tests. if (ns !== '') { continue; } for (const [tag, context] of Object.entries(tagSchema)) { if (context !== SecurityContext.URL && context !== SecurityContext.RESOURCE_URL) { continue; } expect(getUrlSanitizer(tag, prop)) .withContext(`ns: ${ns}, tag: ${tag}, prop: ${prop}, context: ${context}`) .toEqual(sanitizerNameByContext.get(context)!); } } } }); it('should select URL sanitizer case-insensitively', () => { expect(getUrlSanitizer('IFRAME', 'SRC')).toEqual(ɵɵsanitizeResourceUrl); expect(getUrlSanitizer('IFRAME', 'src')).toEqual(ɵɵsanitizeResourceUrl); expect(getUrlSanitizer('iframe', 'SRC')).toEqual(ɵɵsanitizeResourceUrl); expect(getUrlSanitizer('DiV', 'DaTa')).toBeNull(); expect(getUrlSanitizer('A', 'HREF')).toEqual(ɵɵsanitizeUrl); }); it('should sanitize URL or ResourceURL case-insensitively', () => { const ERROR = /NG0904: unsafe value used in a resource URL context.*/; expect(() => ɵɵsanitizeUrlOrResourceUrl('http://server', 'IFRAME', 'SRC')).toThrowError(ERROR); expect(() => ɵɵsanitizeUrlOrResourceUrl('http://server', 'IFRAME', 'src')).toThrowError(ERROR); expect(() => ɵɵsanitizeUrlOrResourceUrl('http://server', 'iframe', 'SRC')).toThrowError(ERROR); expect(ɵɵsanitizeUrlOrResourceUrl('javascript:true', 'A', 'HREF')).toEqual( 'unsafe:javascript:true', ); }); it('should sanitize resourceUrls via sanitizeUrlOrResourceUrl', () => { const ERROR = /NG0904: unsafe value used in a resource URL context.*/; expect(() => ɵɵsanitizeUrlOrResourceUrl('http://server', 'iframe', 'src')).toThrowError(ERROR); expect(() => ɵɵsanitizeUrlOrResourceUrl('javascript:true', 'iframe', 'src')).toThrowError( ERROR, ); expect(() => ɵɵsanitizeUrlOrResourceUrl(bypassSanitizationTrustHtml('javascript:true'), 'iframe', 'src'), ).toThrowError(/Required a safe ResourceURL, got a HTML/); expect( ɵɵsanitizeUrlOrResourceUrl( bypassSanitizationTrustResourceUrl('javascript:true'), 'iframe', 'src', ).toString(), ).toEqual('javascript:true'); }); it('should sanitize urls via sanitizeUrlOrResourceUrl', () => { expect(ɵɵsanitizeUrlOrResourceUrl('http://server', 'a', 'href')).toEqual('http://server'); expect(ɵɵsanitizeUrlOrResourceUrl(new Wrap('http://server'), 'a', 'href')).toEqual( 'http://server', ); expect(ɵɵsanitizeUrlOrResourceUrl('javascript:true', 'a', 'href')).toEqual( 'unsafe:javascript:true', ); expect(ɵɵsanitizeUrlOrResourceUrl(new Wrap('javascript:true'), 'a', 'href')).toEqual( 'unsafe:javascript:true', ); expect(() => ɵɵsanitizeUrlOrResourceUrl(bypassSanitizationTrustHtml('javascript:true'), 'a', 'href'), ).toThrowError(/Required a safe URL, got a HTML/); expect( ɵɵsanitizeUrlOrResourceUrl(bypassSanitizationTrustUrl('javascript:true'), 'a', 'href'), ).toEqual('javascript:true'); expect(ɵɵsanitizeUrlOrResourceUrl('javascript:true', 'div', 'data')).toBe('javascript:true'); }); it('should only trust constant strings from template literal tags without interpolation', () => { expect(ɵɵtrustConstantHtml`<h1>good</h1>`.toString()).toEqual('<h1>good</h1>'); expect(ɵɵtrustConstantResourceUrl`http://good.com`.toString()).toEqual('http://good.com'); expect(() => (ɵɵtrustConstantHtml as any)`<h1>${'evil'}</h1>`).toThrowError( /Unexpected interpolation in trusted HTML constant/, ); expect(() => (ɵɵtrustConstantResourceUrl as any)`http://${'evil'}.com`).toThrowError( /Unexpected interpolation in trusted URL constant/, ); }); });