| 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 |