mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
fix(core): sanitize translated attribute bindings with interpolations
Fixes that we weren't sanitizing attribute bindings with interpolations if they're marked for translation, for example: `<a href="{{evilLink}}" i18n-href></a>`.
Also adds a bit more test coverage for our sanitization.
This commit is contained in:
committed by
Matthew Beck (Berry)
parent
a55475992b
commit
b89b0a83a4
@@ -388,7 +388,7 @@ export function i18nAttributesFirstPass(tView: TView, index: number, values: str
|
||||
previousElementIndex,
|
||||
attrName,
|
||||
countBindings(updateOpCodes),
|
||||
null,
|
||||
URI_ATTRS[attrName.toLowerCase()] ? _sanitizeUrl : null,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -810,18 +810,14 @@ function walkIcuTree(
|
||||
const hasBinding = !!attr.value.match(BINDING_REGEXP);
|
||||
if (hasBinding) {
|
||||
if (VALID_ATTRS.hasOwnProperty(lowerAttrName)) {
|
||||
if (URI_ATTRS[lowerAttrName]) {
|
||||
generateBindingUpdateOpCodes(
|
||||
update,
|
||||
attr.value,
|
||||
newIndex,
|
||||
attr.name,
|
||||
0,
|
||||
_sanitizeUrl,
|
||||
);
|
||||
} else {
|
||||
generateBindingUpdateOpCodes(update, attr.value, newIndex, attr.name, 0, null);
|
||||
}
|
||||
generateBindingUpdateOpCodes(
|
||||
update,
|
||||
attr.value,
|
||||
newIndex,
|
||||
attr.name,
|
||||
0,
|
||||
URI_ATTRS[lowerAttrName] ? _sanitizeUrl : null,
|
||||
);
|
||||
} else {
|
||||
ngDevMode &&
|
||||
console.warn(
|
||||
|
||||
@@ -3605,6 +3605,71 @@ describe('runtime i18n', () => {
|
||||
'translatedText value',
|
||||
);
|
||||
});
|
||||
|
||||
describe('attribute sanitization', () => {
|
||||
@Component({template: ''})
|
||||
class SanitizeAppComp {
|
||||
url = 'javascript:alert("oh no")';
|
||||
count = 0;
|
||||
}
|
||||
|
||||
it('should sanitize translated attribute binding', () => {
|
||||
const fixture = initWithTemplate(SanitizeAppComp, '<a [attr.href]="url" i18n-href></a>');
|
||||
const link: HTMLAnchorElement = fixture.nativeElement.querySelector('a');
|
||||
expect(link.getAttribute('href')).toMatch(/^unsafe:/);
|
||||
});
|
||||
|
||||
it('should sanitize translated property binding', () => {
|
||||
const fixture = initWithTemplate(SanitizeAppComp, '<a [href]="url" i18n-href></a>');
|
||||
const link: HTMLAnchorElement = fixture.nativeElement.querySelector('a');
|
||||
expect(link.getAttribute('href')).toMatch(/^unsafe:/);
|
||||
});
|
||||
|
||||
it('should sanitize translated interpolation', () => {
|
||||
const fixture = initWithTemplate(SanitizeAppComp, '<a href="{{url}}" i18n-href></a>');
|
||||
const link: HTMLAnchorElement = fixture.nativeElement.querySelector('a');
|
||||
expect(link.getAttribute('href')).toMatch(/^unsafe:/);
|
||||
});
|
||||
|
||||
it('should sanitize interpolation inside translated element', () => {
|
||||
const fixture = initWithTemplate(SanitizeAppComp, `<div i18n><a href="{{url}}"></a></div>`);
|
||||
const link: HTMLAnchorElement = fixture.nativeElement.querySelector('a');
|
||||
expect(link.getAttribute('href')).toMatch(/^unsafe:/);
|
||||
});
|
||||
|
||||
it('should sanitize attribute binding inside translated element', () => {
|
||||
const fixture = initWithTemplate(
|
||||
SanitizeAppComp,
|
||||
`<div i18n><a [attr.href]="url"></a></div>`,
|
||||
);
|
||||
const link: HTMLAnchorElement = fixture.nativeElement.querySelector('a');
|
||||
expect(link.getAttribute('href')).toMatch(/^unsafe:/);
|
||||
});
|
||||
|
||||
it('should sanitize property binding inside translated element', () => {
|
||||
const fixture = initWithTemplate(SanitizeAppComp, `<div i18n><a [href]="url"></a></div>`);
|
||||
const link: HTMLAnchorElement = fixture.nativeElement.querySelector('a');
|
||||
expect(link.getAttribute('href')).toMatch(/^unsafe:/);
|
||||
});
|
||||
|
||||
it('should sanitize property binding inside an ICU', () => {
|
||||
const fixture = initWithTemplate(
|
||||
SanitizeAppComp,
|
||||
`<div i18n>{count, plural,
|
||||
=0 {no <strong>link</strong> yet}
|
||||
other {{{count}} Here is the <a href="{{url}}">link</a>!}
|
||||
}</div>`,
|
||||
);
|
||||
|
||||
expect(fixture.nativeElement.querySelector('a')).toBeFalsy();
|
||||
|
||||
fixture.componentInstance.count = 1;
|
||||
fixture.detectChanges();
|
||||
const link: HTMLAnchorElement = fixture.nativeElement.querySelector('a');
|
||||
expect(link).toBeTruthy();
|
||||
expect(link.getAttribute('href')).toMatch(/^unsafe:/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function initWithTemplate(compType: Type<any>, template: string) {
|
||||
|
||||
Reference in New Issue
Block a user