Page MenuHomePhabricator

OOUI's 'href' validation lets through unsafe URLs
Closed, ResolvedPublic

Description

OOUI's 'href' validation still lets through unsafe URLs.

These fail with exceptions, as they should:

new OOUI\ButtonWidget( array( 'href' => "javascript:alert()", 'label' => 'Normal' ) ),
new OO.ui.ButtonWidget( { href: 'javascript:alert()', label: 'Normal' } ),

But these pass, and result in buttons that execute JavaScript when clicked: (adapted from https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Embedded_newline_to_break_up_XSS)

new OOUI\ButtonWidget( array( 'href' => "java\nscript:alert()", 'label' => 'Normal' ) ),
new OO.ui.ButtonWidget( { href: 'java\nscript:alert()', label: 'Normal' } ),

Both the PHP and the JavaScript code incorrectly treat this as a relative link (they don't recognize that it has a protocol at all). Browsers happily ignore the \n and execute the script upon clicking.

Unless we have some battle-tested URI parsing library handy, I think we should give up on relative URLs and reject everything that doesn't start with a) a whitelisted protocol b) a slash.

Event Timeline

matmarex raised the priority of this task from to Needs Triage.
matmarex updated the task description. (Show Details)
matmarex added projects: Vuln-XSS, acl*security, OOUI.
matmarex changed the visibility from "Public (No Login Required)" to "Custom Policy".
matmarex changed the edit policy from "All Users" to "Custom Policy".
matmarex changed Security from None to Software security bug.
matmarex added subscribers: csteipp, Legoktm, matmarex, Krinkle.

I don't know much about OOUI, but if we're just talking about urls that programmers can create (from like javascript), than I don't see why filtering the protocols is needed. If we're talking about things that users can create, I don't think we want them to be able to create arbitrary (even safe) urls, as then they can get around spam blacklists, etc.

Yes, it was added "just in case" (in 16eb98d463e486a4ee52423509c36d6c773653c1 per T75156: Security review of OOjs UI's PHP implementation). (Even that commit says, "I am not entirely sure about the last one; seems like this really should be the library's user's responsibility to validate. But it shouldn't hurt to have it.") I also think it would be okay to remove that check and just very explicitly document that unsafe URLs will be output as-is.

matmarex added a subscriber: Schnark.

So, I think we should get rid of the filtering. Any objections? If there are none, I'll make this bug public and submit public patches for it.

So, I think we should get rid of the filtering. Any objections? If there are none, I'll make this bug public and submit public patches for it.

I haven't been tracking this closely, but is your original,

I think we should give up on relative URLs and reject everything that doesn't start with a) a whitelisted protocol b) a slash.

what is happening now?

In general, I agree with bawolff's comment, except that I'm always nervous that someone is going to add a feature to pass through user controlled content into what we typically consider to be a programmer's interface. But if it's clearly documented, and there are no extensions doing something like that currently, then we can go ahead and do that.

That would be a breaking change now (some relative URLs that were previously accepted would now cause exceptions), and we'd presumably need a config option like allowUnsafeHref to accept them. Not sure how James feels about that.

On further thought, we should rather reject everything that doesn't start with a) a whitelisted protocol b) a slash / or c) a dot and a slash ./. It would still be a technically breaking change, but we wouldn't need any weird config options (relative URLs should just be prefixed with ./ to indicate they're safe, and make them definitely be so).

As far as I know this is not a security problem for anything right now, so I submitted a draft of the patch to Gerrit: https://gerrit.wikimedia.org/r/#/c/263534/ (drafts are not publicly visible, but not exactly safe either) and added everyone subscribed here as a reviewer.

matmarex claimed this task.
matmarex removed a project: Patch-For-Review.
matmarex changed the visibility from "Custom Policy" to "Public (No Login Required)".
matmarex changed the edit policy from "Custom Policy" to "All Users".
Restricted Application changed the visibility from "Public (No Login Required)" to "Custom Policy". · View Herald TranscriptJan 13 2016, 10:27 PM
Restricted Application changed the edit policy from "All Users" to "Custom Policy". · View Herald Transcript
Restricted Application added a subscriber: Luke081515. · View Herald Transcript
matmarex changed the visibility from "Custom Policy" to "Public (No Login Required)".Jan 13 2016, 10:27 PM
matmarex changed the edit policy from "Custom Policy" to "All Users".
matmarex changed Security from Software security bug to None.

https://gerrit.wikimedia.org/r/#/c/263534/ merged now. I really like the ./-prefixing solution, by the way.

On further thought, we should rather reject everything that doesn't start with a) a whitelisted protocol b) a slash / or c) a dot and a slash ./. It would still be a technically breaking change, but we wouldn't need any weird config options (relative URLs should just be prefixed with ./ to indicate they're safe, and make them definitely be so).

It turned out that we have to also allow ? and # at the beginning. ./ does mean "current directory" and not "current file", after all, and prepending these with it would lose the current file name.