To protect users from being served malicious HTML or JavaScript, Apps Script uses a security sandbox to to sandbox HTML-service web apps or custom user interfaces for Google Docs, Sheets, and Forms. (The HTML service does not use a sandbox in other situations, like generating the body of an email.) The sandbox imposes limitations on client-side code.
Sandbox Mode
You can use the
setSandboxMode
method to choose between
three versions of the HTML service
security sandbox.
IFRAME
mode imposes many fewer restrictions than the other sandbox modes and
runs fastest, but does not work at all in certain older browsers, including
Internet Explorer 9. By contrast, EMULATED
mode is more likely to work in
older browsers that do not support ECMAScript 5 strict mode,
most notably Internet Explorer 9. NATIVE
mode is the middle ground. If
NATIVE
mode is set but not supported in the user's browser, the sandbox falls
back to EMULATED
mode for that user.
If a script does not set a sandbox mode, Apps Script uses NATIVE
mode as the
default. Prior to February 2014, the default was EMULATED
. The default is
subject to change.
The example below shows how to set the sandbox mode, as well as how to determine
which sandbox mode the browser is actually using by inspecting the property
google.script.sandbox.mode
.
Code.gs | index.html |
---|---|
function doGet() { return HtmlService.createHtmlOutputFromFile('index') .setSandboxMode(HtmlService.SandboxMode.IFRAME); } |
<script> alert(google.script.sandbox.mode); </script> |
Restrictions in IFRAME mode
The IFRAME
sandbox mode is based on the
iframe sandboxing feature
in HTML5, using the allow-same-origin
, allow-forms
, allow-scripts
, and
allow-popups
keywords.
HTTPS required for active content
"Active" content like scripts, external stylesheets, and XmlHttpRequests must be loaded over HTTPS, not HTTP.
Restrictions in NATIVE and EMULATED mode
The NATIVE
and EMULATED
sandbox modes are based on the
Caja Compiler. Caja’s sanitization
process detects some security violations before even showing the page, and an
in-browser sandbox prevents other actions on the fly. Caja sanitization imposes
more limitations on client-side code than the IFRAME
sandbox does.
HTML
The HTML service produces HTML5 web pages, but only from a markup perspective. In other words, the HTML service supports most HTML5 elements and attributes, but not new APIs like web storage.
Naming restrictions
Like CSS and client-side JavaScript identifiers, no element’s name or ID can end
with __
(two underscores).
Element restrictions
Although embed
, iframe
, and object
elements are technically supported,
their content is severely restricted; in practical terms, you cannot use these
elements.
Anchor tags
Anchor tags in HTML-service pages partially hide the referer from the link's destination. If you link to a page on another server that logs its referers, that server will know that the link came from the Apps Script server, but not from which script specifically.
Also, anchor tags in web apps can only set the _blank
and _self
targets.
Anchor tags in custom user interfaces for Google Docs, Sheets, or Forms can only
set the _blank
target.
Forms
Apps Script allows HTML forms to submit either back to the script or to another server, but, as with anchor tags, forms partially hide the referer from the form’s destination. Thus, if you submit a form to a page on another server that logs its referers, that server will know that the form came from the Apps Script server, but not from which script specifically.
If you’re submitting a form to Apps Script and want to receive an AJAX-like
response without redirecting the page, use the special syntax described in the
forms section of the
google.script
guide.
CSS
A small number of restrictions apply to CSS in HTML-service pages.
Adding CSS dynamically
In the EMULATED
sandbox mode, scripts cannot add link
elements at runtime
that load in new external stylesheets after Caja has already processed the page.
This restriction does not apply in NATIVE
mode.
Naming restrictions
As with HTML elements and client-side JavaScript identifiers, CSS identifiers
cannot end with __
(two underscores).
Double-colon notation
Pseudo-selectors that use double-colon notation (like ::after
) are not
currently supported. Instead, use the single-colon equivalent (like :after
).
Fixed positioning
The CSS declaration position: fixed
is not allowed.
Orphans and widows
The orphans
and widows
properties are not allowed.
Nth-child
The :nth-child()
pseudo-selector is not currently supported.
Obscure CSS3 features
A few obscure or non-standardized CSS3 features are not supported. To check whether Caja supports a specific feature, see the CSS whitelist definitions in Caja's public repository. Additionally, Caja supports some CSS3 properties but not all values for those properties, which may not be obvious from the whitelists. It's usually simplest just to try using the property or value you want, then inspect the rendered page to see whether the CSS made it through.
JavaScript
Rewritten code
In the EMULATED
sandbox mode, Caja inspects and substantially rewrites all
HTML and JavaScript before the page loads. This results in a substantial
slowdown in loading times relative to the newer NATIVE
mode. Because code is
rewritten, it also becomes difficult to debug.
In NATIVE
mode, although comments are still stripped from client-side code,
the code is only rewritten if it contains variables or named functions at the
top level, or if it uses the typeof
operator to refer to a variable directly.
The examples below show how to avoid code rewrites in NATIVE
mode.
✘Don't — code will be rewritten | ✓Do — code will not be
rewritten in NATIVE mode |
---|---|
<script> var x = 3; function foo() { ... } </script> |
<script> window.x = 3; window.foo = function() { ... }; </script> |
<script> if (typeof y === 'undefined') { ... } function bar(a) { if (typeof a === 'object') { ... } } </script> |
<script> if (typeof window.y === 'undefined') { ... } function bar(a) { var o = { a: a }; if (typeof o.a === 'object') { ... } } </script> |
Strict mode
Client-side JavaScript in HTML-service pages must use
“strict” JavaScript,
which, among other things, requires that variables be declared before use,
forbids the with
keyword and delete variable
(while still allowing
delete object.property
), and removes the arguments.callee
reference within
functions. In addition, your code cannot use eval
(even though strict mode
normally allows it). Note that these restrictions apply even if the user’s
browser doesn't natively support strict mode. The use strict
directive is
optional, although still good practice.
Adding scripts dynamically
In the EMULATED
sandbox mode, scripts cannot insert other scripts at runtime.
All JavaScript code must be available during the pre-processing stage to ensure
it complies with the security constraints. This imposes several restrictions:
scripts cannot create script
elements; scripts cannot dynamically add
statements to a button's onclick
attribute (although they can add the name of
an existing function to the onclick
attribute); and the
JSONP technique is not allowed (although
XMLHttpRequests are allowed). None of these restrictions
apply in NATIVE
mode.
External JavaScript libraries
You can include external JavaScript libraries in your code via script
elements
as you would expect. These libraries are subject to the same sandbox
restrictions and potential rewriting as your own client-side code; many
JavaScript libraries work, but not all will. Complex libraries are more likely
to work in NATIVE
mode than in EMULATED
mode.
jQuery and jQuery UI
All recent versions of the jQuery and jQuery UI libraries are compatible with Caja, but the libraries load faster if you use the versions that Google hosts:
- jQuery:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
- jQuery UI:
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.9.1/jquery-ui.min.js"></script>
Browser access
Your JavaScript does not have full access to the surrounding browser. You
cannot, for example, read cookies, navigate the history, or set the title of the
window (although you can set it initially via the HtmlOutput
object’s
setTitle()
method).
Naming restrictions
As with CSS and HTML elements, no identifier in client scripts can end with __
(two underscores). Because this restriction does not apply in server-side Apps
Script code, it’s important to make sure that you don't send objects from the
server to the client that contain illegal properties. If you use a JavaScript
object as a map from strings to objects, where the keys are potentially any
strings, append a character of your own to the end of each string so that you
don't unexpectedly use an illegal key.
Primitives
Your code cannot reassign JavaScript primitive objects such as Array
,
Boolean
, Infinity
, NaN
, Number
, Object
, RegExp
, and String
, and
cannot assign new properties to these objects or their prototypes.
document.documentElement
In EMULATED
mode, document.documentElement
is null
if a page contains only
script
or style
elements.
Error objects
The stack
property of Error
objects is always undefined
.
WeakMap
The WeakMap
object is provided in Caja even though it is not part of ECMAScript 5.
HTTP
Cookies
Because the HTML service cannot read or transmit cookies, externally hosted scripts and other resources referenced in HTML files must be publicly accessible without authentication cookies.
URL proxying
Caja proxies most content retrieved via URL (including external URLs specified
in img
, link
, or script
elements) and may modify or disallow requests for
security reasons. The limitations are more strict in EMULATED
mode.
XMLHttpRequests (XHR)
XMLHttpRequests to other servers are allowed — either without authentication or
using an authorization
header — provided those servers set appropriate
CORS headers and are willing to accept requests
from outside their domain. The syntax for XHRs is standardized to use
XMLHttpRequest
even in Internet Explorer. However, the method
getResponseXML()
is not supported.
XHR requests to the Google Apps Script server are forbidden, but you can use
google.script.run
to make AJAX-like
requests to your script instead.