摘要:的預定義變量和,這些變量的生成過程。主要是由于之前看到一篇文章通過構造沖突實現各種語言的拒絕服務攻擊。其中看似是相當于注冊聲明對應的預定義變量名,而才是真正的將值寫入到和變量中的操作。提交最大變量數限制,中做限制,參考資料
PHP的預定義變量:$_SERVER,$_POST,$_GET,$_COOKIE,$_ENV,$_FILES和$_REQUEST,這些變量的生成過程。
主要是由于之前看到一篇文章通過構造Hash沖突實現各種語言的拒絕服務攻擊。
看完之后思考這些變量是什么時候生成的,是由web服務器生成的還是PHP生成的?
客戶端將請求發(fā)送到web服務器,web服務器在收到請求后,將請求攜帶的參數寫入到緩沖區(qū)stdin,然后php寫入預定義變量的時候,會從stdin中取出這些參數然后裝入到對應的預定義變量中$_GET,$_POST,$_REQUEST中
自己跟蹤代碼看整個php的流程1>執(zhí)行main/mian.c中的php_module_startup函數
2>執(zhí)行php_startup_auto_globals函數,該函數在php_variables.c中定義的
//php_variable.c void php_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(zend_string_init("_POST", sizeof("_POST")-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("_SERVER", sizeof("_SERVER")-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_env); zend_register_auto_global(zend_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,將各個預定義變量寫入 int zend_register_auto_global(zend_string *name, zend_bool jit, zend_auto_global_callback auto_global_callback){ zend_auto_global auto_global; int retval; auto_global.name = zend_new_interned_string(name); 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 ? SUCCESS : FAILURE; zend_string_release(name); return retval; } //zend_compile.c,將各個變量的key-value寫入到hashtable中 static zend_always_inline void *zend_hash_add_mem(HashTable *ht, zend_string *key, void *pData, size_t size){ zval tmp, *zv; ZVAL_PTR(&tmp, NULL); if ((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, size); return Z_PTR_P(zv); } return NULL; }laruence的博客:
要知道PHP是怎么處理的,首先我們要了解,$_GET, $_POST, $_COOKIE等變量的構造過程。
每個請求到來以后,apache處理到response階段的時候, 會將控制權交給PHP模塊, PHP模塊會在處理請求之前首先間接調用 php_request_startup函數,在php_request_startup中:
#ifndef APACHE_HOOKS int php_request_startup(void) { int retval = SUCCESS; #ifdef HAVE_DTRACE DTRACE_REQUEST_STARTUP(SAFE_FILENAME(SG(request_info).path_translated), SAFE_FILENAME(SG(request_info).request_uri), (char *)SAFE_FILENAME(SG(request_info).request_method)); #endif /* HAVE_DTRACE */ #ifdef PHP_WIN32 # if defined(ZTS) _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); # endif PG(com_initialized) = 0; #endif #if PHP_SIGCHILD signal(SIGCHLD, sigchld_handler); #endif zend_try { PG(in_error_log) = 0; PG(during_request_startup) = 1; php_output_activate(); /* initialize global variables */ PG(modules_activated) = 0; PG(header_is_being_sent) = 0; PG(connection_status) = PHP_CONNECTION_NORMAL; PG(in_user_include) = 0; zend_activate(); sapi_activate(); #ifdef ZEND_SIGNALS zend_signal_activate(); #endif if (PG(max_input_time) == -1) { zend_set_timeout(EG(timeout_seconds), 1); } else { zend_set_timeout(PG(max_input_time), 1); } /* Disable realpath cache if an open_basedir is set */ 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 oh; ZVAL_STRING(&oh, PG(output_handler)); php_output_start_user(&oh, 0, PHP_OUTPUT_HANDLER_STDFLAGS); zval_ptr_dtor(&oh); } else if (PG(output_buffering)) { php_output_start_user(NULL, PG(output_buffering) > 1 ? PG(output_buffering) : 0, PHP_OUTPUT_HANDLER_STDFLAGS); } else if (PG(implicit_flush)) { php_output_set_implicit_flush(1); } /* We turn this off in php_execute_script() */ /* PG(during_request_startup) = 0; */ php_hash_environment(); zend_activate_modules(); PG(modules_activated)=1; } zend_catch { retval = FAILURE; } zend_end_try(); SG(sapi_started) = 1; return retval; }
其中的zend_variables.c文件中php_hash_environment函數:
PHPAPI int php_hash_environment(void) { memset(PG(http_globals), 0, sizeof(PG(http_globals))); zend_activate_auto_globals(); if (PG(register_argc_argv)) { php_build_argv(SG(request_info).query_string, &PG(http_globals)[TRACK_VARS_SERVER]); } return SUCCESS; } //回調zend_variables.c中的zend_activate_auto_globals函數將請求的value寫入到對應的$_POST和$_GET預定義變量中 ZEND_API void zend_activate_auto_globals(void) /* {{{ */ { zend_auto_global *auto_global; ZEND_HASH_FOREACH_PTR(CG(auto_globals), auto_global) { if (auto_global->jit) { auto_global->armed = 1; } else if (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->auto_global_callback(auto_global->name); } else { auto_global->armed = 0; } } ZEND_HASH_FOREACH_END(); }
拿其中一個$_REQUEST數據來看,php_variables.c文件中php_auto_globals_create_request函數對應代碼:
static zend_bool php_auto_globals_create_post(zend_string *name) { if (PG(variables_order) && (strchr(PG(variables_order),"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_POST]); array_init(&PG(http_globals)[TRACK_VARS_POST]); } zend_hash_update(&EG(symbol_table), name, &PG(http_globals)[TRACK_VARS_POST]); Z_ADDREF(PG(http_globals)[TRACK_VARS_POST]); return 0; /* don"t rearm */ }
可以看到,離成功不遠了,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/...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/23225.html
摘要:注意和是不同的變量,處理它們的方式不同變量說明默認情況下包含了,和的數組。包含相同的信息,但它不是一個超全局變量。這些特殊的常量不區(qū)分大小寫,如下幾個的魔術常量名稱說明文件中的當前行號。 整理了下關于php的基礎知識,參考了些資料,如下: 超全局變量 超全局變量 — 超全局變量是在全部作用域中始終可用的內置變量: $GLOBALS $GLOBALS — 引用全局作用域中可用的全部變量 ...
摘要:和進程的啟動過程類似,啟動過程有種進程角色啟動進程進程和進程。直到請求到來,將連接賦值給對象的字段。注當進程執(zhí)行完后會再次調用函數,準備監(jiān)聽新的請求。當讀取到的時,會調用函數對進行解析,將中的以及存儲到結構體中。 運營研發(fā)團隊 季偉濱 一、前言 前幾天的工作中,需要通過curl做一次接口測試。讓我意外的是,通過$_POST竟然無法獲取到Content-Type是application...
摘要:最近計劃把手冊,認真的先過一遍。語言參考類型新認知強制轉換類型用。后期靜態(tài)綁定從這里開始語言參考生成器新認知生成器汗水的核心是關鍵字。語言參考預定義變量超全局變量前一個錯誤信息原始數據以上 showImg(https://segmentfault.com/img/remote/1460000010147451); 最近計劃把 PHP手冊,認真的先過一遍。記錄一些以前不知道,不明確的知識...
摘要:,意為跨網站請求偽造,也有寫為。攻擊者偽造目標用戶的請求,然后此請求發(fā)送到有漏洞的網站,網站執(zhí)行此請求后,引發(fā)跨站請求偽造攻擊。 CSRF(Cross Site Request Forgeries),意為跨網站請求偽造,也有寫為XSRF。攻擊者偽造目標用戶的HTTP請求,然后此請求發(fā)送到有CSRF漏洞的網站,網站執(zhí)行此請 求后,引發(fā)跨站請求偽造攻擊。攻擊者利用隱蔽的HTTP連接,讓目標...
摘要:這里創(chuàng)建的對象可以在進程生命周期內使用目的加載框架中的內容定義應用目錄加載基礎文件把接收的信息轉換為可識別的對于超全局數組不會釋放函數輸出打印 Swoole完美支持ThinkPHP5 1、首先要開啟http的server 可以在thinkphp的目錄下創(chuàng)建一個server目錄,里面創(chuàng)建一個HTTPServer的php 2、需要在WorkerStart回調事件做兩件事 定義應用目錄:d...
閱讀 917·2021-09-09 09:32
閱讀 2884·2021-09-02 10:20
閱讀 2706·2021-07-23 11:24
閱讀 835·2019-08-30 15:54
閱讀 3638·2019-08-30 15:54
閱讀 1351·2019-08-30 11:02
閱讀 2852·2019-08-26 17:40
閱讀 1133·2019-08-26 13:55