mirror of
https://github.com/php/php-src.git
synced 2026-10-29 18:24:57 +08:00
ext/soap: truncate a user_agent containing newline characters (#22771)
GH-17976 sanitized user_agent where the HTTP wrapper emits headers and left the SOAP client alone, so a value carrying CRLF still injects request headers through all three of its sources: the SoapClient user_agent option, the http.user_agent stream context option, and the ini setting. Resolve the three to one zend_string and emit it through the same truncate-and-warn check the HTTP wrapper applies. Closes GH-22771
This commit is contained in:
1 parent
b5fba859ea
commit
3dcdb9826b
2 files changed
+75
-11
No files matched your search
+28
-11
@@ -25,6 +25,23 @@ static zend_string *get_http_headers(php_stream *socketd);
|
||||
#define smart_str_append_const(str, const) \
|
||||
smart_str_appendl(str,const,sizeof(const)-1)
|
||||
|
||||
static void soap_smart_str_append_header_value(smart_str *dest, const zend_string *value, const char *header_name)
|
||||
{
|
||||
const char *src = ZSTR_VAL(value);
|
||||
size_t len = ZSTR_LEN(value);
|
||||
size_t i = 0;
|
||||
while (i < len && src[i] != '\r' && src[i] != '\n') {
|
||||
i++;
|
||||
}
|
||||
if (i < len) {
|
||||
smart_str_appendl(dest, src, i);
|
||||
php_error_docref(NULL, E_WARNING,
|
||||
"Header %s value contains newline characters and has been truncated", header_name);
|
||||
} else {
|
||||
smart_str_append(dest, value);
|
||||
}
|
||||
}
|
||||
|
||||
/* Proxy HTTP Authentication */
|
||||
bool proxy_authentication(zval* this_ptr, smart_str* soap_headers)
|
||||
{
|
||||
@@ -607,25 +624,25 @@ try_again:
|
||||
smart_str_append_const(&soap_headers, "\r\n"
|
||||
"Connection: Keep-Alive\r\n");
|
||||
}
|
||||
zend_string *ua_str = NULL;
|
||||
|
||||
tmp = Z_CLIENT_USER_AGENT_P(this_ptr);
|
||||
if (Z_TYPE_P(tmp) == IS_STRING) {
|
||||
if (Z_STRLEN_P(tmp) > 0) {
|
||||
smart_str_append_const(&soap_headers, "User-Agent: ");
|
||||
smart_str_append(&soap_headers, Z_STR_P(tmp));
|
||||
smart_str_append_const(&soap_headers, "\r\n");
|
||||
}
|
||||
ua_str = Z_STR_P(tmp);
|
||||
} else if (context &&
|
||||
(tmp = php_stream_context_get_option(context, "http", "user_agent")) != NULL &&
|
||||
Z_TYPE_P(tmp) == IS_STRING) {
|
||||
if (Z_STRLEN_P(tmp) > 0) {
|
||||
ua_str = Z_STR_P(tmp);
|
||||
} else if (FG(user_agent)) {
|
||||
ua_str = FG(user_agent);
|
||||
}
|
||||
|
||||
if (ua_str) {
|
||||
if (ZSTR_LEN(ua_str) > 0) {
|
||||
smart_str_append_const(&soap_headers, "User-Agent: ");
|
||||
smart_str_append(&soap_headers, Z_STR_P(tmp));
|
||||
soap_smart_str_append_header_value(&soap_headers, ua_str, "User-Agent");
|
||||
smart_str_append_const(&soap_headers, "\r\n");
|
||||
}
|
||||
} else if (FG(user_agent)) {
|
||||
smart_str_append_const(&soap_headers, "User-Agent: ");
|
||||
smart_str_append(&soap_headers, FG(user_agent));
|
||||
smart_str_append_const(&soap_headers, "\r\n");
|
||||
} else {
|
||||
smart_str_append_const(&soap_headers, "User-Agent: PHP-SOAP/"PHP_VERSION"\r\n");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
--TEST--
|
||||
SoapClient must truncate a user_agent that contains newline characters
|
||||
--EXTENSIONS--
|
||||
soap
|
||||
--SKIPIF--
|
||||
<?php
|
||||
if (!file_exists(__DIR__ . "/../../../sapi/cli/tests/php_cli_server.inc")) {
|
||||
echo "skip sapi/cli/tests/php_cli_server.inc required but not found";
|
||||
}
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
include __DIR__ . "/../../../sapi/cli/tests/php_cli_server.inc";
|
||||
|
||||
$args = ["-d", "extension_dir=" . ini_get("extension_dir"), "-d", "extension=" . (substr(PHP_OS, 0, 3) == "WIN" ? "php_" : "") . "soap." . PHP_SHLIB_SUFFIX];
|
||||
if (php_ini_loaded_file()) {
|
||||
$args[] = "-c";
|
||||
$args[] = php_ini_loaded_file();
|
||||
}
|
||||
$code = <<<'PHP'
|
||||
$content = trim(file_get_contents("php://input")) . PHP_EOL;
|
||||
PHP;
|
||||
|
||||
php_cli_server_start($code, null, $args);
|
||||
|
||||
ini_set('user_agent', "evil\r\nX-Injected: yes");
|
||||
|
||||
$client = new SoapClient(NULL, [
|
||||
'location' => 'http://' . PHP_CLI_SERVER_ADDRESS,
|
||||
'uri' => 'misc-uri',
|
||||
'trace' => true,
|
||||
]);
|
||||
|
||||
$client->__soapCall("foo", []);
|
||||
echo $client->__getLastRequestHeaders();
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: SoapClient::__doRequest(): Header User-Agent value contains newline characters and has been truncated in %s on line %d
|
||||
POST / HTTP/1.1
|
||||
Host: localhost:%d
|
||||
Connection: Keep-Alive
|
||||
User-Agent: evil
|
||||
Content-Type: text/xml; charset=utf-8
|
||||
SOAPAction: "misc-uri#foo"
|
||||
Content-Length: %d
|
||||
Reference in new issue
Block a user