Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(564)

Unified Diff: third_party/WebKit/Source/core/frame/LocalFrame.cpp

Issue 2877893002: Make UseCounter take a LocaFrame instead of any Frame (Closed)
Patch Set: Fix compile Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/frame/LocalFrame.cpp
diff --git a/third_party/WebKit/Source/core/frame/LocalFrame.cpp b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
index dc18be7d650e04d21e1cc0a47fcbbd81c2ae5b36..3eefa4fb1b4e989b32a932a7221951863416ce44 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrame.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrame.cpp
@@ -80,6 +80,7 @@
#include "core/svg/SVGDocumentExtensions.h"
#include "core/timing/Performance.h"
#include "platform/DragImage.h"
+#include "platform/Histogram.h"
#include "platform/PluginScriptForbiddenScope.h"
#include "platform/RuntimeEnabledFeatures.h"
#include "platform/ScriptForbiddenScope.h"
@@ -919,6 +920,213 @@ void LocalFrame::ScheduleVisualUpdateUnlessThrottled() {
GetPage()->Animator().ScheduleVisualUpdate(this);
}
+bool LocalFrame::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 = HasReceivedUserGesture();
+
+ // Top navigation in sandbox with or w/o 'allow-top-navigation'.
+ if (target_frame != this && sandboxed && target_frame == Tree().Top()) {
+ UseCounter::Count(this, UseCounter::kTopNavInSandbox);
+ if (!has_user_gesture) {
+ UseCounter::Count(this, 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;
+
+ if (has_user_gesture)
+ framebust_params |= kUserGestureBit;
+
+ UseCounter::Count(this, UseCounter::kTopNavigationFromSubFrame);
+ if (sandboxed) { // Sandboxed with 'allow-top-navigation'.
+ UseCounter::Count(this, UseCounter::kTopNavInSandboxWithPerm);
+ if (!has_user_gesture) {
+ UseCounter::Count(this,
+ 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 '" + 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());
+ GetNavigationScheduler().SchedulePageBlock(GetDocument(),
+ ResourceError::ACCESS_DENIED);
+ return false;
+ }
+ if (!is_allowed_navigation && !error_reason.IsNull())
+ PrintNavigationErrorMessage(target_frame, error_reason.Latin1().data());
+ return is_allowed_navigation;
+}
+
+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 LocalFrame::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;
+}
+
LocalFrameClient* LocalFrame::Client() const {
return static_cast<LocalFrameClient*>(Frame::Client());
}
« no previous file with comments | « third_party/WebKit/Source/core/frame/LocalFrame.h ('k') | third_party/WebKit/Source/core/frame/UseCounter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698