Download & Extend

url_is_external() is badly documented

Project:Drupal core
Version:7.x-dev
Component:base system
Category:task
Priority:normal
Assigned:Unassigned
Status:closed (fixed)
Issue tags:documentation

Issue Summary

url_is_external() is either broken or misnamed. It does not check that a URL is external to the calling website. It checks that the URL is absolute. Huge difference.

What is the desired behavior:

1) Check that a URL is absolute (and therefore not subject to Drupal access control and potentially malicious)?

2) Check that a URL goes off the current site?

If #2, we aren't doing that by verifying the URL against $base_url.

If #1, the function should be renamed url_is_absolute().

Comments

#1

Status:active» needs review

Rescinded. It means 'external' to Drupal. Patch for clarification to the docblock.

AttachmentSizeStatusTest resultOperations
819844-external.patch599 bytesIdlePASSED: [[SimpleTest]]: [MySQL] 20,597 pass(es).View details

#2

Category:bug report» task

#3

Status:needs review» needs work

I'm still confused, what does "external to drupal" mean? Would a non-drupal path like "phpbb2/viewforum.php" be considered "external to drupal"? What about an absolute URL with a domain that matches HTTP_HOST?

#4

huh, this function seems bogus... if the scheme isn't in the list allowed by filter_xss_bad_protocol, it returns FALSE which is clearly wrong for many schemes, e.g.:

file:///etc/services
gopher://example.com/
xmpp:user@example.com/

#5

Yes, it appears we may do better in filter_xss_bad_protocol() with a blacklist than a whitelist.... thoughts?

#6

@grendzy

You shouldn't be able to process a path like 'phpbb2/viewforum.php' through any of Drupal's URL handling functions. It would have to be absolute.

What about an absolute URL with a domain that matches HTTP_HOST?

That was my question at first, too.

I think the intent of this function is actually url_is_absolute().

This might need to be bumped to critical, as it's clearly a big WTF.

#7

I'm struggling to understand why url_is_external uses filter_xss_bad_protocol at all; it doesn't seem relevant.

That said we need a whitelist for filter_xss_bad_protocol since new dangerous schemes can be introduced at any time.

BTW this was named menu_path_is_external in D6.

#8

found the issue that introduced this change: #607008: Fix bugs in https support and force using https for authorize.php if available

If the indented use was only within the context of the menu router system, perhaps the old name was better after all. The new name seems to imply the function can be used to test any URL, which it clearly cannot.

#9

If by "old name" you mean "menu_path_is_external()", then no, the old name was worse. ;) The function didn't have anything to do with the menu system per se, but it was named as if it did, and lived in menu.inc, which sucked for authorize.php wanting to use it, since it would have meant loading nearly 3400 lines of code we don't want to have to rely on inside authorize.php just to reuse this small helper function.

I'll admit to not fully understanding what we're doing with filter_xss_bad_protocol() in here. To answer that, you'd have to read through #131009: Menu bugfixes: 40x pages, external items, parenting and/or get chx to comment here, since that's the issue where the original menu_path_is_external() function was added.

I *though* this was a better function name, and that it was fairly well documented. ;) Sorry, but I don't have the cycles right now to fully parse your objections and resulting confusion. I'm happy to try to help improve things, but I've got a ton of other stuff on my plate right now.

Thanks/sorry,
-Derek

#10

I read through the two issues that @dww posted, and I see the purpose behind the change.

I think this just needs clarifying documentation, (to make it clear that the function is designed to assert that a url is not govered by Drupal's menu access control system). It also means a refactor of #733028: SA-CORE-2010-001 - Open redirection to _not_ use this function or to change its inline documentation to note that the security check is only for whether Drupal's menu system can assert access control.

#11

Status:needs work» needs review

Patch that improves the documentation (which is missing @param currently).

AttachmentSizeStatusTest resultOperations
819844-external.patch5.9 KBIdlePASSED: [[SimpleTest]]: [MySQL] 20,700 pass(es).View details

#12

Title:url_is_external() is badly named» url_is_external() is badly documented

#13

Status:needs review» needs work

Cool, thanks for looking into all this! However, #11 includes hunks for modules/system/system.install and modules/system/system.test that are unrelated to this issue.

#14

Oops! Actually, it is related (it's how we found this problem), it's just not wanted here.

#15

Status:needs work» needs review

Fixed.

AttachmentSizeStatusTest resultOperations
819844-external-doc.patch926 bytesIdlePASSED: [[SimpleTest]]: [MySQL] 20,674 pass(es).View details

#16

Status:needs review» reviewed & tested by the community

Looks good to me, thanks!

#17

+1
looks good. Thanks for unraveling this mystery.

#18

Status:reviewed & tested by the community» fixed

Committed to CVS HEAD. Thanks.

#19

Status:fixed» closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

nobody click here