static void gatherSecurityPolicyViolationEventData(SecurityPolicyViolationEventInit& init, Document* document, const String& directiveText, const String& effectiveDirective, const KURL& blockedURL, const String& header)
{
    if (equalIgnoringCase(effectiveDirective, ContentSecurityPolicy::FrameAncestors)) {
        // If this load was blocked via 'frame-ancestors', then the URL of |document| has not yet
        // been initialized. In this case, we'll set both 'documentURI' and 'blockedURI' to the
        // blocked document's URL.
        init.setDocumentURI(blockedURL.string());
        init.setBlockedURI(blockedURL.string());
    } else {
        init.setDocumentURI(document->url().string());
        init.setBlockedURI(stripURLForUseInReport(document, blockedURL));
    }
    init.setReferrer(document->referrer());
    init.setViolatedDirective(directiveText);
    init.setEffectiveDirective(effectiveDirective);
    init.setOriginalPolicy(header);
    init.setSourceFile(String());
    init.setLineNumber(0);
    init.setColumnNumber(0);
    init.setStatusCode(0);

    if (!SecurityOrigin::isSecure(document->url()) && document->loader())
        init.setStatusCode(document->loader()->response().httpStatusCode());

    RefPtrWillBeRawPtr<ScriptCallStack> stack = currentScriptCallStack(1);
    if (!stack || !stack->size())
        return;

    const ScriptCallFrame& callFrame = stack->at(0);

    if (callFrame.lineNumber()) {
        KURL source = KURL(ParsedURLString, callFrame.sourceURL());
        init.setSourceFile(stripURLForUseInReport(document, source));
        init.setLineNumber(callFrame.lineNumber());
        init.setColumnNumber(callFrame.columnNumber());
    }
}
Esempio n. 2
0
void ContentSecurityPolicy::reportViolation(const String& directiveText, const String& effectiveDirective, const String& consoleMessage, const URL& blockedURL, const Vector<String>& reportURIs, const String& header, const String& contextURL, const WTF::OrdinalNumber& contextLine, JSC::ExecState* state) const
{
    logToConsole(consoleMessage, contextURL, contextLine, state);

    // FIXME: Support sending reports from worker.
    if (!is<Document>(m_scriptExecutionContext))
        return;

    Document& document = downcast<Document>(*m_scriptExecutionContext);
    Frame* frame = document.frame();
    if (!frame)
        return;

#if ENABLE(CSP_NEXT)
    if (experimentalFeaturesEnabled()) {
        // FIXME: This code means that we're gathering information like line numbers twice. Once we can bring this out from behind the flag, we should reuse the data gathered here when generating the JSON report below.
        String documentURI = document.url().string();
        String referrer = document.referrer();
        String blockedURI = stripURLForUseInReport(document, blockedURL);
        String violatedDirective = directiveText;
        String originalPolicy = header;
        String sourceFile = String();
        int lineNumber = 0;
        
        Ref<ScriptCallStack> stack = createScriptCallStack(JSMainThreadExecState::currentState(), 2);
        const ScriptCallFrame* callFrame = stack->firstNonNativeCallFrame();
        if (callFrame && callFrame->lineNumber()) {
            URL source = URL(URL(), callFrame->sourceURL());
            sourceFile = stripURLForUseInReport(document, source);
            lineNumber = callFrame->lineNumber();
        }

        document.enqueueDocumentEvent(SecurityPolicyViolationEvent::create(eventNames().securitypolicyviolationEvent, false, false, documentURI, referrer, blockedURI, violatedDirective, effectiveDirective, originalPolicy, sourceFile, lineNumber));
    }
#endif

    if (reportURIs.isEmpty())
        return;

    // We need to be careful here when deciding what information to send to the
    // report-uri. Currently, we send only the current document's URL and the
    // directive that was violated. The document's URL is safe to send because
    // it's the document itself that's requesting that it be sent. You could
    // make an argument that we shouldn't send HTTPS document URLs to HTTP
    // report-uris (for the same reasons that we suppress the Referer in that
    // case), but the Referer is sent implicitly whereas this request is only
    // sent explicitly. As for which directive was violated, that's pretty
    // harmless information.

    RefPtr<InspectorObject> cspReport = InspectorObject::create();
    cspReport->setString(ASCIILiteral("document-uri"), document.url().strippedForUseAsReferrer());
    cspReport->setString(ASCIILiteral("referrer"), document.referrer());
    cspReport->setString(ASCIILiteral("violated-directive"), directiveText);
#if ENABLE(CSP_NEXT)
    if (experimentalFeaturesEnabled())
        cspReport->setString(ASCIILiteral("effective-directive"), effectiveDirective);
#else
    UNUSED_PARAM(effectiveDirective);
#endif
    cspReport->setString(ASCIILiteral("original-policy"), header);
    cspReport->setString(ASCIILiteral("blocked-uri"), stripURLForUseInReport(document, blockedURL));

    RefPtr<ScriptCallStack> stack = createScriptCallStack(JSMainThreadExecState::currentState(), 2);
    const ScriptCallFrame* callFrame = stack->firstNonNativeCallFrame();
    if (callFrame && callFrame->lineNumber()) {
        URL source = URL(URL(), callFrame->sourceURL());
        cspReport->setString(ASCIILiteral("source-file"), stripURLForUseInReport(document, source));
        cspReport->setInteger(ASCIILiteral("line-number"), callFrame->lineNumber());
    }

    RefPtr<InspectorObject> reportObject = InspectorObject::create();
    reportObject->setObject(ASCIILiteral("csp-report"), cspReport.release());

    RefPtr<FormData> report = FormData::create(reportObject->toJSONString().utf8());

    for (const auto& url : reportURIs)
        PingLoader::sendViolationReport(*frame, document.completeURL(url), report.copyRef());
}