inputs sanitation & remove some obsolete version checks

using filter_vars instead of filter_input, because our unit tests depend on manipulating global arrays, which are not used by filter_input - we would have to mock the function in the unit testing, it therefore is cleaner to use the same code paths in testing as in production

some inputs in I18n and TrafficLimiter remain unfiltered, since we already validate them by other means (IP lib and/or preg_match)

our minimum PHP version is 7.3, so we can drop the two < 5.6 fallback checks
This commit is contained in:
El RIDO 2024-03-23 11:27:25 +01:00
parent 9997178928
commit 65a626f940
4 changed files with 23 additions and 22 deletions

View file

@ -2,7 +2,9 @@
## 1.7.2 (not yet released) ## 1.7.2 (not yet released)
* ADDED: Allow use of `shortenviayourls` in query parameters (#1267) * ADDED: Allow use of `shortenviayourls` in query parameters (#1267)
* ADDED: Input sanitation to some not yet filtered query and server parameters
* CHANGED: "Send" button now labeled "Create" (#946) * CHANGED: "Send" button now labeled "Create" (#946)
* CHANGED: drop some PHP < 5.6 fallbacks, minimum version is PHP 7.3 as of release 1.6.0
* FIXED: Add cache control headers also to API calls (#1263) * FIXED: Add cache control headers also to API calls (#1263)
* FIXED: Shortened paste URL does not appear in email (#606) * FIXED: Shortened paste URL does not appear in email (#606)

View file

@ -108,7 +108,7 @@ abstract class AbstractModel
$this->_data = $data; $this->_data = $data;
// calculate a 64 bit checksum to avoid collisions // calculate a 64 bit checksum to avoid collisions
$this->setId(hash(version_compare(PHP_VERSION, '5.6', '<') ? 'fnv164' : 'fnv1a64', $data['ct'])); $this->setId(hash('fnv1a64', $data['ct']));
} }
/** /**

View file

@ -82,13 +82,10 @@ class Request
*/ */
private function getPasteId() private function getPasteId()
{ {
// RegEx to check for valid paste ID (16 base64 chars)
$pasteIdRegEx = '/^[a-f0-9]{16}$/';
foreach ($_GET as $key => $value) { foreach ($_GET as $key => $value) {
// only return if value is empty and key matches RegEx // only return if value is empty and key is 16 hex chars
if (($value === '') and preg_match($pasteIdRegEx, $key, $match)) { if (($value === '') && strlen($key) === 16 && ctype_xdigit($key)) {
return $match[0]; return $key;
} }
} }
@ -121,7 +118,13 @@ class Request
} }
break; break;
default: default:
$this->_params = $_GET; $this->_params = filter_var_array($_GET, array(
'deletetoken' => FILTER_SANITIZE_SPECIAL_CHARS,
'jsonld' => FILTER_SANITIZE_SPECIAL_CHARS,
'link' => FILTER_SANITIZE_URL,
'pasteid' => FILTER_SANITIZE_SPECIAL_CHARS,
'shortenviayourls' => FILTER_SANITIZE_SPECIAL_CHARS,
), false);
} }
if ( if (
!array_key_exists('pasteid', $this->_params) && !array_key_exists('pasteid', $this->_params) &&
@ -209,9 +212,8 @@ class Request
*/ */
public function getHost() public function getHost()
{ {
return array_key_exists('HTTP_HOST', $_SERVER) ? $host = array_key_exists('HTTP_HOST', $_SERVER) ? filter_var($_SERVER['HTTP_HOST'], FILTER_SANITIZE_URL) : '';
htmlspecialchars($_SERVER['HTTP_HOST']) : return empty($host) ? 'localhost' : $host;
'localhost';
} }
/** /**
@ -222,10 +224,8 @@ class Request
*/ */
public function getRequestUri() public function getRequestUri()
{ {
return array_key_exists('REQUEST_URI', $_SERVER) ? $uri = array_key_exists('REQUEST_URI', $_SERVER) ? filter_var($_SERVER['REQUEST_URI'], FILTER_SANITIZE_URL) : '';
htmlspecialchars( return empty($uri) ? '/' : $uri;
parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)
) : '/';
} }
/** /**
@ -275,10 +275,9 @@ class Request
} }
// advanced case: media type negotiation // advanced case: media type negotiation
$mediaTypes = array();
if ($hasAcceptHeader) { if ($hasAcceptHeader) {
$mediaTypeRanges = explode(',', trim($acceptHeader)); $mediaTypes = array();
foreach ($mediaTypeRanges as $mediaTypeRange) { foreach (explode(',', trim($acceptHeader)) as $mediaTypeRange) {
if (preg_match( if (preg_match(
'#(\*/\*|[a-z\-]+/[a-z\-+*]+(?:\s*;\s*[^q]\S*)*)(?:\s*;\s*q\s*=\s*(0(?:\.\d{0,3})|1(?:\.0{0,3})))?#', '#(\*/\*|[a-z\-]+/[a-z\-+*]+(?:\s*;\s*[^q]\S*)*)(?:\s*;\s*q\s*=\s*(0(?:\.\d{0,3})|1(?:\.0{0,3})))?#',
trim($mediaTypeRange), $match trim($mediaTypeRange), $match
@ -287,6 +286,9 @@ class Request
$match[2] = '1.0'; $match[2] = '1.0';
} else { } else {
$match[2] = (string) floatval($match[2]); $match[2] = (string) floatval($match[2]);
if ($match[2] === '0.0') {
continue;
}
} }
if (!isset($mediaTypes[$match[2]])) { if (!isset($mediaTypes[$match[2]])) {
$mediaTypes[$match[2]] = array(); $mediaTypes[$match[2]] = array();
@ -296,9 +298,6 @@ class Request
} }
krsort($mediaTypes); krsort($mediaTypes);
foreach ($mediaTypes as $acceptedQuality => $acceptedValues) { foreach ($mediaTypes as $acceptedQuality => $acceptedValues) {
if ($acceptedQuality === '0.0') {
continue;
}
foreach ($acceptedValues as $acceptedValue) { foreach ($acceptedValues as $acceptedValue) {
if ( if (
strpos($acceptedValue, self::MIME_HTML) === 0 || strpos($acceptedValue, self::MIME_HTML) === 0 ||

View file

@ -696,7 +696,7 @@ class Helper
*/ */
public static function getPasteId() public static function getPasteId()
{ {
return version_compare(PHP_VERSION, '5.6', '<') ? hash('fnv164', self::$pasteV2['ct']) : self::$pasteid; return self::$pasteid;
} }
/** /**