Framesniffing defense is too aggressive.
https://bugs.webkit.org/show_bug.cgi?id=83721
Reviewed by James Robinson.
Source/WebCore:
The RenderLayer code currently propagates scroll position to parent frames
without any cross-origin checks. This gives it a quick origin boundary check
that is set by FrameLoader only when performing a fragment navigation. This
allows us to safely relax the restriction on not scrolling at load time in
FrameLoader since the safe thing will happen later on at scroll time.
Test: http/tests/navigation/anchor-frames-same-origin.html
* dom/Document.cpp:
(WebCore::Document::findUnsafeParentScrollPropagationBoundary):
* dom/Document.h:
(Document):
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::finishedParsing):
(WebCore::FrameLoader::loadInSameDocument):
(WebCore::FrameLoader::scrollToFragmentWithParentBoundary):
* loader/FrameLoader.h:
(FrameLoader):
* page/FrameView.cpp:
(WebCore::FrameView::FrameView):
(WebCore::FrameView::reset):
* page/FrameView.h:
(WebCore::FrameView::safeToPropagateScrollToParent):
(WebCore::FrameView::setSafeToPropagateScrollToParent):
(FrameView):
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::scrollRectToVisible):
LayoutTests:
* http/tests/inspector/resource-parameters-expected.txt:
* http/tests/navigation/anchor-frames-cross-origin-expected.txt:
* http/tests/navigation/anchor-frames-cross-origin.html:
* http/tests/navigation/anchor-frames-same-origin-expected.txt: Added.
* http/tests/navigation/anchor-frames-same-origin.html: Added.
* http/tests/navigation/resources/frame-with-anchor-cross-origin.html:
* http/tests/navigation/resources/frame-with-anchor-same-origin.html: Added.
* http/tests/navigation/resources/grandchild-with-anchor.html: Added.
* http/tests/security/xssAuditor/anchor-url-dom-write-location-expected.txt:
* http/tests/security/xssAuditor/anchor-url-dom-write-location-inline-event-expected.txt:
* http/tests/security/xssAuditor/anchor-url-dom-write-location-inline-event-null-char-expected.txt:
* http/tests/security/xssAuditor/anchor-url-dom-write-location-javascript-URL-expected.txt:
* http/tests/security/xssAuditor/anchor-url-dom-write-location2-expected.txt:
* http/tests/security/xssAuditor/dom-write-location-inline-event-expected.txt:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@114406 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp
index 1de8374..b1dc02c 100644
--- a/Source/WebCore/loader/FrameLoader.cpp
+++ b/Source/WebCore/loader/FrameLoader.cpp
@@ -662,7 +662,7 @@
// Check if the scrollbars are really needed for the content.
// If not, remove them, relayout, and repaint.
m_frame->view()->restoreScrollbar();
- scrollToFragmentIfAllowed(m_frame->document()->url());
+ scrollToFragmentWithParentBoundary(m_frame->document()->url());
}
void FrameLoader::loadDone()
@@ -1029,7 +1029,7 @@
// We need to scroll to the fragment whether or not a hash change occurred, since
// the user might have scrolled since the previous navigation.
- scrollToFragmentIfAllowed(url);
+ scrollToFragmentWithParentBoundary(url);
m_isComplete = false;
checkCompleted();
@@ -2618,20 +2618,22 @@
&& !m_frame->document()->isFrameSet();
}
-void FrameLoader::scrollToFragmentIfAllowed(const KURL& url)
+void FrameLoader::scrollToFragmentWithParentBoundary(const KURL& url)
{
FrameView* view = m_frame->view();
if (!view)
return;
// Leaking scroll position to a cross-origin ancestor would permit the so-called "framesniffing" attack.
- if (url.hasFragmentIdentifier() && !m_frame->document()->canBeAccessedByEveryAncestorFrame()) {
- DEFINE_STATIC_LOCAL(String, consoleMessage, ("Fragment navigation not allowed with cross-origin frames."));
- m_frame->domWindow()->console()->addMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, consoleMessage);
- return;
- }
+ RefPtr<Frame> boundaryFrame(url.hasFragmentIdentifier() ? m_frame->document()->findUnsafeParentScrollPropagationBoundary() : 0);
+
+ if (boundaryFrame)
+ boundaryFrame->view()->setSafeToPropagateScrollToParent(false);
view->scrollToFragment(url);
+
+ if (boundaryFrame)
+ boundaryFrame->view()->setSafeToPropagateScrollToParent(true);
}
void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument,