2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include "core/loader/MixedContentChecker.h"
32 #include "core/dom/Document.h"
33 #include "core/frame/LocalFrame.h"
34 #include "core/frame/Settings.h"
35 #include "core/inspector/ConsoleMessage.h"
36 #include "core/loader/FrameLoader.h"
37 #include "core/loader/FrameLoaderClient.h"
38 #include "platform/RuntimeEnabledFeatures.h"
39 #include "platform/weborigin/SchemeRegistry.h"
40 #include "platform/weborigin/SecurityOrigin.h"
41 #include "wtf/text/StringBuilder.h"
45 MixedContentChecker::MixedContentChecker(LocalFrame* frame)
50 FrameLoaderClient* MixedContentChecker::client() const
52 return m_frame->loader().client();
56 bool MixedContentChecker::isMixedContent(SecurityOrigin* securityOrigin, const KURL& url)
58 if (securityOrigin->protocol() != "https")
59 return false; // We only care about HTTPS security origins.
61 // We're in a secure context, so |url| is mixed content if it's insecure.
62 return !SecurityOrigin::isSecure(url);
65 bool MixedContentChecker::canDisplayInsecureContentInternal(SecurityOrigin* securityOrigin, const KURL& url, const MixedContentType type) const
67 // Check the top frame if it differs from MixedContentChecker's m_frame.
68 if (!m_frame->tree().top()->isLocalFrame()) {
69 // FIXME: We need a way to access the top-level frame's MixedContentChecker when that frame
70 // is in a different process from the current frame. Until that is done, we always allow
71 // loads in remote frames.
74 Frame* top = m_frame->tree().top();
75 if (top != m_frame && !toLocalFrame(top)->loader().mixedContentChecker()->canDisplayInsecureContent(toLocalFrame(top)->document()->securityOrigin(), url))
78 // Then check the current frame:
79 if (!isMixedContent(securityOrigin, url))
82 Settings* settings = m_frame->settings();
83 bool allowed = client()->allowDisplayingInsecureContent(settings && settings->allowDisplayOfInsecureContent(), securityOrigin, url);
84 logWarning(allowed, url, type);
87 client()->didDisplayInsecureContent();
92 bool MixedContentChecker::canRunInsecureContentInternal(SecurityOrigin* securityOrigin, const KURL& url, const MixedContentType type) const
94 // Check the top frame if it differs from MixedContentChecker's m_frame.
95 if (!m_frame->tree().top()->isLocalFrame()) {
96 // FIXME: We need a way to access the top-level frame's MixedContentChecker when that frame
97 // is in a different process from the current frame. Until that is done, we always allow
98 // loads in remote frames.
101 Frame* top = m_frame->tree().top();
102 if (top != m_frame && !toLocalFrame(top)->loader().mixedContentChecker()->canRunInsecureContent(toLocalFrame(top)->document()->securityOrigin(), url))
105 // Then check the current frame:
106 if (!isMixedContent(securityOrigin, url))
109 Settings* settings = m_frame->settings();
110 bool allowedPerSettings = settings && (settings->allowRunningOfInsecureContent() || ((type == WebSocket) && settings->allowConnectingInsecureWebSocket()));
111 bool allowed = client()->allowRunningInsecureContent(allowedPerSettings, securityOrigin, url);
112 logWarning(allowed, url, type);
115 client()->didRunInsecureContent(securityOrigin, url);
120 bool MixedContentChecker::canFrameInsecureContent(SecurityOrigin* securityOrigin, const KURL& url) const
122 // If we're dealing with a CORS-enabled scheme, then block mixed frames as active content. Otherwise,
123 // treat frames as passive content.
125 // FIXME: Remove this temporary hack once we have a reasonable API for launching external applications
126 // via URLs. http://crbug.com/318788 and https://crbug.com/393481
127 if (SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(url.protocol()))
128 return canRunInsecureContentInternal(securityOrigin, url, MixedContentChecker::Execution);
129 return canDisplayInsecureContentInternal(securityOrigin, url, MixedContentChecker::Display);
132 bool MixedContentChecker::canConnectInsecureWebSocket(SecurityOrigin* securityOrigin, const KURL& url) const
134 if (RuntimeEnabledFeatures::laxMixedContentCheckingEnabled())
135 return canDisplayInsecureContentInternal(securityOrigin, url, MixedContentChecker::WebSocket);
136 return canRunInsecureContentInternal(securityOrigin, url, MixedContentChecker::WebSocket);
139 bool MixedContentChecker::canSubmitToInsecureForm(SecurityOrigin* securityOrigin, const KURL& url) const
141 // For whatever reason, some folks handle forms via JavaScript, and submit to `javascript:void(0)`
142 // rather than calling `preventDefault()`. We special-case `javascript:` URLs here, as they don't
143 // introduce MixedContent for form submissions.
144 if (url.protocolIs("javascript"))
147 // If lax mixed content checking is enabled (noooo!), skip this check entirely.
148 if (RuntimeEnabledFeatures::laxMixedContentCheckingEnabled())
150 return canDisplayInsecureContentInternal(securityOrigin, url, MixedContentChecker::Submission);
153 void MixedContentChecker::logWarning(bool allowed, const KURL& target, const MixedContentType type) const
155 StringBuilder message;
156 message.append((allowed ? "" : "[blocked] "));
157 message.append("The page at '" + m_frame->document()->url().elidedString() + "' was loaded over HTTPS, but ");
160 message.append("displayed insecure content from '" + target.elidedString() + "': this content should also be loaded over HTTPS.\n");
164 message.append("ran insecure content from '" + target.elidedString() + "': this content should also be loaded over HTTPS.\n");
167 message.append("is submitting data to an insecure location at '" + target.elidedString() + "': this content should also be submitted over HTTPS.\n");
170 MessageLevel messageLevel = allowed ? WarningMessageLevel : ErrorMessageLevel;
171 m_frame->document()->addConsoleMessage(ConsoleMessage::create(SecurityMessageSource, messageLevel, message.toString()));