Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle empty and malformed $_SERVER request variables #122

Conversation

BrianHenryIE
Copy link
Contributor

When WordPress is loaded locally, i.e. without a HTTP request, the expected $_SERVER['REQUEST_METHOD'] is not set, resulting in PHP Notice: Undefined index: REQUEST_METHOD in /path/to/wp-content/plugins/satispress/src/ServiceProvider.php on line 156 being logged.

The commit checks if WordPress is DOING_CRON and if so, returns a instantiated but unconfigured Request (WP_REST_Request) object.

When WordPress is loaded locally, i.e. without a HTTP request, the expected `$_SERVER['REQUEST_METHOD']` is not set, resulting in `PHP Notice: Undefined index: REQUEST_METHOD in /path/to/wp-content/plugins/satispress/src/ServiceProvider.php on line 156` being logged.

The commit checks if WordPress is `DOING_CRON` and if so, returns a instantiated but unconfigured `Request` (`WP_REST_Request`) object.
@bradyvercher
Copy link
Member

Thanks for the PR, @BrianHenryIE! Rather than check wp_doing_cron(), let's just check to see if that REQUEST_METHOD key exists and return the default if not:

$request = new Request( $_SERVER['REQUEST_METHOD'] ?? '' );

Does that work for you?

As per discussion on PR
Fix for:

PHP Fatal error: Uncaught TypeError: ltrim() expects parameter 1 to be a string, bool given

`get_request_path()` is called in two places: `authentication.php:83` and `authentication.php:164`, both then preform a string function to determine true/false, so returning an empty string shoud work fine here.
@BrianHenryIE
Copy link
Contributor Author

Yeah, that should work too. I wrote it as a cron check because I was being too lazy too consider any other means of invocation. It probably affects wp shell too.

I had another two related logs this morning. get_request_path() is parsing $_SERVER['REQUEST_URI'] and failing at ltrim() so I'm returning an empty string early, which the two calling methods should be happy with.

@bradyvercher
Copy link
Member

Can you clarify how you're loading WordPress that's causing those notices to be triggered? I believe WordPress should populate $_SERVER['REQUEST_URI'] fairly early in the bootstrap process, so I'm curious when this would be an issue.

@BrianHenryIE
Copy link
Contributor Author

I looked at my transfer logs and it seems that was triggered by:
"GET ///?author=1 HTTP/1.1" 500 2836 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:62) Gecko/20100101 Firefox/62.0"

So $_SERVER['REQUEST_URI'] = ///?author=1 (not empty as I assumed).

?author=1 is a username phishing attempt but I'm not sure what the sequence of / is for.

They're causing wp_parse_url() to return false.

The multiple sequential / could be reduced to one in all cases except :// with:
$request_uri = preg_replace( '/(?<!:)\/{2,}/', '/', $_SERVER['REQUEST_URI']);

but that doesn't seem like the right way to address it.

@bradyvercher
Copy link
Member

Was that request also the one that causes that issue that led to e6a7a67? Or is that unrelated?

It looks like WordPress does a lot of processing to determine the request path. I'd rather not parse the URI more than absolutely necessary, especially since this is for an invalid request.

Since that method is really only used for determining if it's a SatisPress request, we could either ltrim() slashes before passing the URI to wp_parse_url(), or handle cases where wp_parse_url() returns false, which apparently has been an issue before.

@BrianHenryIE
Copy link
Contributor Author

So, two unrelated requests. First is from starting WordPress via cron or command line. Second is via HTTP with a malformed REQUEST_URI. Sorry for mixing up the PR.

I think the wp_parse_url() should really be taking care of the extra slashes, so wouldn't bother here. It's safe to assume a malformed REQUEST_URI is not going to be a SatisPress request. The two places get_request_path() is used, register_hooks() and is_satispress_request(), both run strpos() on the result so I suggest returning an empty string if the URL isn't successfully parsed, i.e.

if( false === $request_path ) {
	return '';
}

That should accommodate other malformed URLs that might come up, and the behaviour is still correct.

@bradyvercher
Copy link
Member

Thanks for the explanation. I just wanted to make sure I understood when these issues were occurring. If you want to push up that fix, I'll get this merged.

Discovered when: `$_SERVER['REQUEST_URI'] = ///?author=1` (possible [phishing attempt](https://htaccessbook.com/block-user-id-phishing/))
@BrianHenryIE BrianHenryIE changed the title Instantiate empty Request object during cron. Handle empty and malformed $_SERVER request variables Feb 6, 2020
@bradyvercher
Copy link
Member

Thanks @BrianHenryIE! I squashed a couple of commits and merged this manually, so it didn't close automatically, but they have been committed. I appreciate you reporting and discussing this. 🍻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants