Browse Source

fixed crash on non-string input to CSRF token

fixes #11822

also adding proper unit tests for validate CSRF token.
ar-bug
Carsten Brandt 8 years ago
parent
commit
17d08cc0a4
  1. 1
      framework/CHANGELOG.md
  2. 4
      framework/web/Request.php
  3. 93
      tests/framework/web/RequestTest.php

1
framework/CHANGELOG.md

@ -41,6 +41,7 @@ Yii Framework 2 Change Log
- Bug #11672: Fixed `yii\validators\NumberValidator` erroring when value is an object without `__toString()` method (SamMousa)
- Bug #11561: Fixed DI container throwing exceptions for optional dependencies (SamMousa)
- Enh #11168: `yii\helpers\BaseHtml` now uses abstracted `booleanInput()` and `activeBooleanInput()` methods to render `radio()`, `checkbox()`, `activeRadio()` and `activeCheckbox()` (cesarnicola)
- Bug #11822: Fixed exception on non-string value provided as CSRF token (cebe)
2.0.8 April 28, 2016
--------------------

4
framework/web/Request.php

@ -1403,6 +1403,10 @@ class Request extends \yii\base\Request
*/
private function validateCsrfTokenInternal($token, $trueToken)
{
if (!is_string($token)) {
return false;
}
$token = base64_decode(str_replace('.', '+', $token));
$n = StringHelper::byteLength($token);
if ($n <= static::CSRF_MASK_LENGTH) {

93
tests/framework/web/RequestTest.php

@ -88,7 +88,100 @@ class RequestTest extends TestCase
$token = $request->getCsrfToken();
// accept any value if CSRF validation is disabled
$request->enableCsrfValidation = false;
$this->assertTrue($request->validateCsrfToken($token));
$this->assertTrue($request->validateCsrfToken($token . 'a'));
$this->assertTrue($request->validateCsrfToken([]));
$this->assertTrue($request->validateCsrfToken([$token]));
$this->assertTrue($request->validateCsrfToken(0));
$this->assertTrue($request->validateCsrfToken(null));
// enable validation
$request->enableCsrfValidation = true;
// accept any value on GET request
foreach(['GET', 'HEAD', 'OPTIONS'] as $method) {
$_POST[$request->methodParam] = $method;
$this->assertTrue($request->validateCsrfToken($token));
$this->assertTrue($request->validateCsrfToken($token . 'a'));
$this->assertTrue($request->validateCsrfToken([]));
$this->assertTrue($request->validateCsrfToken([$token]));
$this->assertTrue($request->validateCsrfToken(0));
$this->assertTrue($request->validateCsrfToken(null));
}
// only accept valid token on POST
foreach(['POST', 'PUT', 'DELETE'] as $method) {
$_POST[$request->methodParam] = $method;
$this->assertTrue($request->validateCsrfToken($token));
$this->assertFalse($request->validateCsrfToken($token . 'a'));
$this->assertFalse($request->validateCsrfToken([]));
$this->assertFalse($request->validateCsrfToken([$token]));
$this->assertFalse($request->validateCsrfToken(0));
$this->assertFalse($request->validateCsrfToken(null));
}
}
/**
* test CSRF token validation by POST param
*/
public function testCsrfTokenPost()
{
$this->mockWebApplication();
$request = new Request();
$request->enableCsrfCookie = false;
$token = $request->getCsrfToken();
// accept no value on GET request
foreach(['GET', 'HEAD', 'OPTIONS'] as $method) {
$_POST[$request->methodParam] = $method;
$this->assertTrue($request->validateCsrfToken());
}
// only accept valid token on POST
foreach(['POST', 'PUT', 'DELETE'] as $method) {
$_POST[$request->methodParam] = $method;
$request->setBodyParams([]);
$this->assertFalse($request->validateCsrfToken());
$request->setBodyParams([$request->csrfParam => $token]);
$this->assertTrue($request->validateCsrfToken());
}
}
/**
* test CSRF token validation by POST param
*/
public function testCsrfTokenHeader()
{
$this->mockWebApplication();
$request = new Request();
$request->enableCsrfCookie = false;
$token = $request->getCsrfToken();
// accept no value on GET request
foreach(['GET', 'HEAD', 'OPTIONS'] as $method) {
$_POST[$request->methodParam] = $method;
$this->assertTrue($request->validateCsrfToken());
}
// only accept valid token on POST
foreach(['POST', 'PUT', 'DELETE'] as $method) {
$_POST[$request->methodParam] = $method;
$request->setBodyParams([]);
//$request->headers->remove(Request::CSRF_HEADER);
unset($_SERVER['HTTP_' . str_replace('-', '_', strtoupper(Request::CSRF_HEADER))]);
$this->assertFalse($request->validateCsrfToken());
//$request->headers->add(Request::CSRF_HEADER, $token);
$_SERVER['HTTP_' . str_replace('-', '_', strtoupper(Request::CSRF_HEADER))] = $token;
$this->assertTrue($request->validateCsrfToken());
}
}
public function testResolve()

Loading…
Cancel
Save