feat(security): add tests for URL sanitization.
This commit is contained in:
parent
7b6c4d5acc
commit
7a524e3deb
|
@ -89,6 +89,14 @@ const HTML_ATTRS =
|
||||||
'scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,' +
|
'scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,' +
|
||||||
'valign,value,vspace,width');
|
'valign,value,vspace,width');
|
||||||
|
|
||||||
|
// NB: This currently conciously doesn't support SVG. SVG sanitization has had several security
|
||||||
|
// issues in the past, so it seems safer to leave it out if possible. If support for binding SVG via
|
||||||
|
// innerHTML is required, SVG attributes should be added here.
|
||||||
|
|
||||||
|
// NB: Sanitization does not allow <form> elements or other active elements (<button> etc). Those
|
||||||
|
// can be sanitized, but they increase security surface area without a legitimate use case, so they
|
||||||
|
// are left out here.
|
||||||
|
|
||||||
const VALID_ATTRS = merge(URI_ATTRS, HTML_ATTRS);
|
const VALID_ATTRS = merge(URI_ATTRS, HTML_ATTRS);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -99,6 +107,9 @@ class SanitizingHtmlSerializer {
|
||||||
private buf: string[] = [];
|
private buf: string[] = [];
|
||||||
|
|
||||||
sanitizeChildren(el: Element): string {
|
sanitizeChildren(el: Element): string {
|
||||||
|
// This cannot use a TreeWalker, as it has to run on Angular's various DOM adapters.
|
||||||
|
// However this code never accesses properties off of `document` before deleting its contents
|
||||||
|
// again, so it shouldn't be vulnerable to DOM clobbering.
|
||||||
let current: Node = el.firstChild;
|
let current: Node = el.firstChild;
|
||||||
while (current) {
|
while (current) {
|
||||||
if (DOM.isElementNode(current)) {
|
if (DOM.isElementNode(current)) {
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
import * as t from '@angular/core/testing/testing_internal';
|
||||||
|
import {sanitizeUrl} from '../../src/security/url_sanitizer';
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
t.describe('URL sanitizer', () => {
|
||||||
|
t.describe('valid URLs', () => {
|
||||||
|
const validUrls = [
|
||||||
|
'',
|
||||||
|
'http://abc',
|
||||||
|
'HTTP://abc',
|
||||||
|
'https://abc',
|
||||||
|
'HTTPS://abc',
|
||||||
|
'ftp://abc',
|
||||||
|
'FTP://abc',
|
||||||
|
'mailto:me@example.com',
|
||||||
|
'MAILTO:me@example.com',
|
||||||
|
'tel:123-123-1234',
|
||||||
|
'TEL:123-123-1234',
|
||||||
|
'#anchor',
|
||||||
|
'/page1.md',
|
||||||
|
'http://JavaScript/my.js'
|
||||||
|
];
|
||||||
|
for (let url of validUrls) {
|
||||||
|
t.it(`valid ${url}`, () => t.expect(sanitizeUrl(url)).toEqual(url));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
t.describe('invalid URLs', () => {
|
||||||
|
const invalidUrls = [
|
||||||
|
'javascript:evil()',
|
||||||
|
'JavaScript:abc',
|
||||||
|
'evilNewProtocol:abc',
|
||||||
|
' \n Java\n Script:abc',
|
||||||
|
'javascript:',
|
||||||
|
'javascript:',
|
||||||
|
'j avascript:',
|
||||||
|
'javascript:',
|
||||||
|
'javascript:',
|
||||||
|
'jav	ascript:alert();',
|
||||||
|
'jav\u0000ascript:alert();',
|
||||||
|
];
|
||||||
|
for (let url of invalidUrls) {
|
||||||
|
t.it(`valid ${url}`, () => t.expect(sanitizeUrl(url)).toMatch(/^unsafe:/));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue