Source/WebCore/ChangeLog

 12020-12-11 Rob Buis <rbuis@igalia.com>
 2
 3 Make MixedContentChecker stateless
 4 https://bugs.webkit.org/show_bug.cgi?id=219771
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Make MixedContentChecker stateless, it only needs the frame
 9 in a few cased which we can just pass as a parameter. Making
 10 MixedContentChecker stateless means that FrameLoader does
 11 not have to know it.
 12
 13 * Modules/websockets/WebSocket.cpp:
 14 (WebCore::WebSocket::connect):
 15 * Modules/websockets/WorkerThreadableWebSocketChannel.cpp:
 16 (WebCore::WorkerThreadableWebSocketChannel::Bridge::connect):
 17 * html/HTMLFormElement.cpp:
 18 (WebCore::HTMLFormElement::parseAttribute):
 19 * html/parser/XSSAuditor.cpp:
 20 * loader/DocumentLoader.cpp:
 21 (WebCore::DocumentLoader::willSendRequest):
 22 * loader/DocumentThreadableLoader.cpp:
 23 (WebCore::DocumentThreadableLoader::loadRequest):
 24 * loader/FrameLoader.cpp:
 25 (WebCore::FrameLoader::FrameLoader):
 26 * loader/FrameLoader.h:
 27 * loader/MixedContentChecker.cpp:
 28 (WebCore::logWarning):
 29 (WebCore::MixedContentChecker::canDisplayInsecureContent):
 30 (WebCore::MixedContentChecker::canRunInsecureContent):
 31 (WebCore::MixedContentChecker::checkFormForMixedContent):
 32 (WebCore::MixedContentChecker::checkForMixedContentInFrameTree):
 33 (WebCore::MixedContentChecker::MixedContentChecker): Deleted.
 34 (WebCore::MixedContentChecker::client const): Deleted.
 35 (WebCore::MixedContentChecker::canDisplayInsecureContent const): Deleted.
 36 (WebCore::MixedContentChecker::canRunInsecureContent const): Deleted.
 37 (WebCore::MixedContentChecker::checkFormForMixedContent const): Deleted.
 38 (WebCore::MixedContentChecker::logWarning const): Deleted.
 39 * loader/MixedContentChecker.h:
 40 * loader/SubframeLoader.cpp:
 41 (WebCore::FrameLoader::SubframeLoader::pluginIsLoadable):
 42 * loader/cache/CachedResourceLoader.cpp:
 43 (WebCore::CachedResourceLoader::checkInsecureContent const):
 44
1452020-12-10 Alex Christensen <achristensen@webkit.org>
246
347 Accept click measurement data from hosting application

Source/WebCore/Modules/websockets/WebSocket.cpp

4545#include "FrameLoaderClient.h"
4646#include "Logging.h"
4747#include "MessageEvent.h"
 48#include "MixedContentChecker.h"
4849#include "ResourceLoadObserver.h"
4950#include "ScriptController.h"
5051#include "ScriptExecutionContext.h"

