105
105
if (!isEnabled())
108
if (findInRequest(code, false, true)) {
110
task.decodeEntities = false;
111
task.allowRequestIfNoIllegalURICharacters = true;
113
if (findInRequest(task)) {
109
114
DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n"));
110
115
m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String());
118
123
if (!isEnabled())
121
if (findInRequest(code, true, false, true)) {
128
task.decodeURLEscapeSequencesTwice = true;
130
if (findInRequest(task)) {
122
131
DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n"));
123
132
m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String());
131
140
if (!isEnabled())
134
if (findInRequest(code, true, true)) {
145
task.allowRequestIfNoIllegalURICharacters = true;
147
if (findInRequest(task)) {
135
148
DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n"));
136
149
m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String());
147
160
if (isSameOriginResource(url))
150
if (findInRequest(context + url)) {
164
task.context = context;
167
if (findInRequest(task)) {
151
168
DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to execute a JavaScript script. Source code of script found within request.\n"));
152
169
m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String());
163
180
if (isSameOriginResource(url))
166
if (findInRequest(url)) {
185
task.allowRequestIfNoIllegalURICharacters = true;
187
if (findInRequest(task)) {
167
188
String consoleMessage = String::format("Refused to load an object. URL found within request: \"%s\".\n", url.utf8().data());
168
189
m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String());
179
200
if (isSameOriginResource(url))
182
if (findInRequest(url)) {
206
if (findInRequest(task)) {
183
207
DEFINE_STATIC_LOCAL(String, consoleMessage, ("Refused to load from document base URL. URL found within request.\n"));
184
208
m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage, 1, String());
265
289
return (m_frame->document()->url().host() == resourceURL.host() && resourceURL.query().isEmpty());
268
bool XSSAuditor::findInRequest(const String& string, bool decodeEntities, bool allowRequestIfNoIllegalURICharacters,
269
bool decodeURLEscapeSequencesTwice) const
292
bool XSSAuditor::findInRequest(const FindTask& task) const
271
294
bool result = false;
272
295
Frame* parentFrame = m_frame->tree()->parent();
273
296
if (parentFrame && m_frame->document()->url() == blankURL())
274
result = findInRequest(parentFrame, string, decodeEntities, allowRequestIfNoIllegalURICharacters, decodeURLEscapeSequencesTwice);
297
result = findInRequest(parentFrame, task);
276
result = findInRequest(m_frame, string, decodeEntities, allowRequestIfNoIllegalURICharacters, decodeURLEscapeSequencesTwice);
299
result = findInRequest(m_frame, task);
280
bool XSSAuditor::findInRequest(Frame* frame, const String& string, bool decodeEntities, bool allowRequestIfNoIllegalURICharacters,
281
bool decodeURLEscapeSequencesTwice) const
303
bool XSSAuditor::findInRequest(Frame* frame, const FindTask& task) const
283
305
ASSERT(frame->document());
290
if (string.isEmpty())
312
if (task.string.isEmpty())
293
315
FormData* formDataObj = frame->loader()->documentLoader()->originalRequest().httpBody();
316
const bool hasFormData = formDataObj && !formDataObj->isEmpty();
294
317
String pageURL = frame->document()->url().string();
296
if (!formDataObj && string.length() >= 2 * pageURL.length()) {
319
String canonicalizedString;
320
if (!hasFormData && task.string.length() > 2 * pageURL.length()) {
297
321
// Q: Why do we bother to do this check at all?
298
322
// A: Canonicalizing large inline scripts can be expensive. We want to
299
// bail out before the call to canonicalize below, which could
300
// result in an unneeded allocation and memcpy.
323
// reduce the size of the string before we call canonicalize below,
324
// since it could result in an unneeded allocation and memcpy.
302
326
// Q: Why do we multiply by two here?
303
327
// A: We attempt to detect reflected XSS even when the server
305
329
// attacker can do get the server to inflate his/her input by a
306
330
// factor of two by sending " characters, which the server
307
331
// transforms to \".
332
canonicalizedString = task.string.substring(0, 2 * pageURL.length());
334
canonicalizedString = task.string;
311
336
if (frame->document()->url().protocolIs("data"))
314
String canonicalizedString = canonicalize(string);
339
canonicalizedString = canonicalize(canonicalizedString);
315
340
if (canonicalizedString.isEmpty())
318
if (string.length() < pageURL.length()) {
319
// The string can actually fit inside the pageURL.
320
String decodedPageURL = m_cache.canonicalizeURL(pageURL, frame->document()->decoder()->encoding(), decodeEntities, decodeURLEscapeSequencesTwice);
322
if (allowRequestIfNoIllegalURICharacters && (!formDataObj || formDataObj->isEmpty())
323
&& decodedPageURL.find(&isIllegalURICharacter, 0) == -1)
324
return false; // Injection is impossible because the request does not contain any illegal URI characters.
326
if (decodedPageURL.find(canonicalizedString, 0, false) != -1)
327
return true; // We've found the smoking gun.
330
if (formDataObj && !formDataObj->isEmpty()) {
331
String formData = formDataObj->flattenToString();
332
if (string.length() < formData.length()) {
333
// Notice it is sufficient to compare the length of the string to
334
// the url-encoded POST data because the length of the url-decoded
335
// code is less than or equal to the length of the url-encoded
337
String decodedFormData = m_cache.canonicalizeURL(formData, frame->document()->decoder()->encoding(), decodeEntities, decodeURLEscapeSequencesTwice);
338
if (decodedFormData.find(canonicalizedString, 0, false) != -1)
339
return true; // We found the string in the POST data.
343
if (!task.context.isEmpty())
344
canonicalizedString = task.context + canonicalizedString;
346
String decodedPageURL = m_cache.canonicalizeURL(pageURL, frame->document()->decoder()->encoding(), task.decodeEntities, task.decodeURLEscapeSequencesTwice);
348
if (task.allowRequestIfNoIllegalURICharacters && !hasFormData && decodedPageURL.find(&isIllegalURICharacter, 0) == -1)
349
return false; // Injection is impossible because the request does not contain any illegal URI characters.
351
if (decodedPageURL.find(canonicalizedString, 0, false) != -1)
352
return true; // We've found the string in the GET data.
355
String decodedFormData = m_cache.canonicalizeURL(formDataObj->flattenToString(), frame->document()->decoder()->encoding(), task.decodeEntities, task.decodeURLEscapeSequencesTwice);
356
if (decodedFormData.find(canonicalizedString, 0, false) != -1)
357
return true; // We found the string in the POST data.