Index: third_party/WebKit/Source/core/frame/Frame.cpp |
diff --git a/third_party/WebKit/Source/core/frame/Frame.cpp b/third_party/WebKit/Source/core/frame/Frame.cpp |
index 28a96d4a9feb27d840f133551d8a334524fcce92..23fdf4279db7e8df1975adee9c5973b1d692ed2e 100644 |
--- a/third_party/WebKit/Source/core/frame/Frame.cpp |
+++ b/third_party/WebKit/Source/core/frame/Frame.cpp |
@@ -45,7 +45,6 @@ |
#include "core/page/FocusController.h" |
#include "core/page/Page.h" |
#include "core/probe/CoreProbes.h" |
-#include "platform/Histogram.h" |
#include "platform/InstanceCounters.h" |
#include "platform/UserGestureIndicator.h" |
#include "platform/feature_policy/FeaturePolicy.h" |
@@ -132,224 +131,13 @@ ChromeClient& Frame::GetChromeClient() const { |
} |
Frame* Frame::FindFrameForNavigation(const AtomicString& name, |
- Frame& active_frame) { |
+ LocalFrame& active_frame) { |
Frame* frame = Tree().Find(name); |
if (!frame || !active_frame.CanNavigate(*frame)) |
return nullptr; |
return frame; |
} |
-static bool CanAccessAncestor(const SecurityOrigin& active_security_origin, |
- const Frame* target_frame) { |
- // targetFrame can be 0 when we're trying to navigate a top-level frame |
- // that has a 0 opener. |
- if (!target_frame) |
- return false; |
- |
- const bool is_local_active_origin = active_security_origin.IsLocal(); |
- for (const Frame* ancestor_frame = target_frame; ancestor_frame; |
- ancestor_frame = ancestor_frame->Tree().Parent()) { |
- const SecurityOrigin* ancestor_security_origin = |
- ancestor_frame->GetSecurityContext()->GetSecurityOrigin(); |
- if (active_security_origin.CanAccess(ancestor_security_origin)) |
- return true; |
- |
- // Allow file URL descendant navigation even when |
- // allowFileAccessFromFileURLs is false. |
- // FIXME: It's a bit strange to special-case local origins here. Should we |
- // be doing something more general instead? |
- if (is_local_active_origin && ancestor_security_origin->IsLocal()) |
- return true; |
- } |
- |
- return false; |
-} |
- |
-bool Frame::CanNavigate(const Frame& target_frame) { |
- String error_reason; |
- const bool is_allowed_navigation = |
- CanNavigateWithoutFramebusting(target_frame, error_reason); |
- const bool sandboxed = |
- GetSecurityContext()->GetSandboxFlags() != kSandboxNone; |
- const bool has_user_gesture = |
- IsLocalFrame() ? ToLocalFrame(this)->HasReceivedUserGesture() : false; |
- |
- // Top navigation in sandbox with or w/o 'allow-top-navigation'. |
- if (target_frame != this && sandboxed && target_frame == Tree().Top()) { |
- UseCounter::Count(&target_frame, UseCounter::kTopNavInSandbox); |
- if (!has_user_gesture) { |
- UseCounter::Count(&target_frame, |
- UseCounter::kTopNavInSandboxWithoutGesture); |
- } |
- } |
- |
- // Top navigation w/o sandbox or in sandbox with 'allow-top-navigation'. |
- if (target_frame != this && |
- !GetSecurityContext()->IsSandboxed(kSandboxTopNavigation) && |
- target_frame == Tree().Top()) { |
- DEFINE_STATIC_LOCAL(EnumerationHistogram, framebust_histogram, |
- ("WebCore.Framebust", 4)); |
- const unsigned kUserGestureBit = 0x1; |
- const unsigned kAllowedBit = 0x2; |
- unsigned framebust_params = 0; |
- UseCounter::Count(&target_frame, UseCounter::kTopNavigationFromSubFrame); |
- |
- if (has_user_gesture) |
- framebust_params |= kUserGestureBit; |
- if (sandboxed) { // Sandboxed with 'allow-top-navigation'. |
- UseCounter::Count(&target_frame, UseCounter::kTopNavInSandboxWithPerm); |
- if (!has_user_gesture) { |
- UseCounter::Count(&target_frame, |
- UseCounter::kTopNavInSandboxWithPermButNoGesture); |
- } |
- } |
- |
- if (is_allowed_navigation) |
- framebust_params |= kAllowedBit; |
- framebust_histogram.Count(framebust_params); |
- if (has_user_gesture || is_allowed_navigation) |
- return true; |
- // Frame-busting used to be generally allowed in most situations, but may |
- // now blocked if the document initiating the navigation has never received |
- // a user gesture. |
- if (!RuntimeEnabledFeatures:: |
- framebustingNeedsSameOriginOrUserGestureEnabled()) { |
- String target_frame_description = |
- target_frame.IsLocalFrame() ? "with URL '" + |
- ToLocalFrame(target_frame) |
- .GetDocument() |
- ->Url() |
- .GetString() + |
- "'" |
- : "with origin '" + |
- target_frame.GetSecurityContext() |
- ->GetSecurityOrigin() |
- ->ToString() + |
- "'"; |
- String message = "Frame with URL '" + |
- ToLocalFrame(this)->GetDocument()->Url().GetString() + |
- "' attempted to navigate its top-level window " + |
- target_frame_description + |
- ". Navigating the top-level window from a cross-origin " |
- "iframe will soon require that the iframe has received " |
- "a user gesture. See " |
- "https://www.chromestatus.com/features/" |
- "5851021045661696."; |
- PrintNavigationWarning(message); |
- return true; |
- } |
- error_reason = |
- "The frame attempting navigation is targeting its top-level window, " |
- "but is neither same-origin with its target nor has it received a " |
- "user gesture. See " |
- "https://www.chromestatus.com/features/5851021045661696."; |
- PrintNavigationErrorMessage(target_frame, error_reason.Latin1().data()); |
- if (IsLocalFrame()) { |
- ToLocalFrame(this)->GetNavigationScheduler().SchedulePageBlock( |
- ToLocalFrame(this)->GetDocument(), ResourceError::ACCESS_DENIED); |
- } |
- return false; |
- } |
- if (!is_allowed_navigation && !error_reason.IsNull()) |
- PrintNavigationErrorMessage(target_frame, error_reason.Latin1().data()); |
- return is_allowed_navigation; |
-} |
- |
-bool Frame::CanNavigateWithoutFramebusting(const Frame& target_frame, |
- String& reason) { |
- if (&target_frame == this) |
- return true; |
- |
- if (GetSecurityContext()->IsSandboxed(kSandboxNavigation)) { |
- if (!target_frame.Tree().IsDescendantOf(this) && |
- !target_frame.IsMainFrame()) { |
- reason = |
- "The frame attempting navigation is sandboxed, and is therefore " |
- "disallowed from navigating its ancestors."; |
- return false; |
- } |
- |
- // Sandboxed frames can also navigate popups, if the |
- // 'allow-sandbox-escape-via-popup' flag is specified, or if |
- // 'allow-popups' flag is specified, or if the |
- if (target_frame.IsMainFrame() && target_frame != Tree().Top() && |
- GetSecurityContext()->IsSandboxed( |
- kSandboxPropagatesToAuxiliaryBrowsingContexts) && |
- (GetSecurityContext()->IsSandboxed(kSandboxPopups) || |
- target_frame.Client()->Opener() != this)) { |
- reason = |
- "The frame attempting navigation is sandboxed and is trying " |
- "to navigate a popup, but is not the popup's opener and is not " |
- "set to propagate sandboxing to popups."; |
- return false; |
- } |
- |
- // Top navigation is forbidden unless opted-in. allow-top-navigation or |
- // allow-top-navigation-by-user-activation will also skips origin checks. |
- if (target_frame == Tree().Top()) { |
- if (GetSecurityContext()->IsSandboxed(kSandboxTopNavigation) && |
- GetSecurityContext()->IsSandboxed( |
- kSandboxTopNavigationByUserActivation)) { |
- reason = |
- "The frame attempting navigation of the top-level window is " |
- "sandboxed, but the flag of 'allow-top-navigation' or " |
- "'allow-top-navigation-by-user-activation' is not set."; |
- return false; |
- } |
- if (GetSecurityContext()->IsSandboxed(kSandboxTopNavigation) && |
- !GetSecurityContext()->IsSandboxed( |
- kSandboxTopNavigationByUserActivation) && |
- !UserGestureIndicator::ProcessingUserGesture()) { |
- // With only 'allow-top-navigation-by-user-activation' (but not |
- // 'allow-top-navigation'), top navigation requires a user gesture. |
- reason = |
- "The frame attempting navigation of the top-level window is " |
- "sandboxed with the 'allow-top-navigation-by-user-activation' " |
- "flag, but has no user activation (aka gesture). See " |
- "https://www.chromestatus.com/feature/5629582019395584."; |
- return false; |
- } |
- return true; |
- } |
- } |
- |
- DCHECK(GetSecurityContext()->GetSecurityOrigin()); |
- SecurityOrigin& origin = *GetSecurityContext()->GetSecurityOrigin(); |
- |
- // This is the normal case. A document can navigate its decendant frames, |
- // or, more generally, a document can navigate a frame if the document is |
- // in the same origin as any of that frame's ancestors (in the frame |
- // hierarchy). |
- // |
- // See http://www.adambarth.com/papers/2008/barth-jackson-mitchell.pdf for |
- // historical information about this security check. |
- if (CanAccessAncestor(origin, &target_frame)) |
- return true; |
- |
- // Top-level frames are easier to navigate than other frames because they |
- // display their URLs in the address bar (in most browsers). However, there |
- // are still some restrictions on navigation to avoid nuisance attacks. |
- // Specifically, a document can navigate a top-level frame if that frame |
- // opened the document or if the document is the same-origin with any of |
- // the top-level frame's opener's ancestors (in the frame hierarchy). |
- // |
- // In both of these cases, the document performing the navigation is in |
- // some way related to the frame being navigate (e.g., by the "opener" |
- // and/or "parent" relation). Requiring some sort of relation prevents a |
- // document from navigating arbitrary, unrelated top-level frames. |
- if (!target_frame.Tree().Parent()) { |
- if (target_frame == Client()->Opener()) |
- return true; |
- if (CanAccessAncestor(origin, target_frame.Client()->Opener())) |
- return true; |
- } |
- |
- reason = |
- "The frame attempting navigation is neither same-origin with the target, " |
- "nor is it the target's parent or opener."; |
- return false; |
-} |
- |
Frame* Frame::FindUnsafeParentScrollPropagationBoundary() { |
Frame* current_frame = this; |
Frame* ancestor_frame = Tree().Parent(); |