Repository navigation
Conversation
buildNewStateUrl() resolved the url argument and History then wrote it into the URL of the page without any origin check, so a page could set its URL to any other origin or scheme. HtmlUnit takes the origin of a page from that URL (document.cookie, the same-origin check of XMLHttpRequest, the local resource check for frames), so after history.replaceState(null, '', 'http://other/') a page could read the cookies of the other site and read its responses without CORS. Throw a SecurityError if the new url is not same origin with the document url, like the browsers do.
|
Member
|
Thanks, will have a look on monday |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Repro: a page on
http://attacker.test/callshistory.replaceState(null, '', 'http://victim.test/'). From then onlocation.hrefanddocument.domainreport victim.test,document.cookiereturns the (non-HttpOnly) cookies the WebClient holds for victim.test, and a plainXMLHttpRequesttohttp://victim.test/apiwithout any CORS headers returns 200 with the body, where the same request failed before the call. AfterreplaceState(null, '', 'file:///')the page can add an<iframe src="file:///...html">and read the local file, because the local resource check inBaseFrameElementlooks at the page url. Chrome and Firefox throw a SecurityError for these calls.Cause:
History.buildNewStateUrl()resolves the url argument andpushState()/replaceState()write it into the url of the page without comparing origins. HtmlUnit takes the origin of a page from that url (cookies, the same-origin decision of XMLHttpRequest, local file access), so the page can pick any origin it likes.Fix: throw a SecurityError from
buildNewStateUrl()if the new url is not same origin (UrlUtils.isSameOrigin(): scheme, host and port) with the document url, following the "can have its URL rewritten" steps of the HTML spec. Both methods go through this helper; same-origin changes of path, query and fragment work as before. The stricter spec rules for file: paths and non-http schemes are not part of this change.pushStateCrossOrigin,replaceStateCrossOriginandreplaceStateFileUrlinHistory2Testfail without the change (the page url becomeshttp://localhost:22223/orfile:///).History2Test,HistoryTest,org.htmlunit.History2Test,VueTest, the htmx 1.7.0, 1.9.12 and 2.0.10 library tests andCodeStyleTestpass. I also added a changes.xml entry.