T上西北

Web安全-隐藏Web Server信息

这是一个非常容易忽略的点。

Web Server的信息包括:

  • Web Server的类型,常见的如Tomcat, Apache Httpd,Ngnix等。
  • 版本信息。即web server的版本信息。

为什么要隐藏这些信息呢?原因很简单,我们非常容易获取web server的软件信息。那么对于攻击者可以做什么呢?我们知道每种软件都是有漏洞的,尤其是对于这些著名的软件。如果出现安全性漏洞,一般都是公开的,而且有些漏洞有详细的复现步骤。

其他web server不在这里例举了。

所以,当攻击者知道web server信息,又加上这对每个漏洞的详细解释,攻击就简单多了。

那么如何隐藏web 容器信息呢?一般来说是可以通过配置解决的。

Apache Tomcat

可以在server.xml里的Connectorserver属性解决。参考https://tomcat.apache.org/tomcat-7.0-doc/config/http.html

Apache HTTPd
security.conf里的ServerSignature Off

Web安全- Command Injection

Command Injection,是指Web App调用系统命令去实现某些功能,同时因为不安全的web请求数据(例如Form,Cookie,HTTP header等)利用该功能造成一些安全影响。

实例

下面的例子便于理解。

本例子来源https://www.owasp.org/index.php/Command_Injection

下面的PHP代码会引起Command Injection:

<?php
print("Please specify the name of the file to delete");
print("<p>");
$file=$_GET['filename'];
system("rm $file");
?>

我们看看请求和返回。

请求

http://127.0.0.1/delete.php?filename=bob.txt;id

响应

Please specify the name of the file to delete

uid=33(www-data) gid=33(www-data) groups=33(www-data) 

我们可以看到,如果执行web的function id足够大的话,是极有可能把不应该的数据删除了,例如filename为/,同时我们也可以看到该id所在的group。

解决方案

可以尽量使用API。例如上面要删除一个文件,可以使用php语言的api去删除文件,而不是调用OS的rm命令。

如果没有相关的API去调用,一定要调用这些command,务必做好命令的验证。就个人经验看,验证允许的command比验证不允许的command要简单一些。

软件开发规则

最后版本: rev 5
最后更新: 2017-04-21

设计

  1. 注重软件设计。
  2. High Available需要考虑。
  3. Geo Redundancy也需要考虑,如果设计web的话。
  4. 考虑软件的需求,有无可能复杂化,定制化,这决定了软件架构,
  5. 将需求详细化,但实现时简单化。
  6. 数据库主从结构,Replication,数据一直等。
  7. web的安全性方面是必须考虑的。
  8. 软件都是逐步迭代的,为了让后期迭代的成本更小,起点最好高一些。
  9. 事先定义软件的版本管理。
  10. 站在使用者的角度去思考。
  11. 解放思想,考虑问题站在高一点的位置。
  12. 防止过度设计。


Coding

  1. 一个文件代码不要太多,1K行左右,一个函数也不同太多,100行左右,如果太多的话,就应该考虑如何去分拆了。
  2. 代码一开始就要考虑模块化。
  3. 代码可重用性。
  4. 代码不能太耦合。
  5. 对于异常case务必写日志,不要认为捕获了就OK了。
  6. 良好的代码目录结构。
  7. 对于SQL等一些reserved keywords建议用大写,例如SELECT * FROM <tbl-name> WHERE field1=v AND field2 = v2
  8. 代码格式上须易于阅读,空格,空行等是必要的。Java有Java的代码规范,可以作为参考准则。
  9. 注释需要合理,不在于多,而在于精。对业务复杂的业务逻辑,加适当的注释会锦上添花。
  10. 代码格式可以利用一些专业化的工具进行检测,例如Sonar,JSLint等。
  11. 写代码是软件开发里非常简单的事情,但是做好不容易。基础非常重要。态度谦逊,借鉴优秀人员的代码,避免自己的不足。
  12. 一开始就要写好,不要以后面可以重构当借口。
  13. 对于web开发,安全性非常重要。可以写完后用安全扫描工具(例如AppScan等)进行扫描。掌握经验,在后面的coding种尽量去避免。
  14. 尽量将问题或需求想的全面,实现时根据实际情况可以取舍。
  15. 设计准备好了才可以写代码。
  16. 对于异常case多处理,不要认为发生的可能性不大。
  17. 尽量让代码的适应性强一些,考虑一些配置来适应未来的需求。
  18. 代码用Maven,Gradle等进行build
  19. 拼接SQL语句需要考虑的SQL安全性,SQL 的 保留关键字或字符,建议用PreparedStatement去完成。

Log

  1. 清晰的日志易于做troubleshooting
  2. 清晰的日志易于team之间的交流和学习。
  3. 日志注意拼写错误,英文合适。
  4. 日志需要将业务分步描述清楚。
  5. 建议developers多做Ops的工作,以便于了解到底什么样的日志才是优美的。
  6. 对于正常的业务也许打log,对于异常的case务必打log。常遇见的情况是正常的业务逻辑少,只有一些exception的case 才打。导致正常业务出问题没法进行troubleshooting。
  7. log的级别。什么样的信息适合什么样的log level,取决于业务。

SCM(SVN/GIT)

  1. 保证仓库里的代码是可以编译通过的。
  2. 代码尽量每天提交。
  3. 一次只提交一个功能或者bug fix代码。
  4. 提交代码时,写上comment描述当次修改。
  5. 如果是bug fix,在comment里注明bug id,如果是功能,注明requirement id。
  6. 安装合适的工具,例如Trac, Phabricator,以及Bitbucket等

Code Review

  1. 强烈建议team之间内部相互review。
  2. 条件允许的话,只有代码进行code review过了,才可以commit到仓库里。
  3. 开Code Review会议前,相关人员提前review一遍。在会议上只提问。
  4. Code Review时只提及修改的部分。
  5. Code Review可以用一些工具,例如Phabricator,ReviewBoard,以及Bitbucket等。

Test

  1. 写单元测试(Unit Test), 可以简单理解白盒测试。
  2. 写功能测试(Functional Test),可以简单黑盒测试。
  3. 一般项目都会用daily build,将单元测试和功能测试加入daily build的task中。
  4. 代码覆盖率也很重要。
  5. 代码必须测试过才可以发出去(内部或者外部)
  6. Test Cases需要详尽才可以,认真写。
  7. Test Cases不是应付,不是交代,而是软件质量的一小步。
  8. 用测试框架去Test case,。例如,在Java里,很多人有个习惯是在class里增加一个main方法去驱动测试某个函数。

 

修改历史记录

  1. 2017-03-08, 第一版起稿。
  2. 2017-03-09, 增加测试部分,以及部分coding规则。
  3. 2017-3-13,增加设计章节。增加测试部分(>=6),log部分(>=6),代码部分(>=14)等
  4. 2017-3-16,增加设计部分(>10)
  5. 2017-4-21, 增加coding 的18,19,修改Log的6