bool XSSFilter::eraseAttributeIfInjected(HTMLToken& token, const QualifiedName& attributeName, const String& replacementValue) { size_t indexOfAttribute; if (findAttributeWithName(token, attributeName, indexOfAttribute)) { const HTMLToken::Attribute& attribute = token.attributes().at(indexOfAttribute); if (isContainedInRequest(snippetForAttribute(token, attribute))) { if (attributeName == srcAttr && isSameOriginResource(String(attribute.m_value.data(), attribute.m_value.size()))) return false; token.eraseValueOfAttribute(indexOfAttribute); if (!replacementValue.isEmpty()) token.appendToAttributeValue(indexOfAttribute, replacementValue); return true; } } return false; }
bool XSSAuditor::eraseAttributeIfInjected(HTMLToken& token, const QualifiedName& attributeName, const String& replacementValue, AttributeKind treatment) { size_t indexOfAttribute = 0; if (findAttributeWithName(token, attributeName, indexOfAttribute)) { const HTMLToken::Attribute& attribute = token.attributes().at(indexOfAttribute); if (isContainedInRequest(decodedSnippetForAttribute(token, attribute, treatment))) { if (attributeName == srcAttr && isLikelySafeResource(String(attribute.m_value.data(), attribute.m_value.size()))) return false; if (attributeName == http_equivAttr && !isDangerousHTTPEquiv(String(attribute.m_value.data(), attribute.m_value.size()))) return false; token.eraseValueOfAttribute(indexOfAttribute); if (!replacementValue.isEmpty()) token.appendToAttributeValue(indexOfAttribute, replacementValue); return true; } } return false; }
bool XSSAuditor::eraseDangerousAttributesIfInjected(HTMLToken& token) { DEFINE_STATIC_LOCAL(String, safeJavaScriptURL, ("javascript:void(0)")); bool didBlockScript = false; for (size_t i = 0; i < token.attributes().size(); ++i) { const HTMLToken::Attribute& attribute = token.attributes().at(i); bool isInlineEventHandler = isNameOfInlineEventHandler(attribute.m_name); bool valueContainsJavaScriptURL = isInlineEventHandler ? false : containsJavaScriptURL(attribute.m_value); if (!isInlineEventHandler && !valueContainsJavaScriptURL) continue; // Beware of trailing characters which came from the page itself, not the // injected vector. Excluding the terminating character covers common cases // where the page immediately ends the attribute, but doesn't cover more // complex cases where there is other page data following the injection. // Generally, these won't parse as javascript, so the injected vector // typically excludes them from consideration via a single-line comment or // by enclosing them in a string literal terminated later by the page's own // closing punctuation. Since the snippet has not been parsed, the vector // may also try to introduce these via entities. As a result, we'd like to // stop before the first "//", the first <!--, the first entity, or the first // quote not immediately following the first equals sign (taking whitespace // into consideration). To keep things simpler, we don't try to distinguish // between entity-introducing amperands vs. other uses, nor do we bother to // check for a second slash for a comment, nor do we bother to check for // !-- following a less-than sign. We stop instead on any ampersand // slash, or less-than sign. String decodedSnippet = decodedSnippetForAttribute(token, attribute); size_t position; if ((position = decodedSnippet.find("=")) != notFound && (position = decodedSnippet.find(isNotHTMLSpace, position + 1)) != notFound && (position = decodedSnippet.find(isTerminatingCharacter, isHTMLQuote(decodedSnippet[position]) ? position + 1 : position)) != notFound) { decodedSnippet.truncate(position); } if (!isContainedInRequest(decodedSnippet)) continue; token.eraseValueOfAttribute(i); if (valueContainsJavaScriptURL) token.appendToAttributeValue(i, safeJavaScriptURL); didBlockScript = true; } return didBlockScript; }
bool XSSAuditor::eraseDangerousAttributesIfInjected(HTMLToken& token) { DEFINE_STATIC_LOCAL(String, safeJavaScriptURL, (ASCIILiteral("javascript:void(0)"))); bool didBlockScript = false; for (size_t i = 0; i < token.attributes().size(); ++i) { const HTMLToken::Attribute& attribute = token.attributes().at(i); bool isInlineEventHandler = isNameOfInlineEventHandler(attribute.m_name); bool valueContainsJavaScriptURL = !isInlineEventHandler && protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(String(attribute.m_value.data(), attribute.m_value.size()))); if (!isInlineEventHandler && !valueContainsJavaScriptURL) continue; if (!isContainedInRequest(decodedSnippetForAttribute(token, attribute, ScriptLikeAttribute))) continue; token.eraseValueOfAttribute(i); if (valueContainsJavaScriptURL) token.appendToAttributeValue(i, safeJavaScriptURL); didBlockScript = true; } return didBlockScript; }
bool XSSFilter::eraseDangerousAttributesIfInjected(HTMLToken& token) { DEFINE_STATIC_LOCAL(String, safeJavaScriptURL, ("javascript:void(0)")); bool didBlockScript = false; for (size_t i = 0; i < token.attributes().size(); ++i) { const HTMLToken::Attribute& attribute = token.attributes().at(i); bool isInlineEventHandler = isNameOfInlineEventHandler(attribute.m_name); bool valueContainsJavaScriptURL = isInlineEventHandler ? false : containsJavaScriptURL(attribute.m_value); if (!isInlineEventHandler && !valueContainsJavaScriptURL) continue; if (!isContainedInRequest(snippetForAttribute(token, attribute))) continue; token.eraseValueOfAttribute(i); if (valueContainsJavaScriptURL) token.appendToAttributeValue(i, safeJavaScriptURL); didBlockScript = true; } return didBlockScript; }