OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> | 2 * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> |
3 * 1999 Lars Knoll <knoll@kde.org> | 3 * 1999 Lars Knoll <knoll@kde.org> |
4 * 1999 Antti Koivisto <koivisto@kde.org> | 4 * 1999 Antti Koivisto <koivisto@kde.org> |
5 * 2000 Simon Hausmann <hausmann@kde.org> | 5 * 2000 Simon Hausmann <hausmann@kde.org> |
6 * 2000 Stefan Schimanski <1Stein@gmx.de> | 6 * 2000 Stefan Schimanski <1Stein@gmx.de> |
7 * 2001 George Staikos <staikos@kde.org> | 7 * 2001 George Staikos <staikos@kde.org> |
8 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All | 8 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All |
9 * rights reserved. | 9 * rights reserved. |
10 * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com> | 10 * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com> |
(...skipping 27 matching lines...) Expand all Loading... |
38 #include "core/frame/UseCounter.h" | 38 #include "core/frame/UseCounter.h" |
39 #include "core/html/HTMLFrameElementBase.h" | 39 #include "core/html/HTMLFrameElementBase.h" |
40 #include "core/input/EventHandler.h" | 40 #include "core/input/EventHandler.h" |
41 #include "core/layout/LayoutPart.h" | 41 #include "core/layout/LayoutPart.h" |
42 #include "core/layout/api/LayoutPartItem.h" | 42 #include "core/layout/api/LayoutPartItem.h" |
43 #include "core/loader/EmptyClients.h" | 43 #include "core/loader/EmptyClients.h" |
44 #include "core/loader/NavigationScheduler.h" | 44 #include "core/loader/NavigationScheduler.h" |
45 #include "core/page/FocusController.h" | 45 #include "core/page/FocusController.h" |
46 #include "core/page/Page.h" | 46 #include "core/page/Page.h" |
47 #include "core/probe/CoreProbes.h" | 47 #include "core/probe/CoreProbes.h" |
48 #include "platform/Histogram.h" | |
49 #include "platform/InstanceCounters.h" | 48 #include "platform/InstanceCounters.h" |
50 #include "platform/UserGestureIndicator.h" | 49 #include "platform/UserGestureIndicator.h" |
51 #include "platform/feature_policy/FeaturePolicy.h" | 50 #include "platform/feature_policy/FeaturePolicy.h" |
52 #include "platform/loader/fetch/ResourceError.h" | 51 #include "platform/loader/fetch/ResourceError.h" |
53 | 52 |
54 namespace blink { | 53 namespace blink { |
55 | 54 |
56 using namespace HTMLNames; | 55 using namespace HTMLNames; |
57 | 56 |
58 Frame::~Frame() { | 57 Frame::~Frame() { |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 return client; | 124 return client; |
126 } | 125 } |
127 | 126 |
128 ChromeClient& Frame::GetChromeClient() const { | 127 ChromeClient& Frame::GetChromeClient() const { |
129 if (Page* page = this->GetPage()) | 128 if (Page* page = this->GetPage()) |
130 return page->GetChromeClient(); | 129 return page->GetChromeClient(); |
131 return GetEmptyChromeClient(); | 130 return GetEmptyChromeClient(); |
132 } | 131 } |
133 | 132 |
134 Frame* Frame::FindFrameForNavigation(const AtomicString& name, | 133 Frame* Frame::FindFrameForNavigation(const AtomicString& name, |
135 Frame& active_frame) { | 134 LocalFrame& active_frame) { |
136 Frame* frame = Tree().Find(name); | 135 Frame* frame = Tree().Find(name); |
137 if (!frame || !active_frame.CanNavigate(*frame)) | 136 if (!frame || !active_frame.CanNavigate(*frame)) |
138 return nullptr; | 137 return nullptr; |
139 return frame; | 138 return frame; |
140 } | 139 } |
141 | 140 |
142 static bool CanAccessAncestor(const SecurityOrigin& active_security_origin, | |
143 const Frame* target_frame) { | |
144 // targetFrame can be 0 when we're trying to navigate a top-level frame | |
145 // that has a 0 opener. | |
146 if (!target_frame) | |
147 return false; | |
148 | |
149 const bool is_local_active_origin = active_security_origin.IsLocal(); | |
150 for (const Frame* ancestor_frame = target_frame; ancestor_frame; | |
151 ancestor_frame = ancestor_frame->Tree().Parent()) { | |
152 const SecurityOrigin* ancestor_security_origin = | |
153 ancestor_frame->GetSecurityContext()->GetSecurityOrigin(); | |
154 if (active_security_origin.CanAccess(ancestor_security_origin)) | |
155 return true; | |
156 | |
157 // Allow file URL descendant navigation even when | |
158 // allowFileAccessFromFileURLs is false. | |
159 // FIXME: It's a bit strange to special-case local origins here. Should we | |
160 // be doing something more general instead? | |
161 if (is_local_active_origin && ancestor_security_origin->IsLocal()) | |
162 return true; | |
163 } | |
164 | |
165 return false; | |
166 } | |
167 | |
168 bool Frame::CanNavigate(const Frame& target_frame) { | |
169 String error_reason; | |
170 const bool is_allowed_navigation = | |
171 CanNavigateWithoutFramebusting(target_frame, error_reason); | |
172 const bool sandboxed = | |
173 GetSecurityContext()->GetSandboxFlags() != kSandboxNone; | |
174 const bool has_user_gesture = | |
175 IsLocalFrame() ? ToLocalFrame(this)->HasReceivedUserGesture() : false; | |
176 | |
177 // Top navigation in sandbox with or w/o 'allow-top-navigation'. | |
178 if (target_frame != this && sandboxed && target_frame == Tree().Top()) { | |
179 UseCounter::Count(&target_frame, UseCounter::kTopNavInSandbox); | |
180 if (!has_user_gesture) { | |
181 UseCounter::Count(&target_frame, | |
182 UseCounter::kTopNavInSandboxWithoutGesture); | |
183 } | |
184 } | |
185 | |
186 // Top navigation w/o sandbox or in sandbox with 'allow-top-navigation'. | |
187 if (target_frame != this && | |
188 !GetSecurityContext()->IsSandboxed(kSandboxTopNavigation) && | |
189 target_frame == Tree().Top()) { | |
190 DEFINE_STATIC_LOCAL(EnumerationHistogram, framebust_histogram, | |
191 ("WebCore.Framebust", 4)); | |
192 const unsigned kUserGestureBit = 0x1; | |
193 const unsigned kAllowedBit = 0x2; | |
194 unsigned framebust_params = 0; | |
195 UseCounter::Count(&target_frame, UseCounter::kTopNavigationFromSubFrame); | |
196 | |
197 if (has_user_gesture) | |
198 framebust_params |= kUserGestureBit; | |
199 if (sandboxed) { // Sandboxed with 'allow-top-navigation'. | |
200 UseCounter::Count(&target_frame, UseCounter::kTopNavInSandboxWithPerm); | |
201 if (!has_user_gesture) { | |
202 UseCounter::Count(&target_frame, | |
203 UseCounter::kTopNavInSandboxWithPermButNoGesture); | |
204 } | |
205 } | |
206 | |
207 if (is_allowed_navigation) | |
208 framebust_params |= kAllowedBit; | |
209 framebust_histogram.Count(framebust_params); | |
210 if (has_user_gesture || is_allowed_navigation) | |
211 return true; | |
212 // Frame-busting used to be generally allowed in most situations, but may | |
213 // now blocked if the document initiating the navigation has never received | |
214 // a user gesture. | |
215 if (!RuntimeEnabledFeatures:: | |
216 framebustingNeedsSameOriginOrUserGestureEnabled()) { | |
217 String target_frame_description = | |
218 target_frame.IsLocalFrame() ? "with URL '" + | |
219 ToLocalFrame(target_frame) | |
220 .GetDocument() | |
221 ->Url() | |
222 .GetString() + | |
223 "'" | |
224 : "with origin '" + | |
225 target_frame.GetSecurityContext() | |
226 ->GetSecurityOrigin() | |
227 ->ToString() + | |
228 "'"; | |
229 String message = "Frame with URL '" + | |
230 ToLocalFrame(this)->GetDocument()->Url().GetString() + | |
231 "' attempted to navigate its top-level window " + | |
232 target_frame_description + | |
233 ". Navigating the top-level window from a cross-origin " | |
234 "iframe will soon require that the iframe has received " | |
235 "a user gesture. See " | |
236 "https://www.chromestatus.com/features/" | |
237 "5851021045661696."; | |
238 PrintNavigationWarning(message); | |
239 return true; | |
240 } | |
241 error_reason = | |
242 "The frame attempting navigation is targeting its top-level window, " | |
243 "but is neither same-origin with its target nor has it received a " | |
244 "user gesture. See " | |
245 "https://www.chromestatus.com/features/5851021045661696."; | |
246 PrintNavigationErrorMessage(target_frame, error_reason.Latin1().data()); | |
247 if (IsLocalFrame()) { | |
248 ToLocalFrame(this)->GetNavigationScheduler().SchedulePageBlock( | |
249 ToLocalFrame(this)->GetDocument(), ResourceError::ACCESS_DENIED); | |
250 } | |
251 return false; | |
252 } | |
253 if (!is_allowed_navigation && !error_reason.IsNull()) | |
254 PrintNavigationErrorMessage(target_frame, error_reason.Latin1().data()); | |
255 return is_allowed_navigation; | |
256 } | |
257 | |
258 bool Frame::CanNavigateWithoutFramebusting(const Frame& target_frame, | |
259 String& reason) { | |
260 if (&target_frame == this) | |
261 return true; | |
262 | |
263 if (GetSecurityContext()->IsSandboxed(kSandboxNavigation)) { | |
264 if (!target_frame.Tree().IsDescendantOf(this) && | |
265 !target_frame.IsMainFrame()) { | |
266 reason = | |
267 "The frame attempting navigation is sandboxed, and is therefore " | |
268 "disallowed from navigating its ancestors."; | |
269 return false; | |
270 } | |
271 | |
272 // Sandboxed frames can also navigate popups, if the | |
273 // 'allow-sandbox-escape-via-popup' flag is specified, or if | |
274 // 'allow-popups' flag is specified, or if the | |
275 if (target_frame.IsMainFrame() && target_frame != Tree().Top() && | |
276 GetSecurityContext()->IsSandboxed( | |
277 kSandboxPropagatesToAuxiliaryBrowsingContexts) && | |
278 (GetSecurityContext()->IsSandboxed(kSandboxPopups) || | |
279 target_frame.Client()->Opener() != this)) { | |
280 reason = | |
281 "The frame attempting navigation is sandboxed and is trying " | |
282 "to navigate a popup, but is not the popup's opener and is not " | |
283 "set to propagate sandboxing to popups."; | |
284 return false; | |
285 } | |
286 | |
287 // Top navigation is forbidden unless opted-in. allow-top-navigation or | |
288 // allow-top-navigation-by-user-activation will also skips origin checks. | |
289 if (target_frame == Tree().Top()) { | |
290 if (GetSecurityContext()->IsSandboxed(kSandboxTopNavigation) && | |
291 GetSecurityContext()->IsSandboxed( | |
292 kSandboxTopNavigationByUserActivation)) { | |
293 reason = | |
294 "The frame attempting navigation of the top-level window is " | |
295 "sandboxed, but the flag of 'allow-top-navigation' or " | |
296 "'allow-top-navigation-by-user-activation' is not set."; | |
297 return false; | |
298 } | |
299 if (GetSecurityContext()->IsSandboxed(kSandboxTopNavigation) && | |
300 !GetSecurityContext()->IsSandboxed( | |
301 kSandboxTopNavigationByUserActivation) && | |
302 !UserGestureIndicator::ProcessingUserGesture()) { | |
303 // With only 'allow-top-navigation-by-user-activation' (but not | |
304 // 'allow-top-navigation'), top navigation requires a user gesture. | |
305 reason = | |
306 "The frame attempting navigation of the top-level window is " | |
307 "sandboxed with the 'allow-top-navigation-by-user-activation' " | |
308 "flag, but has no user activation (aka gesture). See " | |
309 "https://www.chromestatus.com/feature/5629582019395584."; | |
310 return false; | |
311 } | |
312 return true; | |
313 } | |
314 } | |
315 | |
316 DCHECK(GetSecurityContext()->GetSecurityOrigin()); | |
317 SecurityOrigin& origin = *GetSecurityContext()->GetSecurityOrigin(); | |
318 | |
319 // This is the normal case. A document can navigate its decendant frames, | |
320 // or, more generally, a document can navigate a frame if the document is | |
321 // in the same origin as any of that frame's ancestors (in the frame | |
322 // hierarchy). | |
323 // | |
324 // See http://www.adambarth.com/papers/2008/barth-jackson-mitchell.pdf for | |
325 // historical information about this security check. | |
326 if (CanAccessAncestor(origin, &target_frame)) | |
327 return true; | |
328 | |
329 // Top-level frames are easier to navigate than other frames because they | |
330 // display their URLs in the address bar (in most browsers). However, there | |
331 // are still some restrictions on navigation to avoid nuisance attacks. | |
332 // Specifically, a document can navigate a top-level frame if that frame | |
333 // opened the document or if the document is the same-origin with any of | |
334 // the top-level frame's opener's ancestors (in the frame hierarchy). | |
335 // | |
336 // In both of these cases, the document performing the navigation is in | |
337 // some way related to the frame being navigate (e.g., by the "opener" | |
338 // and/or "parent" relation). Requiring some sort of relation prevents a | |
339 // document from navigating arbitrary, unrelated top-level frames. | |
340 if (!target_frame.Tree().Parent()) { | |
341 if (target_frame == Client()->Opener()) | |
342 return true; | |
343 if (CanAccessAncestor(origin, target_frame.Client()->Opener())) | |
344 return true; | |
345 } | |
346 | |
347 reason = | |
348 "The frame attempting navigation is neither same-origin with the target, " | |
349 "nor is it the target's parent or opener."; | |
350 return false; | |
351 } | |
352 | |
353 Frame* Frame::FindUnsafeParentScrollPropagationBoundary() { | 141 Frame* Frame::FindUnsafeParentScrollPropagationBoundary() { |
354 Frame* current_frame = this; | 142 Frame* current_frame = this; |
355 Frame* ancestor_frame = Tree().Parent(); | 143 Frame* ancestor_frame = Tree().Parent(); |
356 | 144 |
357 while (ancestor_frame) { | 145 while (ancestor_frame) { |
358 if (!ancestor_frame->GetSecurityContext()->GetSecurityOrigin()->CanAccess( | 146 if (!ancestor_frame->GetSecurityContext()->GetSecurityOrigin()->CanAccess( |
359 GetSecurityContext()->GetSecurityOrigin())) | 147 GetSecurityContext()->GetSecurityOrigin())) |
360 return current_frame; | 148 return current_frame; |
361 current_frame = ancestor_frame; | 149 current_frame = ancestor_frame; |
362 ancestor_frame = ancestor_frame->Tree().Parent(); | 150 ancestor_frame = ancestor_frame->Tree().Parent(); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
430 is_loading_(false) { | 218 is_loading_(false) { |
431 InstanceCounters::IncrementCounter(InstanceCounters::kFrameCounter); | 219 InstanceCounters::IncrementCounter(InstanceCounters::kFrameCounter); |
432 | 220 |
433 if (owner_) | 221 if (owner_) |
434 owner_->SetContentFrame(*this); | 222 owner_->SetContentFrame(*this); |
435 else | 223 else |
436 page_->SetMainFrame(this); | 224 page_->SetMainFrame(this); |
437 } | 225 } |
438 | 226 |
439 } // namespace blink | 227 } // namespace blink |
OLD | NEW |