简单说说如何编写安全的代码

前段时间看完了《代码整洁之道》,发现其中很多方法有助于去编写更加安全的代码。以前在阅读一些 Web App 中,找到一些漏洞皆是在代码编写风格上出现的问题,比如,一个 CMS 有文章分类、文章显示、评论等等功能,在针对每一种功能的参数进行处理时,都单独做过参数过滤,也就是说,存在大量冗余的过滤代码,很可能在某一功能上可能是安全的,在另外一种功能上却存在漏洞。这种比较极端的例子还是很多的。因此:

在写函数时,我们尽可能保证函数代码的短小,代码越是长,出现的问题越可能变得很多,无论是功能上的 bug,还是可能的安全隐患。那么如何把函数编写得更加短小呢?其实很简单,只让函数去处理一个功能,并且专心处理这个功能,其他与这个功能无关的,我们将它编写成另外的函数来调用。比如很多 Web App 这样实现的:

$id = $_GET['id'];
// 中间一长窜过滤的代码
$sql = 'select * from articles where id='.$id
$query = Mysql::query($sql)

然后在另外一处地方又出现了类似的不同功能的参数处理代码,因此对于这种情况,我们应该绝对保证:1、程序中绝对不能有重复功能的代码,将重复的全部写成一个函数或者放在类中;2、函数短小,将很多琐碎的分成其他函数;3、函数不要关心其他功能,只认真处理好本该完成的功能,这也是函数的本身具有的意义。也就是说,上方的例子中过滤代码可以单独写成一个函数,所有其他类似的地方都只应该调用这个函数,而不是每个地方都单独编写一长窜代码来过滤。

函数应该短小到多少呢,其实我也不清楚,五行到二十行就差不多了吧。目前我写的博客程序中,完全是面向对象写的,一个函数或者方法目前最多的行数目前是5行,普遍在一行和三行左右,或许以后还要稍微长一点点,但绝对不会太多。函数越是小,我们发现问题和处理问题的效率越是高——至少我这么觉得。顺便说句,需要给函数一个合理的、能够看函数名就知函数功能的命名,别弄得连自己都看不懂这个函数是干嘛的。

运用注释

打 TODO 注释的地方应该要完成什么什么样的功能。我写代码的时候,先把主要的精力投入在完成功能上,在可能涉及到安全问题的地方打一个 TODO 注释,最后根据注释来做处理。比如我博客的一个搜索功能:

public function searchKey($key)
{
    //TODO: 过滤跨站和注入
    return self::getResultArray("select ar_title,ar_category,post_time,post_author from
    lx_articles where ar_title like '%$key%'");
}

最后再来解决安全问题。当然,这只是个人方法而已。

运用思维导图

思维导图是一种组织思维,将思维清晰表达出来的一种方式。看很多 Web App 的时候,从代码风格上就可以看出他们的思维硬是混乱的,很极端的例子就如我上面说到的问题,太多冗余的安全处理代码。看这种程序会加大我找到漏洞的信心,我相信这里处理好了,另外一个地方多半都是有问题的。其实,那些处理代码很可能参考网上的,或者直接剽窃过来的。从这点就能知道该作者对安全方面的意识很薄弱。但是,我们还是可以装成很牛的样子,先对整体要完成的功能画一个思维导图,中间把可能出现的问题就顺路画出来了,类似于安全建模,但我们绘制的图更偏向于程序整体的构架。例如下面我针对搜索功能画的一个极其简单的图,该图可能随着我的新想法新点子随时改进:

1.jpg