Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/html/safescript.js
2868 views
1
// Copyright 2014 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview The SafeScript type and its builders.
17
*
18
* TODO(xtof): Link to document stating type contract.
19
*/
20
21
goog.provide('goog.html.SafeScript');
22
23
goog.require('goog.asserts');
24
goog.require('goog.string.Const');
25
goog.require('goog.string.TypedString');
26
27
28
29
/**
30
* A string-like object which represents JavaScript code and that carries the
31
* security type contract that its value, as a string, will not cause execution
32
* of unconstrained attacker controlled code (XSS) when evaluated as JavaScript
33
* in a browser.
34
*
35
* Instances of this type must be created via the factory method
36
* {@code goog.html.SafeScript.fromConstant} and not by invoking its
37
* constructor. The constructor intentionally takes no parameters and the type
38
* is immutable; hence only a default instance corresponding to the empty string
39
* can be obtained via constructor invocation.
40
*
41
* A SafeScript's string representation can safely be interpolated as the
42
* content of a script element within HTML. The SafeScript string should not be
43
* escaped before interpolation.
44
*
45
* Note that the SafeScript might contain text that is attacker-controlled but
46
* that text should have been interpolated with appropriate escaping,
47
* sanitization and/or validation into the right location in the script, such
48
* that it is highly constrained in its effect (for example, it had to match a
49
* set of whitelisted words).
50
*
51
* A SafeScript can be constructed via security-reviewed unchecked
52
* conversions. In this case producers of SafeScript must ensure themselves that
53
* the SafeScript does not contain unsafe script. Note in particular that
54
* {@code <} is dangerous, even when inside JavaScript strings, and so should
55
* always be forbidden or JavaScript escaped in user controlled input. For
56
* example, if {@code </script><script>evil</script>"} were
57
* interpolated inside a JavaScript string, it would break out of the context
58
* of the original script element and {@code evil} would execute. Also note
59
* that within an HTML script (raw text) element, HTML character references,
60
* such as "<" are not allowed. See
61
* http://www.w3.org/TR/html5/scripting-1.html#restrictions-for-contents-of-script-elements.
62
*
63
* @see goog.html.SafeScript#fromConstant
64
* @constructor
65
* @final
66
* @struct
67
* @implements {goog.string.TypedString}
68
*/
69
goog.html.SafeScript = function() {
70
/**
71
* The contained value of this SafeScript. The field has a purposely
72
* ugly name to make (non-compiled) code that attempts to directly access this
73
* field stand out.
74
* @private {string}
75
*/
76
this.privateDoNotAccessOrElseSafeScriptWrappedValue_ = '';
77
78
/**
79
* A type marker used to implement additional run-time type checking.
80
* @see goog.html.SafeScript#unwrap
81
* @const {!Object}
82
* @private
83
*/
84
this.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
85
goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_;
86
};
87
88
89
/**
90
* @override
91
* @const
92
*/
93
goog.html.SafeScript.prototype.implementsGoogStringTypedString = true;
94
95
96
/**
97
* Type marker for the SafeScript type, used to implement additional
98
* run-time type checking.
99
* @const {!Object}
100
* @private
101
*/
102
goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {};
103
104
105
/**
106
* Creates a SafeScript object from a compile-time constant string.
107
*
108
* @param {!goog.string.Const} script A compile-time-constant string from which
109
* to create a SafeScript.
110
* @return {!goog.html.SafeScript} A SafeScript object initialized to
111
* {@code script}.
112
*/
113
goog.html.SafeScript.fromConstant = function(script) {
114
var scriptString = goog.string.Const.unwrap(script);
115
if (scriptString.length === 0) {
116
return goog.html.SafeScript.EMPTY;
117
}
118
return goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse(
119
scriptString);
120
};
121
122
123
/**
124
* Returns this SafeScript's value as a string.
125
*
126
* IMPORTANT: In code where it is security relevant that an object's type is
127
* indeed {@code SafeScript}, use {@code goog.html.SafeScript.unwrap} instead of
128
* this method. If in doubt, assume that it's security relevant. In particular,
129
* note that goog.html functions which return a goog.html type do not guarantee
130
* the returned instance is of the right type. For example:
131
*
132
* <pre>
133
* var fakeSafeHtml = new String('fake');
134
* fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;
135
* var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);
136
* // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by
137
* // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml
138
* // instanceof goog.html.SafeHtml.
139
* </pre>
140
*
141
* @see goog.html.SafeScript#unwrap
142
* @override
143
*/
144
goog.html.SafeScript.prototype.getTypedStringValue = function() {
145
return this.privateDoNotAccessOrElseSafeScriptWrappedValue_;
146
};
147
148
149
if (goog.DEBUG) {
150
/**
151
* Returns a debug string-representation of this value.
152
*
153
* To obtain the actual string value wrapped in a SafeScript, use
154
* {@code goog.html.SafeScript.unwrap}.
155
*
156
* @see goog.html.SafeScript#unwrap
157
* @override
158
*/
159
goog.html.SafeScript.prototype.toString = function() {
160
return 'SafeScript{' +
161
this.privateDoNotAccessOrElseSafeScriptWrappedValue_ + '}';
162
};
163
}
164
165
166
/**
167
* Performs a runtime check that the provided object is indeed a
168
* SafeScript object, and returns its value.
169
*
170
* @param {!goog.html.SafeScript} safeScript The object to extract from.
171
* @return {string} The safeScript object's contained string, unless
172
* the run-time type check fails. In that case, {@code unwrap} returns an
173
* innocuous string, or, if assertions are enabled, throws
174
* {@code goog.asserts.AssertionError}.
175
*/
176
goog.html.SafeScript.unwrap = function(safeScript) {
177
// Perform additional Run-time type-checking to ensure that
178
// safeScript is indeed an instance of the expected type. This
179
// provides some additional protection against security bugs due to
180
// application code that disables type checks.
181
// Specifically, the following checks are performed:
182
// 1. The object is an instance of the expected type.
183
// 2. The object is not an instance of a subclass.
184
// 3. The object carries a type marker for the expected type. "Faking" an
185
// object requires a reference to the type marker, which has names intended
186
// to stand out in code reviews.
187
if (safeScript instanceof goog.html.SafeScript &&
188
safeScript.constructor === goog.html.SafeScript &&
189
safeScript.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ===
190
goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) {
191
return safeScript.privateDoNotAccessOrElseSafeScriptWrappedValue_;
192
} else {
193
goog.asserts.fail('expected object of type SafeScript, got \'' +
194
safeScript + '\' of type ' + goog.typeOf(safeScript));
195
return 'type_error:SafeScript';
196
}
197
};
198
199
200
/**
201
* Package-internal utility method to create SafeScript instances.
202
*
203
* @param {string} script The string to initialize the SafeScript object with.
204
* @return {!goog.html.SafeScript} The initialized SafeScript object.
205
* @package
206
*/
207
goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse =
208
function(script) {
209
return new goog.html.SafeScript().initSecurityPrivateDoNotAccessOrElse_(
210
script);
211
};
212
213
214
/**
215
* Called from createSafeScriptSecurityPrivateDoNotAccessOrElse(). This
216
* method exists only so that the compiler can dead code eliminate static
217
* fields (like EMPTY) when they're not accessed.
218
* @param {string} script
219
* @return {!goog.html.SafeScript}
220
* @private
221
*/
222
goog.html.SafeScript.prototype.initSecurityPrivateDoNotAccessOrElse_ = function(
223
script) {
224
this.privateDoNotAccessOrElseSafeScriptWrappedValue_ = script;
225
return this;
226
};
227
228
229
/**
230
* A SafeScript instance corresponding to the empty string.
231
* @const {!goog.html.SafeScript}
232
*/
233
goog.html.SafeScript.EMPTY =
234
goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse('');
235
236