Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 189 lines (161 sloc) 5.447 kb
7429c2d @rlerdorf Input Filter support. See README.input_filter for details.
rlerdorf authored
1 Input Filter Support in PHP5
2 ----------------------------
3
4 XSS (Cross Site Scripting) hacks are becoming more and more prevalent,
5 and can be quite difficult to prevent. Whenever you accept user data
6 and somehow display this data back to users, you are likely vulnerable
7 to XSS hacks.
8
9 The Input Filter support in PHP5 is aimed at providing the framework
10 through which a company-wide or site-wide security policy can be
11 enforced. It is implemented as a SAPI hook and is called from the
12 treat_data and post handler functions. To implement your own security
13 policy you will need to write a standard PHP extension.
14
15 A simple implementation might look like the following. This stores the
16 original raw user data and adds a my_get_raw() function while the normal
17 $_POST, $_GET and $_COOKIE arrays are only populated with stripped
18 data. In this simple example all I am doing is calling strip_tags() on
19 the data. If register_globals is turned on, the default globals that
20 are created will be stripped ($foo) while a $RAW_foo is created with the
21 original user input.
22
23 ZEND_BEGIN_MODULE_GLOBALS(my_input_filter)
24 zval *post_array;
25 zval *get_array;
26 zval *cookie_array;
27 ZEND_END_MODULE_GLOBALS(my_input_filter)
28
29 #ifdef ZTS
30 #define IF_G(v) TSRMG(my_input_filter_globals_id, zend_my_input_filter_globals *, v)
31 #else
32 #define IF_G(v) (my_input_filter_globals.v)
33 #endif
34
35 ZEND_DECLARE_MODULE_GLOBALS(my_input_filter)
36
37 function_entry my_input_filter_functions[] = {
38 PHP_FE(my_get_raw, NULL)
39 {NULL, NULL, NULL}
40 };
41
42 zend_module_entry my_input_filter_module_entry = {
43 STANDARD_MODULE_HEADER,
44 "my_input_filter",
45 my_input_filter_functions,
46 PHP_MINIT(my_input_filter),
47 PHP_MSHUTDOWN(my_input_filter),
48 NULL,
49 PHP_RSHUTDOWN(my_input_filter),
50 PHP_MINFO(my_input_filter),
51 "0.1",
52 STANDARD_MODULE_PROPERTIES
53 };
54
55 PHP_MINIT_FUNCTION(my_input_filter)
56 {
57 ZEND_INIT_MODULE_GLOBALS(my_input_filter, php_my_input_filter_init_globals, NULL);
58
59 REGISTER_LONG_CONSTANT("POST", PARSE_POST, CONST_CS | CONST_PERSISTENT);
60 REGISTER_LONG_CONSTANT("GET", PARSE_GET, CONST_CS | CONST_PERSISTENT);
61 REGISTER_LONG_CONSTANT("COOKIE", PARSE_COOKIE, CONST_CS | CONST_PERSISTENT);
62
63 sapi_register_input_filter(my_sapi_input_filter);
64 return SUCCESS;
65 }
66
67 PHP_RSHUTDOWN_FUNCTION(my_input_filter)
68 {
69 if(IF_G(get_array)) {
70 zval_ptr_dtor(&IF_G(get_array));
71 IF_G(get_array) = NULL;
72 }
73 if(IF_G(post_array)) {
74 zval_ptr_dtor(&IF_G(post_array));
75 IF_G(post_array) = NULL;
76 }
77 if(IF_G(cookie_array)) {
78 zval_ptr_dtor(&IF_G(cookie_array));
79 IF_G(cookie_array) = NULL;
80 }
81 return SUCCESS;
82 }
83
84 PHP_MINFO_FUNCTION(my_input_filter)
85 {
86 php_info_print_table_start();
87 php_info_print_table_row( 2, "My Input Filter Support", "enabled" );
88 php_info_print_table_row( 2, "Revision", "$Revision$");
89 php_info_print_table_end();
90 }
91
92 unsigned int my_sapi_input_filter(int arg, char *var, char *val, unsigned int val_len)
93 {
94 zval new_var;
95 zval *array_ptr = NULL;
96 char *raw_var;
97 int var_len;
98
99 assert(val != NULL);
100
101 switch(arg) {
102 case PARSE_GET:
103 if(!IF_G(get_array)) {
104 ALLOC_ZVAL(array_ptr);
105 array_init(array_ptr);
106 INIT_PZVAL(array_ptr);
107 }
108 IF_G(get_array) = array_ptr;
109 break;
110 case PARSE_POST:
111 if(!IF_G(post_array)) {
112 ALLOC_ZVAL(array_ptr);
113 array_init(array_ptr);
114 INIT_PZVAL(array_ptr);
115 }
116 IF_G(post_array) = array_ptr;
117 break;
118 case PARSE_COOKIE:
119 if(!IF_G(cookie_array)) {
120 ALLOC_ZVAL(array_ptr);
121 array_init(array_ptr);
122 INIT_PZVAL(array_ptr);
123 }
124 IF_G(cookie_array) = array_ptr;
125 break;
126 }
127 Z_STRLEN(new_var) = val_len;
128 Z_STRVAL(new_var) = estrndup(val, val_len);
129 Z_TYPE(new_var) = IS_STRING;
130
131 var_len = strlen(var);
132 raw_var = emalloc(var_len+5); /* RAW_ and a \0 */
133 strcpy(raw_var, "RAW_");
134 strlcat(raw_var,var,var_len+5);
135
136 php_register_variable_ex(raw_var, &new_var, array_ptr TSRMLS_DC);
137
138 php_strip_tags(val, val_len, NULL, NULL, 0);
139
140 return strlen(val);
141 }
142
143 PHP_FUNCTION(my_get_raw)
144 {
145 long arg;
146 char *var;
147 int var_len;
148 zval **tmp;
149 zval *array_ptr = NULL;
150 HashTable *hash_ptr;
151 char *raw_var;
152
153 if(zend_parse_parameters(2 TSRMLS_CC, "ls|l", &arg, &var, &var_len) == FAILURE) {
154 return;
155 }
156
157 switch(arg) {
158 case PARSE_GET:
159 array_ptr = IF_G(get_array);
160 break;
161 case PARSE_POST:
162 array_ptr = IF_G(post_array);
163 break;
164 case PARSE_COOKIE:
165 array_ptr = IF_G(post_array);
166 break;
167 }
168
169 if(!array_ptr) RETURN_FALSE;
170
171 /*
172 * I'm changing the variable name here because when running with register_globals on,
173 * the variable will end up in the global symbol table
174 */
175 raw_var = emalloc(var_len+5); /* RAW_ and a \0 */
176 strcpy(raw_var, "RAW_");
177 strlcat(raw_var,var,var_len+5);
178 hash_ptr = HASH_OF(array_ptr);
179
180 if(zend_hash_find(hash_ptr, raw_var, var_len+5, (void **)&tmp) == SUCCESS) {
181 *return_value = **tmp;
182 zval_copy_ctor(return_value);
183 } else {
184 RETVAL_FALSE;
185 }
186 efree(raw_var);
187 }
188
Something went wrong with that request. Please try again.