diff --git a/dev/app/Config/Filters.php b/dev/app/Config/Filters.php index d0a9723..256222e 100644 --- a/dev/app/Config/Filters.php +++ b/dev/app/Config/Filters.php @@ -34,7 +34,18 @@ class Filters extends BaseConfig public $globals = [ 'before' => [ // 'honeypot', - // 'csrf', + 'csrf'=>[ + 'except' => [ + 'basicTest/formparamsandquery', + 'basicTest/formparams', + 'basicTest/cookieCreate', + 'FileUploadTest/fileUpload', + 'FileUploadTest/fileMultipleUpload', + 'testRest', + 'testRest/*', + 'sessionTest/createdSession' + ], + ], // 'invalidchars', ], 'after' => [ diff --git a/dev/app/Config/Security.php b/dev/app/Config/Security.php index 107bd95..9ccc94c 100644 --- a/dev/app/Config/Security.php +++ b/dev/app/Config/Security.php @@ -94,7 +94,7 @@ class Security extends BaseConfig * * @var bool */ - public $redirect = true; + public $redirect = false; /** * -------------------------------------------------------------------------- diff --git a/dev/app/Controllers/BasicTest.php b/dev/app/Controllers/BasicTest.php index b1fe5c0..069e200 100644 --- a/dev/app/Controllers/BasicTest.php +++ b/dev/app/Controllers/BasicTest.php @@ -93,4 +93,47 @@ public function i18n() { echo lang('Burner.negotiate'); } + + /** + * test cookie + */ + public function cookieCreate() + { + $text1 = $this->request->getGet('text1'); + $text2 = $this->request->getGet('text2'); + $text3 = $this->request->getGet('text3'); + + $this->response->setCookie('text1', $text1, 3600); + $this->response->setCookie('text2', $text2, 3600); + $this->response->setCookie('text3', $text3, 3600); + + return $this->respond(['status' => true]); + } + + /** + * csrf test + */ + public function csrfCreate() + { + $token = csrf_token(); + $hash = csrf_hash(); + $body = <<< HTML +
+ HTML; + return $body; + } + + /** + * csrf verify + */ + public function csrfVerify() + { + $text = $this->request->getPost('text1'); + return $this->respond($text, 200); + } + } diff --git a/dev/tests/CIBurner/httpTest/BasicTest.php b/dev/tests/CIBurner/httpTest/BasicTest.php index afcf005..34b12e6 100644 --- a/dev/tests/CIBurner/httpTest/BasicTest.php +++ b/dev/tests/CIBurner/httpTest/BasicTest.php @@ -137,4 +137,84 @@ public function testI18n() $this->assertSame(200, $response->getStatusCode()); $this->assertSame('正體中文', $response->getBody()); } + + public function testSetCookies() + { + $text1 = md5(uniqid().'text1'); + $text2 = md5(uniqid().'text2'); + $text3 = md5(uniqid().'text3'); + $query = http_build_query([ + 'text1' => $text1, + 'text2' => $text2, + 'text3' => $text3, + ]); + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, 'http://localhost:8080/basicTest/cookieCreate?' . $query); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_HEADER, 1); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET'); + //get url query + $output = curl_exec($ch); + curl_close($ch); + $cookies = []; + preg_match_all('/^Set-Cookie:\s*([^;]*)/mi', $output, $matches); + foreach ($matches[1] as $item) { + parse_str($item, $cookie); + $cookies = array_merge($cookies, $cookie); + } + + foreach ($cookies as $key => $value) { + $this->assertSame(${$key}, $value); + } + } + + public function testCsrf() + { + //config + config('Security'); + $tokenName = config('Security')->tokenName; + $headerName = config('Security')->headerName; + $client = Services::curlrequest([ + 'base_uri' => 'http://localhost:8080/', + ], null, null, false); + + //get csrf key + $getCsrfKey = function() use ($client){ + $response = $client->get('/basicTest/csrfCreate'); + $this->assertSame(200, $response->getStatusCode()); + $setCookie = $response->getHeaders()['Set-Cookie']->getValue(); + $csrf = explode('=', explode(';', $setCookie)[0]); + return $csrf; + }; + + //csrf form teset + $csrf = $getCsrfKey(); + $text1 = md5(uniqid().'text1'); + $response = $client->post('basicTest/csrfVerify', [ + 'headers' => [ + 'Cookie' => "{$csrf[0]}={$csrf[1]}", + ], + 'form_params' => [ + $tokenName => $csrf[1], + 'text1' => $text1, + ], + ]); + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame($text1, $response->getBody()); + + //csrf header test + $csrf = $getCsrfKey(); + $text1 = md5(uniqid().'text1'); + $response = $client->post('basicTest/csrfVerify', [ + 'headers' => [ + 'Cookie' => "{$csrf[0]}={$csrf[1]}", + $headerName => $csrf[1], + ], + 'form_params' => [ + 'text1' => $text1, + ], + ]); + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame($text1, $response->getBody()); + } } diff --git a/src/Bridge/ResponseBridge.php b/src/Bridge/ResponseBridge.php index f77dd5f..f842843 100644 --- a/src/Bridge/ResponseBridge.php +++ b/src/Bridge/ResponseBridge.php @@ -3,6 +3,7 @@ namespace Monken\CIBurner\Bridge; use Config\App; +use Config\Security; use Laminas\Diactoros\Response; use Laminas\Diactoros\Response\InjectContentTypeTrait; use Laminas\Diactoros\Stream; @@ -26,6 +27,7 @@ public function __construct( $this->getCi4StatusCode($ci4Response), $this->getCi4Headers($ci4Response) ); + } private function getCi4ContentType(\CodeIgniter\HTTP\Response $ci4Response): string @@ -35,48 +37,15 @@ private function getCi4ContentType(\CodeIgniter\HTTP\Response $ci4Response): str private function getCi4Headers(\CodeIgniter\HTTP\Response $ci4Response): array { - if (session_status() === PHP_SESSION_ACTIVE) { - $sessionID = session_id(); - $sessionName = session_name(); - $cookiesSessionID = $this->_rRequest->getCookieParams()[$sessionName] ?? ''; - $cookiesParams = session_get_cookie_params(); - $config = config(App::class); - - if ($cookiesSessionID === '') { - $cookieStr = $this->getCookieString( - $sessionName, - $sessionID, - (time() + $cookiesParams['lifetime']), - $cookiesParams['path'], - $cookiesParams['domain'], - $cookiesParams['secure'], - $cookiesParams['httponly'] - ); - $ci4Response->setHeader('Set-Cookie', $cookieStr); - } elseif ($cookiesSessionID !== $sessionID) { - $cookieStr = $this->getCookieString( - $sessionName, - '', - time(), - $config->cookiePath, - $config->cookieDomain, - $config->cookieSecure, - $config->cookieHTTPOnly - ); - $ci4Response->setHeader('Set-Cookie', $cookieStr); - } - - unset($_SESSION); - session_write_close(); - session_id(null); - } - + $setCookiesArray = $this->ci4Cookies($ci4Response); $ci4headers = $ci4Response->headers(); $headers = []; - foreach ($ci4headers as $key => $value) { $headers[$key] = $value->getValueLine(); } + if (count($setCookiesArray) !== 0) { + $headers['Set-Cookie'] = $setCookiesArray; + } return $headers; } @@ -105,20 +74,53 @@ private function getCookieString($name, $value = null, $expire = 0, $path = '/', return $str; } - private function getcookie($name) + private function ci4Cookies(\CodeIgniter\HTTP\Response $ci4Response): array { - $cookies = []; - $headers = headers_list(); - - foreach ($headers as $header) { - if (strpos($header, 'Set-Cookie: ') === 0) { - $value = str_replace('&', urlencode('&'), substr($header, 12)); - parse_str(current(explode(';', $value, 1)), $pair); - $cookies = array_merge_recursive($cookies, $pair); - } + $result = []; + $cookies = $ci4Response->getCookies(); + foreach ($cookies as $cookie) { + $headerString = $cookie->toHeaderString(); + $result[] = $headerString; } - return $cookies[$name] ?? false; + //Session + if (session_status() === PHP_SESSION_ACTIVE) { + $sessionID = session_id(); + $sessionName = session_name(); + $cookiesSessionID = $this->_rRequest->getCookieParams()[$sessionName] ?? ''; + $cookiesParams = session_get_cookie_params(); + $config = config(App::class); + + if ($cookiesSessionID === '') { + $cookieStr = $this->getCookieString( + $sessionName, + $sessionID, + (time() + $cookiesParams['lifetime']), + $cookiesParams['path'], + $cookiesParams['domain'], + $cookiesParams['secure'], + $cookiesParams['httponly'] + ); + $result[] = $cookieStr; + } elseif ($cookiesSessionID !== $sessionID) { + $cookieStr = $this->getCookieString( + $sessionName, + '', + time(), + $config->cookiePath, + $config->cookieDomain, + $config->cookieSecure, + $config->cookieHTTPOnly + ); + $result[] = $cookieStr; + } + + unset($_SESSION); + session_write_close(); + session_id(null); + } + + return $result; } private function getCi4StatusCode(\CodeIgniter\HTTP\Response $ci4Response): int