]> granicus.if.org Git - php/commitdiff
Input Filter support. See README.input_filter for details.
authorRasmus Lerdorf <rasmus@php.net>
Wed, 19 Feb 2003 19:41:09 +0000 (19:41 +0000)
committerRasmus Lerdorf <rasmus@php.net>
Wed, 19 Feb 2003 19:41:09 +0000 (19:41 +0000)
@- Input Filter support added. See  README.input_filter. (Rasmus)

README.input_filter [new file with mode: 0644]
ext/mbstring/mb_gpc.c
ext/mbstring/mbstring.c
main/SAPI.c
main/SAPI.h
main/php_content_types.c
main/php_variables.c
main/rfc1867.c

diff --git a/README.input_filter b/README.input_filter
new file mode 100644 (file)
index 0000000..011b167
--- /dev/null
@@ -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);
+}
+
index 028612baa673628f7d674496a1e2b97b28ae8f87..61e6dd93d91d2409746f325727c17d602a42f306 100644 (file)
@@ -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){
index 3f9558efc7101138449f071597684fbdf13729fc..c228cf29b6cbc0c62d9309122f1245f680d2483d 100644 (file)
@@ -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);
index cbe23ba575152011db4adb0060bff7796d202eee..117d868fc8a7cdfbc41865676a8645d8357fc8c2 100644 (file)
@@ -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)
 {
index 4ecc77a8b23fe6686de2adb345be3ad1ab15e39a..1bc31b26cba3ec9822cb59c93e4f394828f42853 100644 (file)
@@ -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
 
index 2db3ccd7aef973bcbe9a7668d28407dabba27eb8..53c241cbe39efccea353c197358c4237279f9644 100644 (file)
@@ -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;
 }
 /* }}} */
index 233e6368db471bd6e6e73e263f67ffdc55b8cfa2..a82c966ef8aaa75d8605a994c25586500772e783 100644 (file)
@@ -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));
index 3c9b6d56e222697f3a4fea80aeaa2db6c60d0abb..eea22ce6a8fe881a98a77ac428f1797f15c3237b 100644 (file)
@@ -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);