You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

183 lines
5.2 KiB

20 years ago
  1. Input Filter Support in PHP 5
  2. -----------------------------
  3. XSS (Cross Site Scripting) hacks are becoming more and more prevalent,
  4. and can be quite difficult to prevent. Whenever you accept user data
  5. and somehow display this data back to users, you are likely vulnerable
  6. to XSS hacks.
  7. The Input Filter support in PHP 5 is aimed at providing the framework
  8. through which a company-wide or site-wide security policy can be
  9. enforced. It is implemented as a SAPI hook and is called from the
  10. treat_data and post handler functions. To implement your own security
  11. policy you will need to write a standard PHP extension. There is also
  12. a powerful standard implementation in ext/filter that should suit most
  13. peoples' needs. However, if you want to implement your own security
  14. policy, read on.
  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.
  20. ZEND_BEGIN_MODULE_GLOBALS(my_input_filter)
  21. zval *post_array;
  22. zval *get_array;
  23. zval *cookie_array;
  24. ZEND_END_MODULE_GLOBALS(my_input_filter)
  25. #ifdef ZTS
  26. #define IF_G(v) TSRMG(my_input_filter_globals_id, zend_my_input_filter_globals *, v)
  27. #else
  28. #define IF_G(v) (my_input_filter_globals.v)
  29. #endif
  30. ZEND_DECLARE_MODULE_GLOBALS(my_input_filter)
  31. zend_function_entry my_input_filter_functions[] = {
  32. PHP_FE(my_get_raw, NULL)
  33. {NULL, NULL, NULL}
  34. };
  35. zend_module_entry my_input_filter_module_entry = {
  36. STANDARD_MODULE_HEADER,
  37. "my_input_filter",
  38. my_input_filter_functions,
  39. PHP_MINIT(my_input_filter),
  40. PHP_MSHUTDOWN(my_input_filter),
  41. NULL,
  42. PHP_RSHUTDOWN(my_input_filter),
  43. PHP_MINFO(my_input_filter),
  44. "0.1",
  45. STANDARD_MODULE_PROPERTIES
  46. };
  47. PHP_MINIT_FUNCTION(my_input_filter)
  48. {
  49. ZEND_INIT_MODULE_GLOBALS(my_input_filter, php_my_input_filter_init_globals, NULL);
  50. REGISTER_LONG_CONSTANT("POST", PARSE_POST, CONST_CS | CONST_PERSISTENT);
  51. REGISTER_LONG_CONSTANT("GET", PARSE_GET, CONST_CS | CONST_PERSISTENT);
  52. REGISTER_LONG_CONSTANT("COOKIE", PARSE_COOKIE, CONST_CS | CONST_PERSISTENT);
  53. sapi_register_input_filter(my_sapi_input_filter);
  54. return SUCCESS;
  55. }
  56. PHP_RSHUTDOWN_FUNCTION(my_input_filter)
  57. {
  58. if(IF_G(get_array)) {
  59. zval_ptr_dtor(&IF_G(get_array));
  60. IF_G(get_array) = NULL;
  61. }
  62. if(IF_G(post_array)) {
  63. zval_ptr_dtor(&IF_G(post_array));
  64. IF_G(post_array) = NULL;
  65. }
  66. if(IF_G(cookie_array)) {
  67. zval_ptr_dtor(&IF_G(cookie_array));
  68. IF_G(cookie_array) = NULL;
  69. }
  70. return SUCCESS;
  71. }
  72. PHP_MINFO_FUNCTION(my_input_filter)
  73. {
  74. php_info_print_table_start();
  75. php_info_print_table_row( 2, "My Input Filter Support", "enabled" );
  76. php_info_print_table_row( 2, "Revision", "$Id$");
  77. php_info_print_table_end();
  78. }
  79. /* The filter handler. If you return 1 from it, then PHP also registers the
  80. * (modified) variable. Returning 0 prevents PHP from registering the variable;
  81. * you can use this if your filter already registers the variable under a
  82. * different name, or if you just don't want the variable registered at all. */
  83. SAPI_INPUT_FILTER_FUNC(my_sapi_input_filter)
  84. {
  85. zval new_var;
  86. zval *array_ptr = NULL;
  87. char *raw_var;
  88. int var_len;
  89. assert(*val != NULL);
  90. switch(arg) {
  91. case PARSE_GET:
  92. if(!IF_G(get_array)) {
  93. ALLOC_ZVAL(array_ptr);
  94. array_init(array_ptr);
  95. INIT_PZVAL(array_ptr);
  96. }
  97. IF_G(get_array) = array_ptr;
  98. break;
  99. case PARSE_POST:
  100. if(!IF_G(post_array)) {
  101. ALLOC_ZVAL(array_ptr);
  102. array_init(array_ptr);
  103. INIT_PZVAL(array_ptr);
  104. }
  105. IF_G(post_array) = array_ptr;
  106. break;
  107. case PARSE_COOKIE:
  108. if(!IF_G(cookie_array)) {
  109. ALLOC_ZVAL(array_ptr);
  110. array_init(array_ptr);
  111. INIT_PZVAL(array_ptr);
  112. }
  113. IF_G(cookie_array) = array_ptr;
  114. break;
  115. }
  116. Z_STRLEN(new_var) = val_len;
  117. Z_STRVAL(new_var) = estrndup(*val, val_len);
  118. Z_TYPE(new_var) = IS_STRING;
  119. var_len = strlen(var);
  120. raw_var = emalloc(var_len+5); /* RAW_ and a \0 */
  121. strcpy(raw_var, "RAW_");
  122. strlcat(raw_var,var,var_len+5);
  123. php_register_variable_ex(raw_var, &new_var, array_ptr);
  124. php_strip_tags(*val, val_len, NULL, NULL, 0);
  125. *new_val_len = strlen(*val);
  126. return 1;
  127. }
  128. PHP_FUNCTION(my_get_raw)
  129. {
  130. long arg;
  131. char *var;
  132. int var_len;
  133. zval **tmp;
  134. zval *array_ptr = NULL;
  135. if(zend_parse_parameters(2, "ls", &arg, &var, &var_len) == FAILURE) {
  136. return;
  137. }
  138. switch(arg) {
  139. case PARSE_GET:
  140. array_ptr = IF_G(get_array);
  141. break;
  142. case PARSE_POST:
  143. array_ptr = IF_G(post_array);
  144. break;
  145. case PARSE_COOKIE:
  146. array_ptr = IF_G(post_array);
  147. break;
  148. }
  149. if(!array_ptr) {
  150. RETURN_FALSE;
  151. }
  152. if(zend_hash_find(HASH_OF(array_ptr), var, var_len+5, (void **)&tmp) == SUCCESS) {
  153. *return_value = **tmp;
  154. zval_copy_ctor(return_value);
  155. } else {
  156. RETVAL_FALSE;
  157. }
  158. }