安全开发经验分享
前言
当看代码时,无论是PHP、Java还是Object C、JavaScrpit,我发现有很多我称之为“理想主义”的代码,写的很实在,直奔预想的业务逻辑实现。假设一切都是理想状态,从用户角度看,这段代码可以实现业务。但是互联网是嘈杂的,因此代码需要处理更多异常的情况,异常处理可能会占据到代码量的80%左右。同样,从用户角度看,业务还是那些业务,不同的是,安全的代码能够处理各种异常,给用户友好性的反馈,而不是有点小情况就罢工了、崩溃了。【我们理解客户的预算紧张和迫切的业务需求,同时建议甲方客户需要思考的是,仅仅要进度、省费用,可能换了一个不安全、不稳定,设计粗糙的系统,会造成更多的技术成本,包括时间、市场、品牌等等。】下面总结一下与安全开发、系统可维护的开发经验,对外提供更加健壮的表现,对内提供更加高效的运维,并支撑一个软件从无到有、从有到稳、从稳到优的不断迭代的过程。
三段法开发
无论是Web网页、服务器还是APP,永远不要相信输入信息是正确的,换句话说,在开发时,要假设所有输入都是不正确的,严格的检查所有输入、相关资源状态,确保你所用到的所有信息,完全在你的掌控之下,然后再进行业务逻辑处理。简言之,任何方法或函数的执行,至少分为三个阶段:合法性检查、业务逻辑、返回信息。
合法性检查
为什么要这么做?Web服务就像在互联网的大马路边上,敞开了一个大门,谁都可能进来,什么东西都有可能进来。有效的安全检查确保了系统的稳定和正确。做完一个项目后,你也想轻松一下,不是吗?难道还想继续继续的维护修改?原则:每段程序必须确保所有输入和依赖都是正确存在且合法。
请放心,实际工作并不像你想象的这么复杂,因为好的代码框架将会执行与业务无关的操作。但是你必须有这样的思想。
下面内容列举了一个Web请求在进行业务处理之前所需要进行的校验:检查输入的参数正确性;session是否合法;是否设置;是否为null;是否符合合法规则,例如身份证、是否符合默认的格式,例如id值(一般是自增变量,大于1且不超过11位的正整数);没有在参数列表显示,但是依然是输入的信息,例如$_POST, $_GET, $_SERVER等等;检查所依赖的信息是否正确、存在;所依赖的文件、类、方法、函数是否存在;所依赖的业务数据是否存在,且状态正常;所依赖的计算资源是否存在等等,不一而足。
业务逻辑
在经过了层层校验,就可以开始你真正想做的业务逻辑了,例如生成Hello Security的字符串。此处不再赘述。
返回数据
当服务端进行计算时,无论何种情况,永远不要自己直接结束处理,一定要给前端一个反馈。对于正确的情况,大部分朋友基本能够完成处理,但是往往会忽略异常的处理,甚至于有些代码直接die或者exit了。就好像你打电话给114查询一个车牌号的联系人,对方说请稍等,然后去查询,但是没有查询到,就去忙碌其他的事情或挂断电话,你是何种的感受?前后端的开发也是处理。一定要有礼貌的保持前后端的交互处理。
当有错误情况发生时,需要给前端一个友好性的反馈,并采用基于错误码机制的反馈机制处理。
日志
在我指导过的几个技术团队中有这么一种情况,大家非常积极热烈的讨论交流、努力思考并尝试解决生产系统出现的bug问题,却没有任何的证据和依据。这是一个低效和猜测的过程。为什么不去记录一些有效的日志呢?
请相信现有代码中已经嵌入了写日志的支持,并请保持一致的方式去使用;如果不熟悉,请先去熟悉掌握,切勿再发明一个写日志的办法。
日志级别:请依据规则使用写日志的方法
- INFO:在生产环境运行过程中,给运维工程师提示的信息
- ERROR:错误信息,对一次请求的错误信息提示,一般指请求及其相关操作或依赖有错误,导致本次请求无法处理
- WARN:对于业务操作的警告,不是系统所期待的样子,但是还是能够继续执行,需要运维工程师关注
- FATAL:致命错误,这将会导致系统无法正常运行
- ALARM:警告信息,运维工程师必须关注,会对系统或业务造成影响,但是不会造成系统停止
日志写什么内容?让负责运维的同事们看日志就能够知道绝大部分问题的原因,并能够自行处理,避免任何问题都找研发看代码,结果发现不是代码的问题。
例如:
一定记录整体的输入和输出;http请求第一次到达服务器的信息;http处理完成后返回给浏览器之前最后一步的信息;函数的输入和输出;关键节点或错误的依赖数据。
什么情况必须写日志?返回错误或抛出异常;日志级别:ERROR、ALARM、FATAL
内容:错误说明,相关的数据,以及需要检查的内容;关键输入和输出;
日志文件位置?日志文件应该保存到应用的工作目录下的log目录下(或者logs)。把日志文件随便写在一个目录当然很容易,就像随便摆放家里的家具位置一样。应该如何无需多说。