summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRasmus Lerdorf <rasmus@php.net>2003-02-19 19:41:09 +0000
committerRasmus Lerdorf <rasmus@php.net>2003-02-19 19:41:09 +0000
commit7429c2dc3f72ed9a6a41ccefc68595e76319cdae (patch)
tree5a1cf40f32cb245cc33b043339464da15507462c
parent0458bb5e2b31e571b83e6aa674073c28fb8c4fbf (diff)
downloadphp-git-7429c2dc3f72ed9a6a41ccefc68595e76319cdae.tar.gz
Input Filter support. See README.input_filter for details.
@- Input Filter support added. See README.input_filter. (Rasmus)
-rw-r--r--README.input_filter188
-rw-r--r--ext/mbstring/mb_gpc.c5
-rw-r--r--ext/mbstring/mbstring.c2
-rw-r--r--main/SAPI.c5
-rw-r--r--main/SAPI.h5
-rw-r--r--main/php_content_types.c1
-rw-r--r--main/php_variables.c8
-rw-r--r--main/rfc1867.c1
8 files changed, 212 insertions, 3 deletions
diff --git a/README.input_filter b/README.input_filter
new file mode 100644
index 0000000000..011b167725
--- /dev/null
+++ b/README.input_filter
@@ -0,0 +1,188 @@
+Input Filter Support in PHP5
+----------------------------
+
+XSS (Cross Site Scripting) hacks are becoming more and more prevalent,
+and can be quite difficult to prevent. Whenever you accept user data
+and somehow display this data back to users, you are likely vulnerable
+to XSS hacks.
+
+The Input Filter support in PHP5 is aimed at providing the framework
+through which a company-wide or site-wide security policy can be
+enforced. It is implemented as a SAPI hook and is called from the
+treat_data and post handler functions. To implement your own security
+policy you will need to write a standard PHP extension.
+
+A simple implementation might look like the following. This stores the
+original raw user data and adds a my_get_raw() function while the normal
+$_POST, $_GET and $_COOKIE arrays are only populated with stripped
+data. In this simple example all I am doing is calling strip_tags() on
+the data. If register_globals is turned on, the default globals that
+are created will be stripped ($foo) while a $RAW_foo is created with the
+original user input.
+
+ZEND_BEGIN_MODULE_GLOBALS(my_input_filter)
+ zval *post_array;
+ zval *get_array;
+ zval *cookie_array;
+ZEND_END_MODULE_GLOBALS(my_input_filter)
+
+#ifdef ZTS
+#define IF_G(v) TSRMG(my_input_filter_globals_id, zend_my_input_filter_globals *, v)
+#else
+#define IF_G(v) (my_input_filter_globals.v)
+#endif
+
+ZEND_DECLARE_MODULE_GLOBALS(my_input_filter)
+
+function_entry my_input_filter_functions[] = {
+ PHP_FE(my_get_raw, NULL)
+ {NULL, NULL, NULL}
+};
+
+zend_module_entry my_input_filter_module_entry = {
+ STANDARD_MODULE_HEADER,
+ "my_input_filter",
+ my_input_filter_functions,
+ PHP_MINIT(my_input_filter),
+ PHP_MSHUTDOWN(my_input_filter),
+ NULL,
+ PHP_RSHUTDOWN(my_input_filter),
+ PHP_MINFO(my_input_filter),
+ "0.1",
+ STANDARD_MODULE_PROPERTIES
+};
+
+PHP_MINIT_FUNCTION(my_input_filter)
+{
+ ZEND_INIT_MODULE_GLOBALS(my_input_filter, php_my_input_filter_init_globals, NULL);
+
+ REGISTER_LONG_CONSTANT("POST", PARSE_POST, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("GET", PARSE_GET, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("COOKIE", PARSE_COOKIE, CONST_CS | CONST_PERSISTENT);
+
+ sapi_register_input_filter(my_sapi_input_filter);
+ return SUCCESS;
+}
+
+PHP_RSHUTDOWN_FUNCTION(my_input_filter)
+{
+ if(IF_G(get_array)) {
+ zval_ptr_dtor(&IF_G(get_array));
+ IF_G(get_array) = NULL;
+ }
+ if(IF_G(post_array)) {
+ zval_ptr_dtor(&IF_G(post_array));
+ IF_G(post_array) = NULL;
+ }
+ if(IF_G(cookie_array)) {
+ zval_ptr_dtor(&IF_G(cookie_array));
+ IF_G(cookie_array) = NULL;
+ }
+ return SUCCESS;
+}
+
+PHP_MINFO_FUNCTION(my_input_filter)
+{
+ php_info_print_table_start();
+ php_info_print_table_row( 2, "My Input Filter Support", "enabled" );
+ php_info_print_table_row( 2, "Revision", "$Revision$");
+ php_info_print_table_end();
+}
+
+unsigned int my_sapi_input_filter(int arg, char *var, char *val, unsigned int val_len)
+{
+ zval new_var;
+ zval *array_ptr = NULL;
+ char *raw_var;
+ int var_len;
+
+ assert(val != NULL);
+
+ switch(arg) {
+ case PARSE_GET:
+ if(!IF_G(get_array)) {
+ ALLOC_ZVAL(array_ptr);
+ array_init(array_ptr);
+ INIT_PZVAL(array_ptr);
+ }
+ IF_G(get_array) = array_ptr;
+ break;
+ case PARSE_POST:
+ if(!IF_G(post_array)) {
+ ALLOC_ZVAL(array_ptr);
+ array_init(array_ptr);
+ INIT_PZVAL(array_ptr);
+ }
+ IF_G(post_array) = array_ptr;
+ break;
+ case PARSE_COOKIE:
+ if(!IF_G(cookie_array)) {
+ ALLOC_ZVAL(array_ptr);
+ array_init(array_ptr);
+ INIT_PZVAL(array_ptr);
+ }
+ IF_G(cookie_array) = array_ptr;
+ break;
+ }
+ Z_STRLEN(new_var) = val_len;
+ Z_STRVAL(new_var) = estrndup(val, val_len);
+ Z_TYPE(new_var) = IS_STRING;
+
+ var_len = strlen(var);
+ raw_var = emalloc(var_len+5); /* RAW_ and a \0 */
+ strcpy(raw_var, "RAW_");
+ strlcat(raw_var,var,var_len+5);
+
+ php_register_variable_ex(raw_var, &new_var, array_ptr TSRMLS_DC);
+
+ php_strip_tags(val, val_len, NULL, NULL, 0);
+
+ return strlen(val);
+}
+
+PHP_FUNCTION(my_get_raw)
+{
+ long arg;
+ char *var;
+ int var_len;
+ zval **tmp;
+ zval *array_ptr = NULL;
+ HashTable *hash_ptr;
+ char *raw_var;
+
+ if(zend_parse_parameters(2 TSRMLS_CC, "ls|l", &arg, &var, &var_len) == FAILURE) {
+ return;
+ }
+
+ switch(arg) {
+ case PARSE_GET:
+ array_ptr = IF_G(get_array);
+ break;
+ case PARSE_POST:
+ array_ptr = IF_G(post_array);
+ break;
+ case PARSE_COOKIE:
+ array_ptr = IF_G(post_array);
+ break;
+ }
+
+ if(!array_ptr) RETURN_FALSE;
+
+ /*
+ * I'm changing the variable name here because when running with register_globals on,
+ * the variable will end up in the global symbol table
+ */
+ raw_var = emalloc(var_len+5); /* RAW_ and a \0 */
+ strcpy(raw_var, "RAW_");
+ strlcat(raw_var,var,var_len+5);
+ hash_ptr = HASH_OF(array_ptr);
+
+ if(zend_hash_find(hash_ptr, raw_var, var_len+5, (void **)&tmp) == SUCCESS) {
+ *return_value = **tmp;
+ zval_copy_ctor(return_value);
+ } else {
+ RETVAL_FALSE;
+ }
+ efree(raw_var);
+}
+
diff --git a/ext/mbstring/mb_gpc.c b/ext/mbstring/mb_gpc.c
index 028612baa6..61e6dd93d9 100644
--- a/ext/mbstring/mb_gpc.c
+++ b/ext/mbstring/mb_gpc.c
@@ -169,7 +169,7 @@ MBSTRING_API SAPI_TREAT_DATA_FUNC(mbstr_treat_data)
break;
}
- _php_mb_encoding_handler_ex(array_ptr, res, separator, 0, 0 TSRMLS_CC);
+ _php_mb_encoding_handler_ex(arg, array_ptr, res, separator, 0, 0 TSRMLS_CC);
if (MBSTRG(http_input_identify) != mbfl_no_encoding_invalid) {
switch(arg){
@@ -199,7 +199,7 @@ MBSTRING_API SAPI_TREAT_DATA_FUNC(mbstr_treat_data)
/* }}} */
/* {{{ int _php_mb_encoding_handler_ex() */
-int _php_mb_encoding_handler_ex(zval *arg, char *res, char *separator, int force_register_globals, int report_errors TSRMLS_DC)
+int _php_mb_encoding_handler_ex(int data_type, zval *arg, char *res, char *separator, int force_register_globals, int report_errors TSRMLS_DC)
{
char *var, *val, *s1, *s2;
char *strtok_buf = NULL, **val_list = NULL;
@@ -342,6 +342,7 @@ int _php_mb_encoding_handler_ex(zval *arg, char *res, char *separator, int force
val_len = len_list[n];
}
n++;
+ val_len = sapi_module.input_filter(data_type, var, val, val_len TSRMLS_CC);
/* add variable to symbol table */
php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC);
if (convd != NULL){
diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c
index 3f9558efc7..c228cf29b6 100644
--- a/ext/mbstring/mbstring.c
+++ b/ext/mbstring/mbstring.c
@@ -1281,7 +1281,7 @@ PHP_FUNCTION(mb_parse_str)
encstr = estrndup(encstr, encstr_len);
- RETVAL_BOOL(_php_mb_encoding_handler_ex(track_vars_array, encstr, separator, (track_vars_array == NULL), 1 TSRMLS_CC));
+ RETVAL_BOOL(_php_mb_encoding_handler_ex(PARSE_STRING, track_vars_array, encstr, separator, (track_vars_array == NULL), 1 TSRMLS_CC));
if (encstr != NULL) efree(encstr);
if (separator != NULL) efree(separator);
diff --git a/main/SAPI.c b/main/SAPI.c
index cbe23ba575..117d868fc8 100644
--- a/main/SAPI.c
+++ b/main/SAPI.c
@@ -823,6 +823,11 @@ SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zva
return SUCCESS;
}
+SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char *val, unsigned int val_len TSRMLS_DC))
+{
+ sapi_module.input_filter = input_filter;
+ return SUCCESS;
+}
SAPI_API int sapi_flush(TSRMLS_D)
{
diff --git a/main/SAPI.h b/main/SAPI.h
index 4ecc77a8b2..1bc31b26cb 100644
--- a/main/SAPI.h
+++ b/main/SAPI.h
@@ -178,6 +178,7 @@ SAPI_API int sapi_register_post_entry(sapi_post_entry *post_entry);
SAPI_API void sapi_unregister_post_entry(sapi_post_entry *post_entry);
SAPI_API int sapi_register_default_post_reader(void (*default_post_reader)(TSRMLS_D));
SAPI_API int sapi_register_treat_data(void (*treat_data)(int arg, char *str, zval *destArray TSRMLS_DC));
+SAPI_API int sapi_register_input_filter(unsigned int (*input_filter)(int arg, char *var, char *val, unsigned int val_len TSRMLS_DC));
SAPI_API int sapi_flush(TSRMLS_D);
SAPI_API struct stat *sapi_get_stat(TSRMLS_D);
@@ -238,6 +239,8 @@ struct _sapi_module_struct {
int (*get_target_uid)(uid_t * TSRMLS_DC);
int (*get_target_gid)(gid_t * TSRMLS_DC);
+
+ unsigned int (*input_filter)(int arg, char *var, char *val, unsigned int val_len TSRMLS_DC);
};
@@ -266,10 +269,12 @@ struct _sapi_post_entry {
#define SAPI_POST_HANDLER_FUNC(post_handler) void post_handler(char *content_type_dup, void *arg TSRMLS_DC)
#define SAPI_TREAT_DATA_FUNC(treat_data) void treat_data(int arg, char *str, zval* destArray TSRMLS_DC)
+#define SAPI_INPUT_FILTER_FUNC(input_filter) unsigned int input_filter(int arg, char *var, char *val, unsigned int val_len TSRMLS_DC)
SAPI_API SAPI_POST_READER_FUNC(sapi_read_standard_form_data);
SAPI_API SAPI_POST_READER_FUNC(php_default_post_reader);
SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data);
+SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter);
#define STANDARD_SAPI_MODULE_PROPERTIES
diff --git a/main/php_content_types.c b/main/php_content_types.c
index 2db3ccd7ae..53c241cbe3 100644
--- a/main/php_content_types.c
+++ b/main/php_content_types.c
@@ -77,6 +77,7 @@ int php_startup_sapi_content_types(void)
sapi_register_post_entries(php_post_entries);
sapi_register_default_post_reader(php_default_post_reader);
sapi_register_treat_data(php_default_treat_data);
+ sapi_register_input_filter(php_default_input_filter);
return SUCCESS;
}
/* }}} */
diff --git a/main/php_variables.c b/main/php_variables.c
index 233e6368db..a82c966ef8 100644
--- a/main/php_variables.c
+++ b/main/php_variables.c
@@ -226,12 +226,19 @@ SAPI_API SAPI_POST_HANDLER_FUNC(php_std_post_handler)
*val++ = '\0';
php_url_decode(var, strlen(var));
val_len = php_url_decode(val, strlen(val));
+ val_len = sapi_module.input_filter(PARSE_POST, var, val, val_len TSRMLS_CC);
php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC);
}
var = php_strtok_r(NULL, "&", &strtok_buf);
}
}
+SAPI_API SAPI_INPUT_FILTER_FUNC(php_default_input_filter)
+{
+ /* TODO: check .ini setting here and apply user-defined input filter */
+ return val_len;
+}
+
SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data)
{
char *res = NULL, *var, *val, *separator=NULL;
@@ -314,6 +321,7 @@ SAPI_API SAPI_TREAT_DATA_FUNC(php_default_treat_data)
*val++ = '\0';
php_url_decode(var, strlen(var));
val_len = php_url_decode(val, strlen(val));
+ val_len = sapi_module.input_filter(arg, var, val, val_len TSRMLS_CC);
php_register_variable_safe(var, val, val_len, array_ptr TSRMLS_CC);
} else {
php_url_decode(var, strlen(var));
diff --git a/main/rfc1867.c b/main/rfc1867.c
index 3c9b6d56e2..eea22ce6a8 100644
--- a/main/rfc1867.c
+++ b/main/rfc1867.c
@@ -805,6 +805,7 @@ SAPI_API SAPI_POST_HANDLER_FUNC(rfc1867_post_handler)
value = estrdup("");
}
+ sapi_module.input_filter(PARSE_POST, param, value, strlen(value) TSRMLS_CC);
safe_php_register_variable(param, value, array_ptr, 0 TSRMLS_CC);
if (!strcmp(param, "MAX_FILE_SIZE")) {
max_file_size = atol(value);