Skip to content

Commit 67ed2e2

Browse files
committed
feat(security): fill in missing security contexts.
Reviewers: koto, rjamet, molnarg Differential Revision: https://reviews.angular.io/D109
1 parent 6d36a7a commit 67ed2e2

File tree

2 files changed

+59
-7
lines changed

2 files changed

+59
-7
lines changed

modules/@angular/compiler/src/schema/dom_element_schema_registry.ts

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,53 @@ var attrToPropMap: {[name: string]: string} = <any>{
206206
'tabindex': 'tabIndex'
207207
};
208208

209+
function registerContext(map: {[k: string]: SecurityContext}, ctx: SecurityContext, specs: string[]) {
210+
for (let spec of specs) map[spec] = ctx;
211+
}
212+
213+
/** Map from tagName|propertyName SecurityContext. Properties applying to all tags use '*'. */
214+
const SECURITY_SCHEMA: {[k: string]: SecurityContext} = {};
215+
216+
registerContext(SECURITY_SCHEMA, SecurityContext.HTML, [
217+
'iframe|srcdoc',
218+
'*|innerHTML',
219+
'*|outerHTML',
220+
]);
221+
registerContext(SECURITY_SCHEMA, SecurityContext.STYLE, ['*|style']);
222+
// NB: no SCRIPT contexts here, they are never allowed.
223+
registerContext(SECURITY_SCHEMA, SecurityContext.URL, [
224+
'area|href',
225+
'area|ping',
226+
'audio|src',
227+
'a|href',
228+
'a|ping',
229+
'blockquote|cite',
230+
'body|background',
231+
'button|formaction',
232+
'del|cite',
233+
'form|action',
234+
'img|src',
235+
'input|formaction',
236+
'input|src',
237+
'ins|cite',
238+
'q|cite',
239+
'source|src',
240+
'video|poster',
241+
'video|src',
242+
]);
243+
registerContext(SECURITY_SCHEMA, SecurityContext.RESOURCE_URL, [
244+
'applet|code',
245+
'applet|codebase',
246+
'base|href',
247+
'frame|src',
248+
'head|profile',
249+
'html|manifest',
250+
'iframe|src',
251+
'object|codebase',
252+
'object|data',
253+
'script|src',
254+
'track|src',
255+
]);
209256

210257
@Injectable()
211258
export class DomElementSchemaRegistry extends ElementSchemaRegistry {
@@ -267,11 +314,10 @@ export class DomElementSchemaRegistry extends ElementSchemaRegistry {
267314
* attack vectors are assigned their appropriate context.
268315
*/
269316
securityContext(tagName: string, propName: string): SecurityContext {
270-
// TODO(martinprobst): Fill in missing properties.
271-
if (propName === 'style') return SecurityContext.STYLE;
272-
if (tagName === 'a' && propName === 'href') return SecurityContext.URL;
273-
if (propName === 'innerHTML') return SecurityContext.HTML;
274-
return SecurityContext.NONE;
317+
let ctx = SECURITY_SCHEMA[tagName + '|' + propName];
318+
if (ctx !== undefined) return ctx;
319+
ctx = SECURITY_SCHEMA['*|' + propName];
320+
return ctx !== undefined ? ctx : SecurityContext.NONE;
275321
}
276322

277323
getMappedPropName(propName: string): string {

modules/@angular/compiler/test/schema/dom_element_schema_registry_spec.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,14 @@ export function main() {
5757
expect(registry.getMappedPropName('exotic-unknown')).toEqual('exotic-unknown');
5858
});
5959

60-
it('should return security contexts for elements',
61-
() => { expect(registry.securityContext('a', 'href')).toBe(SecurityContext.URL); });
60+
it('should return security contexts for elements', () => {
61+
expect(registry.securityContext('iframe', 'srcdoc')).toBe(SecurityContext.HTML);
62+
expect(registry.securityContext('p', 'innerHTML')).toBe(SecurityContext.HTML);
63+
expect(registry.securityContext('a', 'href')).toBe(SecurityContext.URL);
64+
expect(registry.securityContext('a', 'style')).toBe(SecurityContext.STYLE);
65+
expect(registry.securityContext('ins', 'cite')).toBe(SecurityContext.URL);
66+
expect(registry.securityContext('base', 'href')).toBe(SecurityContext.RESOURCE_URL);
67+
});
6268

6369
it('should detect properties on namespaced elements',
6470
() => { expect(registry.hasProperty('@svg:g', 'id')).toBeTruthy(); });

0 commit comments

Comments
 (0)