Skip to content

Commit

Permalink
Merge pull request from GHSA-wjfc-pgfp-pv9c
Browse files Browse the repository at this point in the history
Improper Input Validation in headers
  • Loading branch information
Nyholm committed Apr 17, 2023
1 parent 52887ca commit 1029a26
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/MessageTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ private function setHeaders(array $headers): void
*/
private function validateAndTrimHeader($header, $values): array
{
if (!\is_string($header) || 1 !== \preg_match("@^[!#$%&'*+.^_`|~0-9A-Za-z-]+$@", $header)) {
if (!\is_string($header) || 1 !== \preg_match("@^[!#$%&'*+.^_`|~0-9A-Za-z-]+$@D", $header)) {
throw new \InvalidArgumentException('Header name must be an RFC 7230 compatible string');
}

Expand All @@ -207,7 +207,7 @@ private function validateAndTrimHeader($header, $values): array
// Assert Non empty array
$returnValues = [];
foreach ($values as $v) {
if ((!\is_numeric($v) && !\is_string($v)) || 1 !== \preg_match("@^[ \t\x21-\x7E\x80-\xFF]*$@", (string) $v)) {
if ((!\is_numeric($v) && !\is_string($v)) || 1 !== \preg_match("@^[ \t\x21-\x7E\x80-\xFF]*$@D", (string) $v)) {
throw new \InvalidArgumentException('Header values must be RFC 7230 compatible strings');
}

Expand Down
46 changes: 46 additions & 0 deletions tests/RequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -294,4 +294,50 @@ public function testUpdateHostFromUri()
$request = $request->withUri(new Uri('https://nyholm.tech:443'));
$this->assertEquals('nyholm.tech', $request->getHeaderLine('Host'));
}

/**
* @dataProvider provideHeaderValuesContainingNotAllowedChars
*/
public function testCannotHaveHeaderWithInvalidValue(string $name)
{
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Header name must be an RFC 7230 compatible string');
$r = new Request('GET', 'https://example.com/');
$r->withHeader($name, 'Bar');
}

public static function provideHeaderValuesContainingNotAllowedChars(): array
{
// Explicit tests for newlines as the most common exploit vector.
$tests = [
["new\nline"],
["new\r\nline"],
["new\rline"],
["new\r\n line"],
["newline\n"],
["\nnewline"],
["newline\r\n"],
["\n\rnewline"],
];

for ($i = 0; $i <= 0xFF; ++$i) {
if ("\t" == \chr($i)) {
continue;
}
if (' ' == \chr($i)) {
continue;
}
if ($i >= 0x21 && $i <= 0x7E) {
continue;
}
if ($i >= 0x80) {
continue;
}

$tests[] = ['foo' . \chr($i) . 'bar'];
$tests[] = ['foo' . \chr($i)];
}

return $tests;
}
}
31 changes: 31 additions & 0 deletions tests/ResponseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -274,4 +274,35 @@ public function testHeaderValuesAreTrimmed($r)
$this->assertSame('Foo', $r->getHeaderLine('OWS'));
$this->assertSame(['Foo'], $r->getHeader('OWS'));
}

/**
* @dataProvider invalidWithHeaderProvider
*/
public function testWithInvalidHeader($header, $headerValue, $expectedMessage): void
{
$r = new Response();
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage($expectedMessage);
$r->withHeader($header, $headerValue);
}

public function invalidWithHeaderProvider(): iterable
{
return [
['foo', [], 'Header values must be a string or an array of strings, empty array given'],
['foo', new \stdClass(), 'Header values must be RFC 7230 compatible strings'],
[[], 'foo', 'Header name must be an RFC 7230 compatible string'],
[false, 'foo', 'Header name must be an RFC 7230 compatible string'],
[new \stdClass(), 'foo', 'Header name must be an RFC 7230 compatible string'],
['', 'foo', 'Header name must be an RFC 7230 compatible string'],
["Content-Type\r\n\r\n", 'foo', 'Header name must be an RFC 7230 compatible string'],
["Content-Type\r\n", 'foo', 'Header name must be an RFC 7230 compatible string'],
["Content-Type\n", 'foo', 'Header name must be an RFC 7230 compatible string'],
["\r\nContent-Type", 'foo', 'Header name must be an RFC 7230 compatible string'],
["\nContent-Type", 'foo', 'Header name must be an RFC 7230 compatible string'],
["\n", 'foo', 'Header name must be an RFC 7230 compatible string'],
["\r\n", 'foo', 'Header name must be an RFC 7230 compatible string'],
["\t", 'foo', 'Header name must be an RFC 7230 compatible string'],
];
}
}

0 comments on commit 1029a26

Please sign in to comment.