-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Type checking with security sanitization in place #28
Comments
I've got something really hacky working by just checking the names of the types, rather than needing to have a reference to the proper types. The core of the check is roughly: const securityOverrideMap = {
'iframe': {
'src': ['TrustedResourceUrl'],
},
'a': {
'href': ['TrustedResourceUrl', 'SafeUrl', 'string'],
},
'img': {
'src': ['TrustedResourceUrl', 'SafeUrl', 'string'],
},
// ... etc
};
const globalSecurityOverrides = {
'style': ['SafeStyle', 'string'],
};
function checkSecurityAssignability(typeB, htmlAttr, document) {
const overrideNode = securityOverrideMap[htmlAttr.htmlNode.tagName];
const overriddenTypes = (overrideNode && overrideNode[htmlAttr.name]) || (globalSecurityOverrides[htmlAttr.name]);
if (!overriddenTypes) {
return undefined;
}
if (!matchOverriddenTypes(overriddenTypes, typeB)) {
return [{
kind: exports.LitHtmlDiagnosticKind.INVALID_ATTRIBUTE_EXPRESSION_TYPE,
message:
`Type '${tsSimpleType.toTypeString(typeB)}' is not assignable to '${
overriddenTypes.join(' | ')}'.`,
severity: 'error',
location: {document, ...htmlAttr.location.name},
htmlAttr,
typeB
}];
}
return [];
}
function matchOverriddenTypes(typeNames, typeB) {
if (typeNames.includes(typeB.name)) {
return true;
}
switch (typeB.kind) {
case 'UNION':
return typeB.types.every((t) => matchOverriddenTypes(typeNames, t));
case 'STRING_LITERAL':
case 'STRING':
return typeNames.includes('string');
default:
return false;
}
} |
I would like to start making progress on this issue now. Before I start, I have some thoughts/questions that I want to clarify:
|
Sweet! Fair warning, things are a little up in the air still with trusted types, so depending on how much we want to keep iterating on this it might make sense to wait for them to stabilize a bit more before landing this.
One subtle thing is that the security types should only apply to data bindings. So this is fine, because the url is from a programmer-written constant: html`
<script src="/foo.js"></script>
`; But this should be rejected, because there's no way for the runtime to tell that the url doesn't come from untrusted resource: const url = '/foo.js';
html`
<script src="${url}"></script>
`; |
Related bug: microsoft/TypeScript#30024 |
This is crashing when comparing an instance of an empty class against a primitive type (e.g. a boolean). Showed up in writing tests for runem/lit-analyzer#28
When running in an environment with https://github.com/WICG/trusted-types* the types of some security sensitive built-in attributes and properties are effectively changed. For example, an iframe's src isn't string, but TrustedUrl.
Full list of overrides here: https://wicg.github.io/trusted-types/dist/spec/#enforcement-in-sinks
As the spec isn't yet finalized, the types aren't yet included automatically in the main typings. Further, inside google we use a slightly different system for the time being based on closure library types (e.g. https://google.github.io/closure-library/api/goog.html.SafeUrl.html).
Type typing these with these types doesn't have to be perfect, the canonical security layer is at runtime.
*or when running lit-html with lit/lit#750 enabled, which is kinda-sorta a ponyfill of the trusted types spec purely for lit-html templates
The text was updated successfully, but these errors were encountered: