UNPKG

node-phonenumber

Version:

Google's phone number handling library ported to Node

393 lines (280 loc) 14.2 kB
--- title: JavaScript Conformance Rules for Closure Library section: develop layout: article --- <!-- Documentation licensed under CC BY 4.0 --> <!-- License available at https://creativecommons.org/licenses/by/4.0/ --> # JavaScript Conformance Rules for Closure Library The config file: [closure/goog/conformance\_proto.txt](https://github.com/google/closure-library/tree/master/closure/goog/conformance_proto.txt) ## Introduction Closure JavaScript code is expected to conform to a set of rules for security, performance, code health, or other reasons. This configuration file for the [JS Conformance Framework] enforces this. The security-specific rules in here mostly target DOM (and Closure) APIs that are prone to script-injection vulnerabilities ([XSS]). In these cases, the rules will point to wrapper APIs that, instead of plain strings, consume values of types with specific security contracts indicating that the value can be safely used in a given context. ## Possible Violations If you are adding code and the warning you are seeing doesn’t seem appropriate and the warning is a "Possible Violation" then the compiler doesn’t have enough type information to confirm that you aren’t violating a rule. As noted in the [JS Conformance Framework] documentation, conformance rules are enforced strictly so you aren’t allowed to "possibly violate". The fix is to change the code to so that sufficient type information is available. ## How to fix possible violations Removing false-positive 'possible violations' requires providing more type-information. Often this is as simple as declaring array content types or tightening an APIs return type or choosing a different API. For example, many Closure DOM APIs return a precise type if passed a `goog.dom.TagName` instance. Passing this instance instead of a string solves many possible violations. Examples: ```js // Possible violation. var img = goog.dom.createDom('img'); img.src = src; // Clean. var img = goog.dom.createDom(goog.dom.TagName.IMG); img.src = src; // Build error - native APIs don't support goog.dom.TagName. var img = document.createElement(goog.dom.TagName.IMG); img.src = src; ``` ```js // Possible violation. var img = goog.dom.getElementByClass('avatar'); img.src = src; // Clean. var img = goog.dom.getElementByTagNameAndClass(goog.dom.TagName.IMG, 'avatar'); img.src = src; ``` ```js // Possible violation. var img = goog.dom.getElement('avatar'); img.src = src; // Clean. var img = goog.dom.asserts.assertIsHTMLImageElement(goog.dom.getElement('avatar')); img.src = src; // No violation but unsafe - see below. var img = /** @type {!HTMLImageElement} */ (goog.dom.getElement('avatar')); img.src = src; ``` Summing it up: * Use `goog.dom` functions with `goog.dom.TagName` instances. * Use `getElementByTagNameAndClass`. * Use `goog.dom.asserts` if there's no better API. * Avoid type-casting as there's no check whether you actually cast a correct type - it means that you can cast `HTMLScriptElement` typed as `Element` to `HTMLImageElement`. ## Explanation of conformance rules ### goog.base goog.base is not compatible with EcmaScript 5+ strict mode. As part of the migration to strict mode Closure Library has moved away from goog.base and instead uses the "base" method defined on the class constructor by goog.inherits. Calling a super class constructor: ```js var MyClass = function(arg) { MyClass.base(this, 'constructor', arg); }; ``` Calling a super class method: ```js MyClass.prototype.method = function(arg) { MyClass.base(this, 'method', arg); } ``` {: #logger} ### goog.debug.Logger goog.debug.Logger should not be used directly. Instead use the goog.log static wrappers. goog.log is safely strippable from production code. However, goog.debug.Logger is only stripped from code if the logger\_ suffix is used in the name. Note: You may see "possible violations" for code that is not a logger if the code is badly typed. Verify that you have a dependency on the type you are expecting. ### eval eval is a security risk and is not allowed to be used. Since values passed to eval() are evaluated and executed as any ordinary JavaScript, it is not inherently safe to pass content to eval(). Eval() is typically not necessary for ordinary programming. IE's `execScript` is also banned. `Function`, `setTimeout`, `setInterval` and `requestAnimationFrame` with string argument are also banned. {: #throwOfNonErrorTypes} ### throw 'message' `throw` with a string literal can not have a stack trace attached to it, making debugging significantly more difficult. Use `throw new Error('message')` instead. {: #callee} ### Arguments.prototype.callee `Arguments.prototype.callee` is not allowed in EcmaScript "[strict mode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode)" code. {: #documentWrite} ### Calls to Document.prototype.write Calling `Document.prototype.write` is a security risk and is banned. Any content passed to `write()` will be automatically evaluated in the DOM and therefore the assignment of user-controlled, insufficiently sanitized or escaped content can result in [XSS] vulnerabilities. `Document.prototype.write` is bad for performance as it forces document reparsing, has unpredictable semantics and disallows many optimizations a browser may make. It is almost never needed. Only exception is writing to a completely new window such as a popup or an iframe. If you need to use it, use the type-safe [`goog.dom.safe.documentWrite`] wrapper, or directly render a Strict Soy template using [`goog.soy.Renderer.prototype.renderElement`] or similar. {: #innerHtml} ### Assignment to Element.prototype.innerHTML/outerHTML Direct assignment of a non-constant value to `innerHTML` and `outerHTML` is a security risk and is banned. Any content passed to `innerHTML` or `outerHTML` will be automatically evaluated in the DOM and therefore the assignment of user-controlled, insufficiently sanitized or escaped content can result in [XSS] vulnerabilities. Instead, use the type-safe [`goog.dom.safe.setInnerHtml`] wrapper, or directly render a Strict Soy template using [`goog.soy.Renderer.prototype.renderElement`] (or similar). Note: Reads of these properties are permitted. {: #untypedElements} ### Creating untyped elements is forbidden We have several conformance rules banning assignment to dangerous properties such as `script.src`. These rules work only if we know the type of the manipulated element, e.g. `HTMLScriptElement`. Sadly, `document.createElement('script')` and similar return only `Element` as perceived by JS Compiler. For our rules to work, we need to know the exact type which is returned by `goog.dom` methods when used together with `goog.dom.TagName`. Typically, it's `goog.dom.createElement` and `goog.dom.createDom` but other methods such as `goog.dom.getElementsByTagName` also work. `DomHelper` counterparts of these methods support `goog.dom.TagName` too. For this reason, we ban creating untyped `'script'`, `'iframe'`, `'frame'`, `'embed'`, and `'object'` elements and require using `goog.dom` methods with `goog.dom.TagName` with them. {: #soyDeprecatedAutoescaping} ### Non-strict escaping in Soy templates Rendering non-strict templates is prohibited for security reasons. We check if functions `soy.renderAsElement`, `soy.renderAsFragment` and `soy.renderElement` plus their versions in `goog.soy` and `goog.soy.Renderer` are called with strict-autoescaping templates. Calling them with non-strict templates is banned. This violation might be a false positive if you pass strict templates around with type `{Function}` or `function(): *`. Pass them with type `{goog.soy.StrictTemplate}` instead. {: #location} ### Assignment to Location.prototype.href and Window.prototype.location Direct assignment of a non-constant value to `Location.prototype.href` and `Window.prototype.location` is a security risk and is banned. Externally controlled strings assigned to `Location.href` can result in [XSS] vulnerabilities, e.g. via "`javascript:evil()`" URLs. Instead of directly assigning to Location.prototype.href or Window.prototype.location, use the safe wrapper function [`goog.dom.safe.setLocationHref`]. When passed a string, this wrapper sanitizes the URL before passing it to the underlying DOM property. If passed a value of type`goog.html.SafeUrl`, the value is assigned without further sanitization. Note: Reads of this property are permitted. {: #href} ### Assignment to .href property of Anchor, Link, etc elements Direct assignment of a non-constant value to the href property of Anchor, Link, and similar elements is a security risk and is banned. Externally controlled strings assigned to the href property can result in [XSS] vulnerabilities, e.g. via "javascript:evil()" URLs. Instead of directly assigning to the href property, use safe wrapper functions such as [`goog.dom.safe.setAnchorHref`]. When passed a string, this wrapper sanitizes the URL before passing it to the underlying DOM property. If passed a value of type goog.html.SafeUrl, the value is assigned without further sanitization. Note: Reads of this property are permitted. {: #trustedResourceUrl} ### Assignment to property requires a TrustedResourceUrl via goog.dom.safe Assignment of a non-constant value to certain URL-valued properties, like Base.href and Script.src, via a string that is not fully application controlled is a security risk and is banned. Attacker controlled values assigned to these properties can result in loading code from an untrusted domain. For example, the following would be unsafe if www.google.com were to have an open redirector and attackerControlled were something like '../redirect=http://evil.com/evil#': ```js script.src = 'https://www.google.com/module/' + attackerControlled + '.js'; ``` Instead of directly assigning to these properties use safe wrapper functions which take TrustedResourceUrl, such as goog.dom.safe.setScriptSrc. Note: Reads of this property are permitted. {: #createDom} ### Assigning a variable to a dangerous property via createDom is forbidden. `goog.dom.createDom` and its version in `DomHelper` support assigning attributes to the newly created elements. This conformance rule bans assigning attributes that can load attacker controlled code, such as `script.src` or `innerHTML`. To assign these attributes, create the element first and then assign the attribute using `goog.dom.safe` functions like this: ```js var script = goog.dom.createDom(goog.dom.TagName.SCRIPT); goog.dom.safe.setScriptSrc(script, trustedResourceUrl); ``` Alternatively, use a function in `goog.html.SafeHtml` such as `goog.html.SafeHtml.createScriptSrc`. This rule might report a possible violation if the tag name or attributes are not literals. To avoid this possible violation, structure the code like this: ```js // Reports a possible violation. var tag = 'img'; var attrs = {'src': ''}; goog.dom.createDom(tag, attrs); // Passes. goog.dom.createDom('img', {'src': ''}); ``` Note that string literal values assigned to banned attributes are allowed as they couldn't be attacker controlled. {: #scriptContent} ### Setting content of Script element is not allowed Setting content of `<script>` and then appending it to the document has the same effect as calling eval(). This coding pattern is prone to XSS vulnerabilities, and therefore disallowed. {: #postMessage} ### Window.prototype.postMessage Raw "postMessage" can create security vulnerabilities. Use gapi.rpc instead. gapi.rpc conceptually augments window.postmessage with more security and other features. Valid reasons for using raw "postMessage" include when it is used for communication to/from an iframe hosted on the same domain as the page containing the iframe. However, be sure to get a security review to allow usage of this. {: #expose} ### @expose @expose has non-obvious global side-effects that can cause errors. {: #globalVars} ### Global declarations Global functions and var declarations are not allowed, these pollute global scope. Top level namespaces are allowed if declared with "goog.provide" or "goog.module". {: #unknownThis} ### Unknown types Loose types "?" (unknown), "\*" (all), "Object" and "Function" should be used sparingly as they degrade available type information. "?" as a "this" type is forbidden so that accidental unknowns (which are far more common) can be caught. {: #storage} ### Client Side Storage (Closure library specific) Client side storage mechanisms are dangerous because of PII and security implications. TODO(johnlenz): Document what someone submitting code to Closure should in the case they see this warning. {: #legacyApis} ### Unsafe legacy APIs Closure (as well as some libraries built on top of Closure) include several APIs that consume plain strings, and pass them on to an API that process that string in an injection-vulnerability-prone way (most commonly, an assigmnent to `.innerHTML`). Thus, use of such APIs incurs similar risks of injection vulnerabilities as the underlying DOM API (e.g., `innerHTML` assignment). Due to these risks, conformance rules disallow the use of such APIs. The respective conformance rules' error message refers to the equivalent, safe API to use instead. Typically, the safe API consumes values of an appropriate security-contract type such as `goog.html.SafeHtml`. <!-- Links --> [JS Conformance Framework]: https://github.com/google/closure-compiler/wiki/JS-Conformance-Framework [XSS]: https://en.wikipedia.org/wiki/Cross-site_scripting [`goog.dom.safe.documentWrite`]: https://google.github.io/closure-library/api/goog.dom.safe#documentWrite [`goog.dom.safe.setAnchorHref`]: https://google.github.io/closure-library/api/goog.dom.safe#setAnchorHref [`goog.dom.safe.setInnerHtml`]: https://google.github.io/closure-library/api/goog.dom.safe#setInnerHtml [`goog.dom.safe.setLocationHref`]: https://google.github.io/closure-library/api/goog.dom.safe#setLocationHref [`goog.soy.Renderer.prototype.renderElement`]: https://google.github.io/closure-library/api/goog.soy.Renderer#renderElement