1/*
2 * Copyright (C) 2011 Google Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 */
26
27#include "config.h"
28#include "SecurityContext.h"
29
30#include "ContentSecurityPolicy.h"
31#include "HTMLParserIdioms.h"
32#include "SecurityOrigin.h"
33#include "SecurityOriginPolicy.h"
34#include <wtf/text/StringBuilder.h>
35
36namespace WebCore {
37
38SecurityContext::SecurityContext() = default;
39
40SecurityContext::~SecurityContext() = default;
41
42void SecurityContext::setSecurityOriginPolicy(RefPtr<SecurityOriginPolicy>&& securityOriginPolicy)
43{
44 m_securityOriginPolicy = WTFMove(securityOriginPolicy);
45 m_haveInitializedSecurityOrigin = true;
46}
47
48SecurityOrigin* SecurityContext::securityOrigin() const
49{
50 if (!m_securityOriginPolicy)
51 return nullptr;
52
53 return &m_securityOriginPolicy->origin();
54}
55
56void SecurityContext::setContentSecurityPolicy(std::unique_ptr<ContentSecurityPolicy> contentSecurityPolicy)
57{
58 m_contentSecurityPolicy = WTFMove(contentSecurityPolicy);
59}
60
61bool SecurityContext::isSecureTransitionTo(const URL& url) const
62{
63 // If we haven't initialized our security origin by now, this is probably
64 // a new window created via the API (i.e., that lacks an origin and lacks
65 // a place to inherit the origin from).
66 if (!haveInitializedSecurityOrigin())
67 return true;
68
69 return securityOriginPolicy()->origin().canAccess(SecurityOrigin::create(url).get());
70}
71
72void SecurityContext::enforceSandboxFlags(SandboxFlags mask)
73{
74 m_sandboxFlags |= mask;
75
76 // The SandboxOrigin is stored redundantly in the security origin.
77 if (isSandboxed(SandboxOrigin) && securityOriginPolicy() && !securityOriginPolicy()->origin().isUnique())
78 setSecurityOriginPolicy(SecurityOriginPolicy::create(SecurityOrigin::createUnique()));
79}
80
81bool SecurityContext::isSupportedSandboxPolicy(StringView policy)
82{
83 static const char* const supportedPolicies[] = {
84 "allow-forms", "allow-same-origin", "allow-scripts", "allow-top-navigation", "allow-pointer-lock", "allow-popups", "allow-popups-to-escape-sandbox", "allow-top-navigation-by-user-activation", "allow-modals", "allow-storage-access-by-user-activation"
85 };
86
87 for (auto* supportedPolicy : supportedPolicies) {
88 if (equalIgnoringASCIICase(policy, supportedPolicy))
89 return true;
90 }
91 return false;
92}
93
94// Keep SecurityContext::isSupportedSandboxPolicy() in sync when updating this function.
95SandboxFlags SecurityContext::parseSandboxPolicy(const String& policy, String& invalidTokensErrorMessage)
96{
97 // http://www.w3.org/TR/html5/the-iframe-element.html#attr-iframe-sandbox
98 // Parse the unordered set of unique space-separated tokens.
99 SandboxFlags flags = SandboxAll;
100 unsigned length = policy.length();
101 unsigned start = 0;
102 unsigned numberOfTokenErrors = 0;
103 StringBuilder tokenErrors;
104 while (true) {
105 while (start < length && isHTMLSpace(policy[start]))
106 ++start;
107 if (start >= length)
108 break;
109 unsigned end = start + 1;
110 while (end < length && !isHTMLSpace(policy[end]))
111 ++end;
112
113 // Turn off the corresponding sandbox flag if it's set as "allowed".
114 String sandboxToken = policy.substring(start, end - start);
115 if (equalLettersIgnoringASCIICase(sandboxToken, "allow-same-origin"))
116 flags &= ~SandboxOrigin;
117 else if (equalLettersIgnoringASCIICase(sandboxToken, "allow-forms"))
118 flags &= ~SandboxForms;
119 else if (equalLettersIgnoringASCIICase(sandboxToken, "allow-scripts")) {
120 flags &= ~SandboxScripts;
121 flags &= ~SandboxAutomaticFeatures;
122 } else if (equalLettersIgnoringASCIICase(sandboxToken, "allow-top-navigation")) {
123 flags &= ~SandboxTopNavigation;
124 flags &= ~SandboxTopNavigationByUserActivation;
125 } else if (equalLettersIgnoringASCIICase(sandboxToken, "allow-popups"))
126 flags &= ~SandboxPopups;
127 else if (equalLettersIgnoringASCIICase(sandboxToken, "allow-pointer-lock"))
128 flags &= ~SandboxPointerLock;
129 else if (equalLettersIgnoringASCIICase(sandboxToken, "allow-popups-to-escape-sandbox"))
130 flags &= ~SandboxPropagatesToAuxiliaryBrowsingContexts;
131 else if (equalLettersIgnoringASCIICase(sandboxToken, "allow-top-navigation-by-user-activation"))
132 flags &= ~SandboxTopNavigationByUserActivation;
133 else if (equalLettersIgnoringASCIICase(sandboxToken, "allow-modals"))
134 flags &= ~SandboxModals;
135 else if (equalLettersIgnoringASCIICase(sandboxToken, "allow-storage-access-by-user-activation"))
136 flags &= ~SandboxStorageAccessByUserActivation;
137 else {
138 if (numberOfTokenErrors)
139 tokenErrors.appendLiteral(", '");
140 else
141 tokenErrors.append('\'');
142 tokenErrors.append(sandboxToken);
143 tokenErrors.append('\'');
144 numberOfTokenErrors++;
145 }
146
147 start = end + 1;
148 }
149
150 if (numberOfTokenErrors) {
151 if (numberOfTokenErrors > 1)
152 tokenErrors.appendLiteral(" are invalid sandbox flags.");
153 else
154 tokenErrors.appendLiteral(" is an invalid sandbox flag.");
155 invalidTokensErrorMessage = tokenErrors.toString();
156 }
157
158 return flags;
159}
160
161}
162