1/*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 * Copyright (C) 2013-2017 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "config.h"
31#include "MixedContentChecker.h"
32
33#include "ContentSecurityPolicy.h"
34#include "Document.h"
35#include "Frame.h"
36#include "FrameLoader.h"
37#include "FrameLoaderClient.h"
38#include "SecurityOrigin.h"
39#include "Settings.h"
40#include <wtf/text/CString.h>
41#include <wtf/text/WTFString.h>
42
43namespace WebCore {
44
45MixedContentChecker::MixedContentChecker(Frame& frame)
46 : m_frame(frame)
47{
48}
49
50FrameLoaderClient& MixedContentChecker::client() const
51{
52 return m_frame.loader().client();
53}
54
55// static
56bool MixedContentChecker::isMixedContent(SecurityOrigin& securityOrigin, const URL& url)
57{
58 if (securityOrigin.protocol() != "https")
59 return false; // We only care about HTTPS security origins.
60
61 // We're in a secure context, so |url| is mixed content if it's insecure.
62 return !SecurityOrigin::isSecure(url);
63}
64
65bool MixedContentChecker::canDisplayInsecureContent(SecurityOrigin& securityOrigin, ContentType type, const URL& url, AlwaysDisplayInNonStrictMode alwaysDisplayInNonStrictMode) const
66{
67 if (!isMixedContent(securityOrigin, url))
68 return true;
69
70 if (!m_frame.document()->contentSecurityPolicy()->allowRunningOrDisplayingInsecureContent(url))
71 return false;
72
73 bool isStrictMode = m_frame.document()->isStrictMixedContentMode();
74 if (!isStrictMode && alwaysDisplayInNonStrictMode == AlwaysDisplayInNonStrictMode::Yes)
75 return true;
76
77 bool allowed = !isStrictMode && (m_frame.settings().allowDisplayOfInsecureContent() || type == ContentType::ActiveCanWarn) && !m_frame.document()->geolocationAccessed();
78 logWarning(allowed, "display", url);
79
80 if (allowed) {
81 m_frame.document()->setFoundMixedContent(SecurityContext::MixedContentType::Inactive);
82 client().didDisplayInsecureContent();
83 }
84
85 return allowed;
86}
87
88bool MixedContentChecker::canRunInsecureContent(SecurityOrigin& securityOrigin, const URL& url) const
89{
90 if (!isMixedContent(securityOrigin, url))
91 return true;
92
93 if (!m_frame.document()->contentSecurityPolicy()->allowRunningOrDisplayingInsecureContent(url))
94 return false;
95
96 bool allowed = !m_frame.document()->isStrictMixedContentMode() && m_frame.settings().allowRunningOfInsecureContent() && !m_frame.document()->geolocationAccessed() && !m_frame.document()->secureCookiesAccessed();
97 logWarning(allowed, "run", url);
98
99 if (allowed) {
100 m_frame.document()->setFoundMixedContent(SecurityContext::MixedContentType::Active);
101 client().didRunInsecureContent(securityOrigin, url);
102 }
103
104 return allowed;
105}
106
107void MixedContentChecker::checkFormForMixedContent(SecurityOrigin& securityOrigin, const URL& url) const
108{
109 // Unconditionally allow javascript: URLs as form actions as some pages do this and it does not introduce
110 // a mixed content issue.
111 if (WTF::protocolIsJavaScript(url))
112 return;
113
114 if (!isMixedContent(securityOrigin, url))
115 return;
116
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);
119
120 client().didDisplayInsecureContent();
121}
122
123void MixedContentChecker::logWarning(bool allowed, const String& action, const URL& target) const
124{
125 const char* errorString = allowed ? " was allowed to " : " was not allowed to ";
126 String message = makeString((allowed ? String() : "[blocked] "), "The page at ", m_frame.document()->url().stringCenterEllipsizedToLength(), errorString, action, " insecure content from ", target.stringCenterEllipsizedToLength(), ".\n");
127 m_frame.document()->addConsoleMessage(MessageSource::Security, MessageLevel::Warning, message);
128}
129
130} // namespace WebCore
131