@@ExceptionOr<void> WebSocket::connect(const String& url, const Vector<String>& pr
310311 Document& document = downcast<Document>(context);
311312 RefPtr<Frame> frame = document.frame();
312313 // FIXME: make the mixed content check equivalent to the non-document mixed content check currently in WorkerThreadableWebSocketChannel::Bridge::connect()
313  if (!frame || !frame->loader().mixedContentChecker().canRunInsecureContent(document.securityOrigin(), m_url)) {
 314 if (!frame || !MixedContentChecker::canRunInsecureContent(*frame, document.securityOrigin(), m_url)) {
314315 failAsynchronously();
315316 return { };
316317 }

Source/WebCore/Modules/websockets/WorkerThreadableWebSocketChannel.cpp

3434#include "Blob.h"
3535#include "Document.h"
3636#include "Frame.h"
37 #include "FrameLoader.h"
 37#include "MixedContentChecker.h"
3838#include "ScriptExecutionContext.h"
3939#include "SocketProvider.h"
4040#include "ThreadableWebSocketChannelClientWrapper.h"

@@void WorkerThreadableWebSocketChannel::Bridge::connect(const URL& url, const Str
411411
412412 // FIXME: make this mixed content check equivalent to the document mixed content check currently in WebSocket::connect()
413413 if (document.frame()) {
414  Optional<String> errorString = document.frame()->loader().mixedContentChecker().checkForMixedContentInFrameTree(url);
 414 Optional<String> errorString = MixedContentChecker::checkForMixedContentInFrameTree(*document.frame(), url);
415415 if (errorString) {
416416 peer->fail(errorString.value());
417417 return;

Source/WebCore/html/HTMLFormElement.cpp

4444#include "HTMLObjectElement.h"
4545#include "HTMLParserIdioms.h"
4646#include "HTMLTableElement.h"
 47#include "MixedContentChecker.h"
4748#include "NodeRareData.h"
4849#include "Page.h"
4950#include "RadioNodeList.h"

@@void HTMLFormElement::parseAttribute(const QualifiedName& name, const AtomString
447448 if (!m_attributes.action().isEmpty()) {
448449 if (RefPtr<Frame> f = document().frame()) {
449450 Frame& topFrame = f->tree().top();
450  topFrame.loader().mixedContentChecker().checkFormForMixedContent(topFrame.document()->securityOrigin(), document().completeURL(m_attributes.action()));
 451 MixedContentChecker::checkFormForMixedContent(topFrame, topFrame.document()->securityOrigin(), document().completeURL(m_attributes.action()));
451452 }
452453 }
453454 } else if (name == targetAttr)

Source/WebCore/html/parser/XSSAuditor.cpp

3838#include "HTMLNames.h"
3939#include "HTMLParamElement.h"
4040#include "HTMLParserIdioms.h"
 41#include "MixedContentChecker.h"
4142#include "SVGNames.h"
4243#include "Settings.h"
4344#include "TextResourceDecoder.h"

Source/WebCore/loader/DocumentLoader.cpp

6767#include "LoaderStrategy.h"
6868#include "Logging.h"
6969#include "MemoryCache.h"
 70#include "MixedContentChecker.h"
7071#include "NavigationScheduler.h"
7172#include "NetworkLoadMetrics.h"
7273#include "NetworkStorageSession.h"

@@void DocumentLoader::willSendRequest(ResourceRequest&& newRequest, const Resourc
644645 newRequest.setCachePolicy(ResourceRequestCachePolicy::ReloadIgnoringCacheData);
645646
646647 if (&topFrame != m_frame) {
647  if (!m_frame->loader().mixedContentChecker().canDisplayInsecureContent(m_frame->document()->securityOrigin(), MixedContentChecker::ContentType::Active, newRequest.url(), MixedContentChecker::AlwaysDisplayInNonStrictMode::Yes)) {
 648 if (!MixedContentChecker::canDisplayInsecureContent(*m_frame, m_frame->document()->securityOrigin(), MixedContentChecker::ContentType::Active, newRequest.url(), MixedContentChecker::AlwaysDisplayInNonStrictMode::Yes)) {
648649 cancelMainResourceLoad(frameLoader()->cancelledError(newRequest));
649650 return completionHandler(WTFMove(newRequest));
650651 }
651  if (!frameLoader()->mixedContentChecker().canDisplayInsecureContent(topFrame.document()->securityOrigin(), MixedContentChecker::ContentType::Active, newRequest.url())) {
 652 if (!MixedContentChecker::canDisplayInsecureContent(*m_frame, topFrame.document()->securityOrigin(), MixedContentChecker::ContentType::Active, newRequest.url())) {
652653 cancelMainResourceLoad(frameLoader()->cancelledError(newRequest));
653654 return completionHandler(WTFMove(newRequest));
654655 }

Source/WebCore/loader/DocumentThreadableLoader.cpp

4141#include "DOMWindow.h"
4242#include "Document.h"
4343#include "Frame.h"
44 #include "FrameLoader.h"
4544#include "InspectorInstrumentation.h"
4645#include "LegacySchemeRegistry.h"
4746#include "LoadTiming.h"
4847#include "LoaderStrategy.h"
 48#include "MixedContentChecker.h"
4949#include "Performance.h"
5050#include "PlatformStrategies.h"
5151#include "ProgressTracker.h"

@@void DocumentThreadableLoader::loadRequest(ResourceRequest&& request, SecurityCh
591591 ResourceResponse response;
592592 unsigned long identifier = std::numeric_limits<unsigned long>::max();
593593 if (m_document.frame()) {
594  auto& frameLoader = m_document.frame()->loader();
595  if (!frameLoader.mixedContentChecker().canRunInsecureContent(m_document.securityOrigin(), requestURL))
 594 if (!MixedContentChecker::canRunInsecureContent(*m_document.frame(), m_document.securityOrigin(), requestURL))
596595 return;
 596 auto& frameLoader = m_document.frame()->loader();
597597 identifier = frameLoader.loadResourceSynchronously(request, m_options.clientCredentialPolicy, m_options, *m_originalHeaders, error, response, data);
598598 }
599599

Source/WebCore/loader/FrameLoader.cpp

@@FrameLoader::FrameLoader(Frame& frame, UniqueRef<FrameLoaderClient>&& client)
296296 , m_history(makeUnique<HistoryController>(frame))
297297 , m_notifier(frame)
298298 , m_subframeLoader(makeUnique<SubframeLoader>(frame))
299  , m_mixedContentChecker(frame)
300299 , m_state(FrameStateProvisional)
301300 , m_loadType(FrameLoadType::Standard)
302301 , m_quickRedirectComing(false)

Source/WebCore/loader/FrameLoader.h

3636#include "FrameLoaderStateMachine.h"
3737#include "FrameLoaderTypes.h"
3838#include "LayoutMilestone.h"
39 #include "MixedContentChecker.h"
4039#include "PageIdentifier.h"
4140#include "PrivateClickMeasurement.h"
4241#include "ReferrerPolicy.h"

@@public:
119118 class SubframeLoader;
120119 SubframeLoader& subframeLoader() { return *m_subframeLoader; }
121120 const SubframeLoader& subframeLoader() const { return *m_subframeLoader; }
122  MixedContentChecker& mixedContentChecker() const { return m_mixedContentChecker; }
123121
124122 void setupForReplace();
125123

@@private:
439437 mutable ResourceLoadNotifier m_notifier;
440438 const std::unique_ptr<SubframeLoader> m_subframeLoader;
441439 mutable FrameLoaderStateMachine m_stateMachine;
442  mutable MixedContentChecker m_mixedContentChecker;
443440
444441 class FrameProgressTracker;
445442 std::unique_ptr<FrameProgressTracker> m_progressTracker;

Source/WebCore/loader/MixedContentChecker.cpp

4242
4343namespace WebCore {
4444
45 MixedContentChecker::MixedContentChecker(Frame& frame)
46  : m_frame(frame)
47 {
48 }
49 
50 FrameLoaderClient& MixedContentChecker::client() const
51 {
52  return m_frame.loader().client();
53 }
54 
5545// static
5646bool MixedContentChecker::isMixedContent(SecurityOrigin& securityOrigin, const URL& url)
5747{

@@bool MixedContentChecker::isMixedContent(SecurityOrigin& securityOrigin, const U
6252 return !SecurityOrigin::isSecure(url);
6353}
6454
65 bool MixedContentChecker::canDisplayInsecureContent(SecurityOrigin& securityOrigin, ContentType type, const URL& url, AlwaysDisplayInNonStrictMode alwaysDisplayInNonStrictMode) const
 55static void logWarning(const Frame& frame, bool allowed, const String& action, const URL& target)
 56{
 57 const char* errorString = allowed ? " was allowed to " : " was not allowed to ";
 58 String message = makeString((allowed ? String() : "[blocked] "), "The page at ", frame.document()->url().stringCenterEllipsizedToLength(), errorString, action, " insecure content from ", target.stringCenterEllipsizedToLength(), ".\n");
 59 frame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Warning, message);
 60}
 61
 62bool MixedContentChecker::canDisplayInsecureContent(Frame& frame, SecurityOrigin& securityOrigin, ContentType type, const URL& url, AlwaysDisplayInNonStrictMode alwaysDisplayInNonStrictMode)
6663{
6764 if (!isMixedContent(securityOrigin, url))
6865 return true;
6966
70  if (!m_frame.document()->contentSecurityPolicy()->allowRunningOrDisplayingInsecureContent(url))
 67 if (!frame.document()->contentSecurityPolicy()->allowRunningOrDisplayingInsecureContent(url))
7168 return false;
7269
73  bool isStrictMode = m_frame.document()->isStrictMixedContentMode();
 70 bool isStrictMode = frame.document()->isStrictMixedContentMode();
7471 if (!isStrictMode && alwaysDisplayInNonStrictMode == AlwaysDisplayInNonStrictMode::Yes)
7572 return true;
7673
77  bool allowed = !isStrictMode && (m_frame.settings().allowDisplayOfInsecureContent() || type == ContentType::ActiveCanWarn) && !m_frame.document()->geolocationAccessed();
78  logWarning(allowed, "display", url);
 74 bool allowed = !isStrictMode && (frame.settings().allowDisplayOfInsecureContent() || type == ContentType::ActiveCanWarn) && !frame.document()->geolocationAccessed();
 75 logWarning(frame, allowed, "display", url);
7976
8077 if (allowed) {
81  m_frame.document()->setFoundMixedContent(SecurityContext::MixedContentType::Inactive);
82  client().didDisplayInsecureContent();
 78 frame.document()->setFoundMixedContent(SecurityContext::MixedContentType::Inactive);
 79 frame.loader().client().didDisplayInsecureContent();
8380 }
8481
8582 return allowed;
8683}
8784
88 bool MixedContentChecker::canRunInsecureContent(SecurityOrigin& securityOrigin, const URL& url) const
 85bool MixedContentChecker::canRunInsecureContent(Frame& frame, SecurityOrigin& securityOrigin, const URL& url)
8986{
9087 if (!isMixedContent(securityOrigin, url))
9188 return true;
9289
93  if (!m_frame.document()->contentSecurityPolicy()->allowRunningOrDisplayingInsecureContent(url))
 90 if (!frame.document()->contentSecurityPolicy()->allowRunningOrDisplayingInsecureContent(url))
9491 return false;
9592
96  bool allowed = !m_frame.document()->isStrictMixedContentMode() && m_frame.settings().allowRunningOfInsecureContent() && !m_frame.document()->geolocationAccessed() && !m_frame.document()->secureCookiesAccessed();
97  logWarning(allowed, "run", url);
 93 bool allowed = !frame.document()->isStrictMixedContentMode() && frame.settings().allowRunningOfInsecureContent() && !frame.document()->geolocationAccessed() && !frame.document()->secureCookiesAccessed();
 94 logWarning(frame, allowed, "run", url);
9895
9996 if (allowed) {
100  m_frame.document()->setFoundMixedContent(SecurityContext::MixedContentType::Active);
101  client().didRunInsecureContent(securityOrigin, url);
 97 frame.document()->setFoundMixedContent(SecurityContext::MixedContentType::Active);
 98 frame.loader().client().didRunInsecureContent(securityOrigin, url);
10299 }
103100
104101 return allowed;
105102}
106103
107 void MixedContentChecker::checkFormForMixedContent(SecurityOrigin& securityOrigin, const URL& url) const
 104void MixedContentChecker::checkFormForMixedContent(Frame& frame, SecurityOrigin& securityOrigin, const URL& url)
108105{
109106 // Unconditionally allow javascript: URLs as form actions as some pages do this and it does not introduce
110107 // a mixed content issue.

@@void MixedContentChecker::checkFormForMixedContent(SecurityOrigin& securityOrigi
114111 if (!isMixedContent(securityOrigin, url))
115112 return;
116113
117  String message = makeString("The page at ", m_frame.document()->url().stringCenterEllipsizedToLength(), " contains a form which targets an insecure URL ", url.stringCenterEllipsizedToLength(), ".\n");
118  m_frame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Warning, message);
 114 String message = makeString("The page at ", frame.document()->url().stringCenterEllipsizedToLength(), " contains a form which targets an insecure URL ", url.stringCenterEllipsizedToLength(), ".\n");
 115 frame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Warning, message);
119116
120  client().didDisplayInsecureContent();
 117 frame.loader().client().didDisplayInsecureContent();
121118}
122119
123 Optional<String> MixedContentChecker::checkForMixedContentInFrameTree(const URL& url)
 120Optional<String> MixedContentChecker::checkForMixedContentInFrameTree(const Frame& frame, const URL& url)
124121{
125  auto* document = m_frame.document();
 122 auto* document = frame.document();
126123
127124 while (document) {
128125 RELEASE_ASSERT_WITH_MESSAGE(document->frame(), "An unparented document tried to connect to a websocket with url: %s", url.string().utf8().data());

@@Optional<String> MixedContentChecker::checkForMixedContentInFrameTree(const URL&
142139 return WTF::nullopt;
143140}
144141
145 void MixedContentChecker::logWarning(bool allowed, const String& action, const URL& target) const
146 {
147  const char* errorString = allowed ? " was allowed to " : " was not allowed to ";
148  String message = makeString((allowed ? String() : "[blocked] "), "The page at ", m_frame.document()->url().stringCenterEllipsizedToLength(), errorString, action, " insecure content from ", target.stringCenterEllipsizedToLength(), ".\n");
149  m_frame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Warning, message);
150 }
151 
152142} // namespace WebCore

Source/WebCore/loader/MixedContentChecker.h

@@public:
4747 ActiveCanWarn,
4848 };
4949
50  MixedContentChecker(Frame&);
51 
5250 enum class AlwaysDisplayInNonStrictMode {
5351 No,
5452 Yes,
5553 };
5654
57  bool canDisplayInsecureContent(SecurityOrigin&, ContentType, const URL&, AlwaysDisplayInNonStrictMode = AlwaysDisplayInNonStrictMode::No) const;
58  bool canRunInsecureContent(SecurityOrigin&, const URL&) const;
59  void checkFormForMixedContent(SecurityOrigin&, const URL&) const;
60  static bool isMixedContent(SecurityOrigin&, const URL&);
61  Optional<String> checkForMixedContentInFrameTree(const URL&);
62 
63 private:
6455 // FIXME: This should probably have a separate client from FrameLoader.
65  FrameLoaderClient& client() const;
66 
67  void logWarning(bool allowed, const String& action, const URL&) const;
68 
69  Frame& m_frame;
 56 static bool canDisplayInsecureContent(Frame&, SecurityOrigin&, ContentType, const URL&, AlwaysDisplayInNonStrictMode = AlwaysDisplayInNonStrictMode::No);
 57 static bool canRunInsecureContent(Frame&, SecurityOrigin&, const URL&);
 58 static void checkFormForMixedContent(Frame&, SecurityOrigin&, const URL&);
 59 static bool isMixedContent(SecurityOrigin&, const URL&);
 60 static Optional<String> checkForMixedContentInFrameTree(const Frame&, const URL&);
7061};
7162
7263} // namespace WebCore

Source/WebCore/loader/SubframeLoader.cpp

3838#include "DiagnosticLoggingKeys.h"
3939#include "DocumentLoader.h"
4040#include "Frame.h"
41 #include "FrameLoader.h"
4241#include "FrameLoaderClient.h"
4342#include "HTMLFrameElement.h"
4443#include "HTMLIFrameElement.h"
4544#include "HTMLNames.h"
4645#include "HTMLObjectElement.h"
4746#include "MIMETypeRegistry.h"
 47#include "MixedContentChecker.h"
4848#include "NavigationScheduler.h"
4949#include "Page.h"
5050#include "PluginData.h"

@@bool FrameLoader::SubframeLoader::pluginIsLoadable(const URL& url, const String&
140140 return false;
141141 }
142142
143  if (!m_frame.loader().mixedContentChecker().canRunInsecureContent(document->securityOrigin(), url))
 143 if (!MixedContentChecker::canRunInsecureContent(m_frame, document->securityOrigin(), url))
144144 return false;
145145 }
146146

Source/WebCore/loader/cache/CachedResourceLoader.cpp

6262#include "LocalizedStrings.h"
6363#include "Logging.h"
6464#include "MemoryCache.h"
 65#include "MixedContentChecker.h"
6566#include "Page.h"
6667#include "PingLoader.h"
6768#include "PlatformStrategies.h"

@@bool CachedResourceLoader::checkInsecureContent(CachedResource::Type type, const
419420 // These resource can inject script into the current document (Script,
420421 // XSL) or exfiltrate the content of the current document (CSS).
421422 if (Frame* frame = this->frame()) {
422  if (!frame->loader().mixedContentChecker().canRunInsecureContent(m_document->securityOrigin(), url))
 423 if (!MixedContentChecker::canRunInsecureContent(*frame, m_document->securityOrigin(), url))
423424 return false;
424425 Frame& top = frame->tree().top();
425  if (&top != frame && !top.loader().mixedContentChecker().canRunInsecureContent(top.document()->securityOrigin(), url))
 426 if (&top != frame && !MixedContentChecker::canRunInsecureContent(top, top.document()->securityOrigin(), url))
426427 return false;
427428 }
428429 break;

@@bool CachedResourceLoader::checkInsecureContent(CachedResource::Type type, const
437438 case CachedResource::Type::FontResource: {
438439 // These resources can corrupt only the frame's pixels.
439440 if (Frame* frame = this->frame()) {
440  if (!frame->loader().mixedContentChecker().canDisplayInsecureContent(m_document->securityOrigin(), contentTypeFromResourceType(type), url, MixedContentChecker::AlwaysDisplayInNonStrictMode::Yes))
 441 if (!MixedContentChecker::canDisplayInsecureContent(*frame, m_document->securityOrigin(), contentTypeFromResourceType(type), url, MixedContentChecker::AlwaysDisplayInNonStrictMode::Yes))
441442 return false;
442443 Frame& topFrame = frame->tree().top();
443  if (!topFrame.loader().mixedContentChecker().canDisplayInsecureContent(topFrame.document()->securityOrigin(), contentTypeFromResourceType(type), url))
 444 if (!MixedContentChecker::canDisplayInsecureContent(topFrame, topFrame.document()->securityOrigin(), contentTypeFromResourceType(type), url))
444445 return false;
445446 }
446447 break;