当前位置: 首页 > 后端技术 > PHP

【PHP预定义变量】$_GET、$_POST、$_REQUEST生成

时间:2023-03-30 00:09:43 PHP

PHP预定义变量:$_SERVER、$_POST、$_GET、$_COOKIE、$_ENV、$_FILES和$_REQUEST,这些变量的生成过程。主要是之前看到一篇文章通过构造Hash冲突来实现各种语言的拒绝服务攻击。看完之后想想这些变量是什么时候产生的,是web服务器产生的还是PHP产生的?猜测:客户端向Web服务器发送请求。Web服务器收到请求后,将请求携带的参数写入bufferstdin中,然后php写入预定义变量时,会从stdin中取出这些参数并加载。输入对应的预定义变量$_GET、$_POST、$_REQUEST自己跟踪代码可以看到整个php流程1>执行main/mian.c中的php_module_startup函数2>执行php_startup_auto_globals函数,该函数在php_variables.c中定义//php_variable.cvoidphp_startup_auto_globals(void){zend_register_auto_global(zend_string_init("_GET",sizeof("_GET")-1,1),0,php_auto_globals_create_get);zend_register_auto_global("POST("POST",_POS("_ize)-1,1),0,php_auto_globals_create_post);zend_register_auto_global(zend_string_init("_COOKIE",sizeof("_COOKIE")-1,1),0,php_auto_globals_create_cookie);zend_register_auto_global(zend_string_init("_COOKIE",sizeof("_COOKIE")-1,1),0,php_auto_globals_create_cookie);zend_register_auto_global(zend_string_init("_COOKIE(","_)-1,1),PG(auto_globals_jit),php_auto_globals_create_server);zend_register_auto_global(zend_string_init("_ENV",sizeof("_ENV")-1,1),PG(auto_globals_jit),php_auto_globals_create_envist);_zend_reg_string_init("_REQUEST",sizeof("_REQUEST")-1,1),PG(auto_globals_jit),php_auto_globals_create_request);zend_register_auto_global(zend_string_init("_FILES",sizeof("_FILES")-1,1),0,php_auto_globals_create_files);}//zend_compile.c,将各个预定义变量写入intzend_register_auto_global(zend_string*name,zbalend_autocall_jit,zbalend_autocall_jit,auto_global_callback){zend_auto_globalauto_global;内部更新;auto_global.name=zend_new_interned_string(名称);auto_global.auto_global_callback=auto_global_callback;auto_global.jit=jit;retval=zend_hash_add_mem(CG(auto_globals),auto_global.name,&auto_global,sizeof(zend_auto_global))!=NULL?成功:失败;zend_string_release(名字);returnretval;}//zend_compile.c,将各个变化的key-value写入hashtable中staticzend_always_inlinevoid*zend_hash_add_mem(HashTable*ht,zend_string*key,void*pData,size_tsize){zvaltmp,*zv;ZVAL_PTR(&tmp,NULL);如果((zv=zend_hash_add(ht,key,&tmp))){//这一步的$_REQUEST可能被攻击Z_PTR_P(zv)=pemalloc(size,ht->u.flags&HASH_FLAG_PERSISTENT);memcpy(Z_PTR_P(zv),pData,大小);返回Z_PTR_P(zv);}returnNULL;}Laruence的博客:要知道PHP是如何处理的,首先要了解$_GET、$_POST、$_COOKIE等变量的构造过程每次请求到达后,apache在处理响应阶段时,会将控制权交给PHP模块。PHP模块在处理请求之前会先间接调用php_request_startup函数。在php_request_startup中:#ifndefAPACHE_HOOKSintphp_request_startup(void){intretval=SUCCESS;#ifdefHAVE_DTRACEDTRACE_REQUEST_STARTUP(SAFE_FILENAME(SG(request_info).path_translated),SAFE_FILENAME(SG(request_info).request_uri),(char*)SAFE_FILENAME(SG(request_info)).request_VETRACE*HAFETRACE));#endif/D#ifdefPHP_WIN32#ifdefined(ZTS)_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);#endifPG(com_initialized)=0;#endif#ifPHP_SIGCHILDsignal(SIGCHLD,sigchld_handler);#endifzend_que{PG(in_error_log)=0)_restur_PG(d=1;php_output_activate();/*初始化全局变量*/PG(modules_activated)=0;PG(header_is_being_sent)=0;PG(connection_status)=PHP_CONNECTION_NORMAL;PG(in_user_include)=0;#ifdefZEND_SIGNALSzend_signal_activate();#endifif(PG(max_input_time)==-1){zend_set_timeout(EG(timeout_seconds),1);}else{zend_set_timeout(PG(max_input_time),1);}/*如果设置了open_basedir,则禁用真实路径缓存*/if(PG(open_basedir)&&*PG(open_basedir)){CWDG(realpath_cache_size_limit)=0;}if(PG(expose_php)){sapi_add_header(SAPI_PHP_VERSION_HEADER,sizeof(SAPI_PHP_VERSION_HEADER)-1,1);}if(PG(output_handler)&&PG(output_handler)[0]){zval哦;ZVAL_STRING(&oh,PG(output_handler));php_output_start_user(&oh,0,PHP_OUTPUT_HANDLER_STDFLAGS);zval_ptr_dtor(&oh);}elseif(PG(output_buffering)){php_output_start_user(NULL,PG(output_buffering)>1?PG(output_buffering):0,PHP_OUTPUT_HANDLER_STDFLAGS);}否则如果(PG(我plicit_flush)){php_output_set_implicit_flush(1);}/*我们在php_execute_script()中关闭它*//*PG(during_request_startup)=0;*/php_hash_environment();zend_activate_modules();PG(modules_activated)=1;}zend_c{retval=FAILURE;}zend_end_try();SG(sapi_started)=1;returnretval;}zend_variables.c文件中的php_hash_environment函数:PHPAPIintphp_hash_environment(void){memset(PG(http_globals),0,sizeof(PG(http_globals)));zend_activate_auto_globals();如果(PG(register_argc_argv)){php_build_argv(SG(request_info).query_string,&PG(http_globals)[TRACK_VARS_SERVER]);}returnSUCCESS;}/callbackinzend_varizend_glact函数将请求的值写入对应的$_POST和$_GET预定义变量ZEND_APIvoidzend_activate_auto_globals(void)/*{{{*/{zend_auto_global*auto_global;ZEND_HASH_FOREACH_PTR(CG(auto_globals),auto_global){如果(auto_global->jit){auto_global->armed=1;}elseif(auto_global->auto_global_callback){//这里会回调php_auto_globals_create_post,php_auto_globals_create_get,php_auto_globals_create_request函数来处理对应的变量auto_global->armed=auto_global->autoglobal_name(;}else{auto_global->armed=0;}}ZEND_HASH_FOREACH_END();}取其中一条$_REQUEST数据,对应php_variables.c文件中php_auto_globals_create_request函数的代码:,'P')||strchr(PG(variables_order),'p'))&&!SG(headers_sent)&&SG(request_info).request_method&&!strcasecmp(SG(request_info).request_method,"POST")){//写入数据sapi_module.treat_data(PARSE_POST,NULL,NULL);}else{zval_ptr_dtor(&PG(http_globals)[TRACK_VARS/*don'trearm*/}可以看到离成功不远了,sapi_module.treat_data是php_default_treat_data,在php_default_treat_data中,对于变量,调用php_register_variable_safe注册变量,php_register_variable_safe最终会调用php_register_variable_ex:zend_variables.c文件中的zend_register_auto_global和zend_activate_auto_globals之间的关系应该是顺序问题。其中zend_register_auto_global似乎相当于注册语句对应的预定义变量名,而zend_activate_auto_globals才是真正的将值写入$_GET和$_POST变量的操作。.提交最大变量数限制,php_varialbles.c中add_post_vars进行限制,SAPI_POST_HANDLER_FUNC(php_std_post_handler)参考:http://www.laruence.com/2008/...http://www.laruence.com/2008/。..http://www.php-internals.com/...