diff options
| author | jvoisin | 2019-05-14 21:57:13 +0200 |
|---|---|---|
| committer | jvoisin | 2019-05-14 22:48:55 +0200 |
| commit | 1cdb880fac5044194f0bc62dd82fcd4480192ebe (patch) | |
| tree | ace8fdb1a2e00be2ac2c99bd7054a8d7a19fd3b3 | |
| parent | 6ae912e2dc8c7f47d240e6910e42bb31263eb339 (diff) | |
Fix the cookie's handling for PHP7.3+
PHP 7.3+ added a new prototype for the cookie
setting mechanism, breaking our ghetto samesite-injection,
this commit takes care of it.
| -rw-r--r-- | src/sp_cookie_encryption.c | 71 | ||||
| -rw-r--r-- | src/sp_disabled_functions.c | 1 | ||||
| -rw-r--r-- | src/sp_utils.c | 1 |
3 files changed, 69 insertions, 4 deletions
diff --git a/src/sp_cookie_encryption.c b/src/sp_cookie_encryption.c index 9c034da..249de2d 100644 --- a/src/sp_cookie_encryption.c +++ b/src/sp_cookie_encryption.c | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | #include "php_snuffleupagus.h" | 1 | #include "php_snuffleupagus.h" |
| 2 | 2 | ||
| 3 | |||
| 4 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | 3 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) |
| 5 | 4 | ||
| 6 | static inline const sp_cookie *sp_lookup_cookie_config(const zend_string *key) { | 5 | static inline const sp_cookie *sp_lookup_cookie_config(const zend_string *key) { |
| @@ -40,6 +39,54 @@ static zend_string *encrypt_data(zend_string *data) { | |||
| 40 | return z; | 39 | return z; |
| 41 | } | 40 | } |
| 42 | 41 | ||
| 42 | #if PHP_VERSION_ID >= 70300 | ||
| 43 | static void php_head_parse_cookie_options_array( | ||
| 44 | zval *options, zend_long *expires, zend_string **path, zend_string **domain, | ||
| 45 | zend_bool *secure, zend_bool *httponly, zend_string **samesite) { | ||
| 46 | int found = 0; | ||
| 47 | zend_string *key; | ||
| 48 | zval *value; | ||
| 49 | |||
| 50 | ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(options), key, value) { | ||
| 51 | if (key) { | ||
| 52 | if (zend_string_equals_literal_ci(key, "expires")) { | ||
| 53 | *expires = zval_get_long(value); | ||
| 54 | found++; | ||
| 55 | } else if (zend_string_equals_literal_ci(key, "path")) { | ||
| 56 | *path = zval_get_string(value); | ||
| 57 | found++; | ||
| 58 | } else if (zend_string_equals_literal_ci(key, "domain")) { | ||
| 59 | *domain = zval_get_string(value); | ||
| 60 | found++; | ||
| 61 | } else if (zend_string_equals_literal_ci(key, "secure")) { | ||
| 62 | *secure = zval_is_true(value); | ||
| 63 | found++; | ||
| 64 | } else if (zend_string_equals_literal_ci(key, "httponly")) { | ||
| 65 | *httponly = zval_is_true(value); | ||
| 66 | found++; | ||
| 67 | } else if (zend_string_equals_literal_ci(key, "samesite")) { | ||
| 68 | *samesite = zval_get_string(value); | ||
| 69 | found++; | ||
| 70 | } else { | ||
| 71 | php_error_docref(NULL, E_WARNING, | ||
| 72 | "Unrecognized key '%s' found in the options array", | ||
| 73 | ZSTR_VAL(key)); | ||
| 74 | } | ||
| 75 | } else { | ||
| 76 | php_error_docref(NULL, E_WARNING, | ||
| 77 | "Numeric key found in the options array"); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | ZEND_HASH_FOREACH_END(); | ||
| 81 | |||
| 82 | /* Array is not empty but no valid keys were found */ | ||
| 83 | if (found == 0 && zend_hash_num_elements(Z_ARRVAL_P(options)) > 0) { | ||
| 84 | php_error_docref(NULL, E_WARNING, | ||
| 85 | "No valid options were found in the given array"); | ||
| 86 | } | ||
| 87 | } | ||
| 88 | #endif | ||
| 89 | |||
| 43 | PHP_FUNCTION(sp_setcookie) { | 90 | PHP_FUNCTION(sp_setcookie) { |
| 44 | zend_string *name = NULL, *value = NULL, *path = NULL, *domain = NULL, | 91 | zend_string *name = NULL, *value = NULL, *path = NULL, *domain = NULL, |
| 45 | *value_enc = NULL, | 92 | *value_enc = NULL, |
| @@ -50,6 +97,7 @@ PHP_FUNCTION(sp_setcookie) { | |||
| 50 | #endif | 97 | #endif |
| 51 | 98 | ||
| 52 | zend_long expires = 0; | 99 | zend_long expires = 0; |
| 100 | zval *expires_or_options = NULL; | ||
| 53 | zend_bool secure = 0, httponly = 0; | 101 | zend_bool secure = 0, httponly = 0; |
| 54 | const sp_cookie *cookie_node = NULL; | 102 | const sp_cookie *cookie_node = NULL; |
| 55 | char *cookie_samesite; | 103 | char *cookie_samesite; |
| @@ -59,7 +107,7 @@ PHP_FUNCTION(sp_setcookie) { | |||
| 59 | Z_PARAM_STR(name) | 107 | Z_PARAM_STR(name) |
| 60 | Z_PARAM_OPTIONAL | 108 | Z_PARAM_OPTIONAL |
| 61 | Z_PARAM_STR(value) | 109 | Z_PARAM_STR(value) |
| 62 | Z_PARAM_LONG(expires) | 110 | Z_PARAM_ZVAL(expires_or_options) |
| 63 | Z_PARAM_STR(path) | 111 | Z_PARAM_STR(path) |
| 64 | Z_PARAM_STR(domain) | 112 | Z_PARAM_STR(domain) |
| 65 | Z_PARAM_BOOL(secure) | 113 | Z_PARAM_BOOL(secure) |
| @@ -67,6 +115,25 @@ PHP_FUNCTION(sp_setcookie) { | |||
| 67 | ZEND_PARSE_PARAMETERS_END(); | 115 | ZEND_PARSE_PARAMETERS_END(); |
| 68 | // LCOV_EXCL_BR_END | 116 | // LCOV_EXCL_BR_END |
| 69 | 117 | ||
| 118 | if (expires_or_options) { | ||
| 119 | #if PHP_VERSION_ID < 70300 | ||
| 120 | expires = zval_get_long(expires_or_options); | ||
| 121 | #else | ||
| 122 | if (Z_TYPE_P(expires_or_options) == IS_ARRAY) { | ||
| 123 | if (UNEXPECTED(ZEND_NUM_ARGS() > 3)) { | ||
| 124 | php_error_docref(NULL, E_WARNING, | ||
| 125 | "Cannot pass arguments after the options array"); | ||
| 126 | RETURN_FALSE; | ||
| 127 | } | ||
| 128 | php_head_parse_cookie_options_array(expires_or_options, &expires, &path, | ||
| 129 | &domain, &secure, &httponly, | ||
| 130 | &samesite); | ||
| 131 | } else { | ||
| 132 | expires = zval_get_long(expires_or_options); | ||
| 133 | } | ||
| 134 | #endif | ||
| 135 | } | ||
| 136 | |||
| 70 | /* If the request was issued over HTTPS, the cookie should be "secure" */ | 137 | /* If the request was issued over HTTPS, the cookie should be "secure" */ |
| 71 | if (SNUFFLEUPAGUS_G(config).config_auto_cookie_secure) { | 138 | if (SNUFFLEUPAGUS_G(config).config_auto_cookie_secure) { |
| 72 | const zval server_vars = PG(http_globals)[TRACK_VARS_SERVER]; | 139 | const zval server_vars = PG(http_globals)[TRACK_VARS_SERVER]; |
diff --git a/src/sp_disabled_functions.c b/src/sp_disabled_functions.c index 030fbd8..8177ce1 100644 --- a/src/sp_disabled_functions.c +++ b/src/sp_disabled_functions.c | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | #include "php_snuffleupagus.h" | 1 | #include "php_snuffleupagus.h" |
| 2 | 2 | ||
| 3 | |||
| 4 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | 3 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) |
| 5 | 4 | ||
| 6 | static void should_disable(zend_execute_data* execute_data, | 5 | static void should_disable(zend_execute_data* execute_data, |
diff --git a/src/sp_utils.c b/src/sp_utils.c index ea6afaf..475d552 100644 --- a/src/sp_utils.c +++ b/src/sp_utils.c | |||
| @@ -1,6 +1,5 @@ | |||
| 1 | #include "php_snuffleupagus.h" | 1 | #include "php_snuffleupagus.h" |
| 2 | 2 | ||
| 3 | |||
| 4 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) | 3 | ZEND_DECLARE_MODULE_GLOBALS(snuffleupagus) |
| 5 | 4 | ||
| 6 | bool sp_zend_string_equals(const zend_string* s1, const zend_string* s2) { | 5 | bool sp_zend_string_equals(const zend_string* s1, const zend_string* s2) { |
