diff --git a/js/csrfprotector.js b/js/csrfprotector.js index aa548cb..0d22955 100644 --- a/js/csrfprotector.js +++ b/js/csrfprotector.js @@ -289,16 +289,8 @@ function csrfprotector_init() { */ function new_send(data) { if (this.method.toLowerCase() === 'post') { - if (data !== null && typeof data === 'object') { - data.append(CSRFP.CSRFP_TOKEN, CSRFP._getAuthKey()); - } else { - if (typeof data != "undefined") { - data += "&"; - } else { - data = ""; - } - data += CSRFP.CSRFP_TOKEN +"=" +CSRFP._getAuthKey(); - } + // attach the token in request header + this.setRequestHeader(CSRFP.CSRFP_TOKEN, CSRFP._getAuthKey()); } return this.old_send(data); } diff --git a/libs/csrf/csrfprotector.php b/libs/csrf/csrfprotector.php index fa258cf..7e097a2 100755 --- a/libs/csrf/csrfprotector.php +++ b/libs/csrf/csrfprotector.php @@ -1,5 +1,4 @@ */ private static $cookieConfig = null; + /** + * Variable: $tokenHeaderKey + * Key value in header array, which contain the token + * @var string + */ + private static $tokenHeaderKey = null; + /* * Variable: $requestType * Varaible to store weather request type is post or get @@ -188,6 +194,9 @@ public static function init($length = null, $action = null) if (self::$config['CSRFP_TOKEN'] == '') self::$config['CSRFP_TOKEN'] = CSRFP_TOKEN; + self::$tokenHeaderKey = 'HTTP_' .strtoupper(self::$config['CSRFP_TOKEN']); + self::$tokenHeaderKey = str_replace('-', '_', self::$tokenHeaderKey); + // load parameters for setcookie method if (!isset(self::$config['cookieConfig'])) self::$config['cookieConfig'] = array(); @@ -248,19 +257,19 @@ public static function authorizePost() //set request type to POST self::$requestType = "POST"; + // look for token in payload else from header + $token = self::getTokenFromRequest(); + //currently for same origin only - if (!(isset($_POST[self::$config['CSRFP_TOKEN']]) - && isset($_SESSION[self::$config['CSRFP_TOKEN']]) - && (self::isValidToken($_POST[self::$config['CSRFP_TOKEN']])) - )) { + if (!($token && isset($_SESSION[self::$config['CSRFP_TOKEN']]) + && (self::isValidToken($token)))) { //action in case of failed validation - self::failedValidationAction(); + self::failedValidationAction(); } else { self::refreshToken(); //refresh token for successfull validation } } else if (!static::isURLallowed()) { - //currently for same origin only if (!(isset($_GET[self::$config['CSRFP_TOKEN']]) && isset($_SESSION[self::$config['CSRFP_TOKEN']]) @@ -275,6 +284,36 @@ public static function authorizePost() } } + /* + * Fucntion: getTokenFromRequest + * function to get token in case of POST request + * + * Parameters: + * void + * + * Returns: + * any (string / bool) - token retrieved from header or form payload + */ + private static function getTokenFromRequest() { + // look for in $_POST, then header + if (isset($_POST[self::$config['CSRFP_TOKEN']])) { + return $_POST[self::$config['CSRFP_TOKEN']]; + } + + if (function_exists('apache_request_headers')) { + if (isset(apache_request_headers()[self::$config['CSRFP_TOKEN']])) { + return apache_request_headers()[self::$config['CSRFP_TOKEN']]; + } + } + + if (self::$tokenHeaderKey === null) return false; + if (isset($_SERVER[self::$tokenHeaderKey])) { + return $_SERVER[self::$tokenHeaderKey]; + } + + return false; + } + /* * Function: isValidToken * function to check the validity of token in session array diff --git a/test/csrfprotector_test.php b/test/csrfprotector_test.php index 388ff9a..52a1279 100644 --- a/test/csrfprotector_test.php +++ b/test/csrfprotector_test.php @@ -350,11 +350,10 @@ public function testAuthorisePost_failedAction_6() } /** - * test authorise success + * test authorise success with token in $_POST */ public function testAuthorisePost_success() { - $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST[csrfprotector::$config['CSRFP_TOKEN']] = $_GET[csrfprotector::$config['CSRFP_TOKEN']] @@ -382,6 +381,34 @@ public function testAuthorisePost_success() // $this->assertTrue(csrfp_wrapper::checkHeader($_SESSION[csrfprotector::$config['CSRFP_TOKEN']][0])); // Combine these 3 later } + /** + * test authorise success with token in header + */ + public function testAuthorisePost_success_2() + { + unset($_POST[csrfprotector::$config['CSRFP_TOKEN']]); + $_SERVER['REQUEST_METHOD'] = 'POST'; + $serverKey = 'HTTP_' .strtoupper(csrfprotector::$config['CSRFP_TOKEN']); + $serverKey = str_replace('-', '_', $serverKey); + + $csrfp = new csrfProtector; + $reflection = new \ReflectionClass(get_class($csrfp)); + $property = $reflection->getProperty('tokenHeaderKey'); + $property->setAccessible(true); + // change value to false + $property->setValue($csrfp, $serverKey); + + $_SERVER[$serverKey] = $_SESSION[csrfprotector::$config['CSRFP_TOKEN']][0]; + $temp = $_SESSION[csrfprotector::$config['CSRFP_TOKEN']]; + + csrfprotector::authorizePost(); //will create new session and cookies + $this->assertFalse($temp == $_SESSION[csrfprotector::$config['CSRFP_TOKEN']][0]); + $this->assertTrue(csrfp_wrapper::checkHeader('Set-Cookie')); + $this->assertTrue(csrfp_wrapper::checkHeader('csrfp_token')); + // $this->assertTrue(csrfp_wrapper::checkHeader($_SESSION[csrfprotector::$config['CSRFP_TOKEN']][0])); // Combine these 3 later + + } + /** * test for generateAuthToken() */