标题: Suhosin,PHP保护神?
作者: Demon
链接: https://demon.tw/software/suhosin-php.html
版权: 本博客的所有文章,都遵守“署名-非商业性使用-相同方式共享 2.5 中国大陆”协议条款。
ihipop这两天一直在抱怨他的BT站在某些种子文件在做种的时候出现
"失败: 错误:缺少参数 info_hash"
的错误。有点BT常识的人都知道,BT客户端向服务器请求数据的方式仅仅是简单的HTTP GET,info_hash是其中的一个参数,表示bencode编码的种子文件中info这个字典的sha1值(二进制)。
announce.php开始是这么写的:
//为了好看省略了部分参数 $req = "passkey,info_hash,peer_id,port"; foreach (explode(",", $req) as $x) { if (!isset($_GET[$x])) { err("错误:缺少参数 $x"); break; } }
很显然,上面的错误是因为$_GET["info_hash"]并不存在,按常识推断,很可能是info_hash参数并没有提交。然而另一方面,uTorrent作为广泛使用的BT客户端,不可能犯这种低级的错误,肯定提交了info_hash。由此引出了矛盾,到底哪里出了问题呢?经过一个下午的讨论,终于找到了罪魁祸首——Suhosin!想了解事情的真相和讨论的始末,请点击这里传送到“小顾de杂记”。
Suhosin,朝鲜语,译音为“保护神”。Suhosin是一个PHP程序的保护系统。它的设计初衷是为了保护服务器和用户抵御PHP程序和PHP核心中,已知或者未知的缺陷。Suhosin有两个独立的部分,使用时可以分开使用或者联合使用。第一部分是一个用于PHP核心的补丁,它能抵御缓冲区溢出或者格式化串的弱点;第二部分是一个强大的PHP扩展,包含其他所有的保护措施。
Suhosin的作用大概是:保护服务器和已知或未知的缺陷,类似内存泄漏等等吧;解决php的“远程文件包含”带来的安全隐患,例如PHP禁止allow_url_fopen选项,但不能彻底禁止通过PHP的攻击,Suhosin就修补了这个缺憾。可使用额外的配置来禁止一些php中可能带来安全隐患的功能。
在Suhosin源码的treat_data.c中定义了一个suhosin_hook_treat_data函数:
void suhosin_hook_treat_data() { sapi_register_treat_data(suhosin_treat_data); #ifdef ZEND_ENGINE_2 if (old_input_filter == NULL) { old_input_filter = sapi_module.input_filter; } sapi_module.input_filter = suhosin_input_filter_wrapper; #endif }
用自己的suhosin_treat_data函数hook掉了PHP中默认用来生成$_GET、$_POST等变量的php_default_treat_data函数。而在suhosin_treat_data函数中又使用了自定义的suhosin_input_filter函数对用来生成$_GET变量的变量进行了过滤:
if (val) { /* have a value */ int val_len; unsigned int new_val_len; *val++ = '\0'; php_url_decode(var, strlen(var)); val_len = php_url_decode(val, strlen(val)); val = estrndup(val, val_len); if (suhosin_input_filter(arg, var, &val, val_len, &new_val_len TSRMLS_CC)) { #ifdef ZEND_ENGINE_2 if (sapi_module.input_filter(arg, var, &val, new_val_len, &new_val_len TSRMLS_CC)) { #endif php_register_variable_safe(var, val, new_val_len, array_ptr TSRMLS_CC); #ifdef ZEND_ENGINE_2 } #endif } else { SUHOSIN_G(abort_request) = 1; } efree(val); } else {
再然后,在ifilter.c定义的suhosin_input_filter函数中有那么几行:
/* Check if variable value is truncated by a \0 */ if (val && *val && val_len != strlen(*val)) { if (SUHOSIN_G(disallow_nul)) { suhosin_log(S_VARS, "ASCII-NUL chars not allowed within request variables - dropped variable '%s'", var); if (!SUHOSIN_G(simulation)) { return 0; } } switch (arg) { case PARSE_GET: if (SUHOSIN_G(disallow_get_nul)) { suhosin_log(S_VARS, "ASCII-NUL chars not allowed within GET variables - dropped variable '%s'", var); if (!SUHOSIN_G(simulation)) { return 0; } } break; } }
如果val变量(也就是用来生成$_GET数组的变量)中有\0,并且Suhosin配置中disallow_get_nul(默认为1)为真,那么就会丢弃掉这个变量,于是$_GET中就不会存在这个索引值。由于info_hash是二进制值,包含\0那是很正常的,于是就被Suhosin当做敏感词给过滤掉了,再于是isset($_GET["info_hash"])就会返回false。终于,山高月小,水落而石出!
就是这样该死的Suhosin,浪费了我本应用来看宠物小精灵的时间!好好的PHP,干嘛非要弄个所谓的“保护神”。为了性能和方便,PHP中可以防止大部分SQL注入的magic_quotes_gpc选项都将要删除了,现在又弄个“保护神”来过滤敏感字符?关键是写出安全的代码,而不是安装乱七八糟的拓展来提高安全性!
参考链接:
赞赏微信赞赏支付宝赞赏
随机文章:
代码是人写的。
是人就会犯错。
没人能保证自己写的代码是100%安全的。只能说不断发现问题 然后改进。
在自己没发现问题之前 借助这种扩展保护自己没什么错误。
关键问题是 Debian把它默认集成了,而不是我特意去装他。
Suhosin存在即合理。总归有他存在的道理的。
不是所有的数据都需要过滤的,涉及SQL的数据只是很少一部分。
对没有必要过滤的数据进行过滤会影响性能,甚至,像你一样出现这种莫名其妙的错误。
magic_quotes_gpc可以防止大部分SQL注入,还不是将被PHP删掉了?
详见PHP手册《Why not to use Magic Quotes》。
主要是因为过度对他的依赖导致了一些人放松了代码安全方面的要求。
而悲剧的是 这选项不是总打开的。如果这些没有被“保护”代码运行在没有开Magic Quotes的情况下,那是非常危险的。是基于这一层考虑。
Suhosin的过滤和Magic Quotes差不多。
过度对Magic Quotes的依赖导致了一些人放松了代码安全方面的要求,你又怎能保证不会有人过度依赖Suhosin?
如果说Magic Quotes选项不是总打开的,那么Suhosin拓展更不是总安装有的。如果这些没有被“保护”代码运行在没有Suhosin情况下,难道就不危险?
说到底,安全性关键还是在于代码,而不是开启了OOXX选项,安装了OOXX拓展。
这不一样。
一个是预防性质的。没有Suhosin也不会有什么特别的大问题。
有了更好。
但是魔法引用就不一样了。没有了他,写的代码又是专门为他而写的,平时没做过滤,那就完蛋的死翘翘了。
“但是魔法引用就不一样了。没有了他,写的代码又是专门为他而写的,平时没做过滤,那就完蛋的死翘翘了。”
写的代码依赖魔法引用,那还不是代码本身的问题。代码本身不安全,弄个乱七八糟的拓展就安全了?就拿晨光上次的XSS漏洞来说,开个Suhosin就安全了?
XSS好像不是Suhosin管得着的吧。
你这就叫诡辩。
和拉不出屎怪地心没引力是一个逻辑~ :)
懒得跟你吵,你下次拉不出屎的时候别找我就行,哼!
http://www.laruence.com/2011/12/29/2412.html
2011年末的动态语言 Hash DOS 漏洞。Suhosin 就设置了 post.max_vars 限制。
[…] 《Suhosin,PHP保护神?》 […]
写出安全的代码,确实比安装各种奇怪的扩展来得好!