应用开发中的网络安全

最近有个朋友让我帮忙看看他系统中的一个问题:他给了我一个用户名密码,让我ssh到他的某台服务器上。那是一台redis server,里面存放数据库查询的缓存和其他的一些业务逻辑。问题断断续续花了不少时间才定位出来,期间应我的要求,朋友又给了我其它两台服务器的用户名和密码。在这个过程中,这个朋友在网络安全意识上的淡薄,可能也是很多web/mobile app开发者共通的问题。去年我有篇文章讲安全,主要集中在社工方面,今天,则讲讲网络安全。

在上面的例子里,朋友犯下了好几个常见的错误:

  1. 服务器直接通过公有IP暴露在互联网上。
  2. 管理端口(ssh port)没有对源IP做任何限制。
  3. 使用用户名+密码的方式而非用户名+密钥的方式登入。

下面我们讲讲这些错误的应对之策。

不要暴露不必要的服务

网络设计有个著名的原则:最小权限原则。最小权限原则要求计算环境中的特定抽象层的每个模块如进程、用户或者计算机程序只能访问当下所必需的信息或者资源。当我们赋予每一个合法动作最小的权限,就是为了保护数据以及功能避免受到错误或者恶意行为的破坏。[1]

理论上讲,一个互联网服务,暴露给任何源IP的只应该是必须对外的服务,如 web server,api server(本质上也是 web server),loadbalancer 等,按端口来说,主要是 80(HTTP)/443(HTTPS)端口。除了对外的服务器需要 public IP 外,其他任何服务器应该应该只有 private IP。如果应用部署在AWS,那么,只需要有 public ELB 即可;如果应用部署在自己(或者第三方)的数据中心,那么,只需要 nginx / haproxy 等服务所在的服务器有 public IP。

data base server 和 cache server 等内部服务,因为其只对 web server 提供服务,并不对最终用户提供服务,一定只能有 private IP。如下图:

每台服务器,除必要的对外服务端口外,其他端口一律封死。如 database server 是 mysql,那么就打开其缺省的 3306 端口。打开某个端口要注意其允许访问的源IP。即便是一台拥有 public IP 的服务器(如 web server),使用 ssh 访问的源 IP 也尽量只允许相同子网的内网IP。

打造安全的 ssh 服务

ssh 主要用在三种场合:

  1. 服务器诊断
  2. 服务器配置和软件安装
  3. 其他基于命令行的服务器管理任务

如今通过 logstash / reimann 等日志服务工具,各个服务器上的日志和事件都可以被集中到中心节点,方便查询和诊断。因此,为服务器诊断之目的而存在的 ssh 登入可以被替换。如果你使用 ssh 主要是此种目的,可以考虑选择一个合适的日志服务工具。

服务器配置和软件安装是大多数 ssh 登入的主要舞台。但如今这样一个高度自动化的时代,服务器的构建应该通过各种 ops 工具(如ansible/chef等)来完成,而非手工完成。如果大量的服务器配置和软件安装还通过 ssh 登入手工完成,那么,团队要考虑学习一种 ops 工具了。

尽管90%的场合下,服务器诊断和服务器的配置安装都可以通过工具完成,但还有少量的一次性任务不得不依赖 ssh。比如服务无法访问,也没留下什么日志的时候,你可能需要在服务器上使用 tcpdump 抓包做网络诊断。因此,临时性的ssh访问还是必要的。

对此,有两个方法访问:1) 在网络的边界设置一台 ssh server(如上图),2) 配置 SSL VPN。

在内网和外网的边界处设置一台 ssh server,管理员可以通过其 public IP ssh 登录进来,然后以其为跳板,进一步通过 ssh 登录到内网中的其他服务器进行管理。

专门的 ssh server,因为其可从互联网的任意位置进行访问,需要做一些特殊处理:登录的用户只拥有很小的权限(不能sudo),不能安装软件,系统里可运行的软件最好也最小化成只保留 ssh 和必要的软件。

除此之外,可以做这些设置:

  • 设置 ssh 登录的方式为仅允许用户名 + private key的方式,杜绝密码在网络上传输被破解的可能性。
  • 把 ssh port 换成一个非知名端口。这样虽然对特定的攻击(就是针对你的服务器)不起作用(还是可以针对你的IP一个端口一个端口嗅探出来),但可以防止被泛泛的攻击者锁定(有些攻击会嗅探全网的 22 端口,然后针对打开这一端口的服务器再进一步攻击)。
  • 在 iptables 里对能够访问的源 IP 进行限制 —— 如无必要,请不要允许任意源 IP。

相对于专门的 SSH 服务器,更 "professional" 的方法是配置 SSL VPN。SSL VPN的原理是在你的计算机和目标网络中建立一条隧道,使得你的计算机获得内网IP和路由,当你发起对内网的某台服务器的访问时,协议栈生成的 IP 包(Inner packet)会进入 SSL VPN tunnel,封装公网 IP 头,并使用 TLS 加密;当数据从 tunnel 出来后,又会被解密,把 inner packet 取出分发到目的地。对于服务器而言,你的访问等同于一个来自内网的访问。

配置SSL VPN的过程比较复杂,这里就不展开了,可以照着 openvpn 的文档一步步配置。初服务端需要安装外,每个需要访问内网的计算机还需要安装 vpn 软件(如 tunnelblick,如果要动态令牌,还需要安装 google authenticator),并为其生成客户端证书。整个过程很麻烦,但麻烦带来的好处是,大部分攻击者可以被拒之门外。

动态安全

将网络规划成内网和外网,赋予外界最小的访问权限,并在必要的情况下允许用户通过SSL VPN访问内网,进行管理任务。这样做,从网络安全的角度看,安全等级已经比较高了。但有些对安全性要求非常高的场合,还应该应用动态安全。

比如你有一个单独存放用户信用卡数据的 database cluster。该 cluster 里的服务器,只有一个叫 tyr 的管理员才能登录。tyr 需要通过 SSL VPN 接入到内网,获得到达服务器的路由,然后使用自己的私钥通过ssh访问该服务器。这虽然已经足够安全,但 ssh 的端口毕竟是一直打开的,万一内网中某个拥有外网 IP 的服务器(如 web server)被攻陷,攻击者可以利用该服务器为跳板进一步攻击,此时,一直打开 ssh port 就存在着潜在的风险。其实 ssh 端口并不需要一直打开 —— 有没有一种方式在想要访问的时候才通过iptables打开该端口,访问完毕后再关闭该端口呢?

当你想到这样的问题时,离解决方案也就不远了:你可以自己撰写一个服务,比如说叫:knock-knock。在接收到某种特定的命令,如客户端说:「天王盖地虎」,knock-knock 服务就在 iptables 里打开这个客户端对 ssh port 的访问;当客户端访问结束后,说一句「宝塔镇河妖」,knock-knock 服务就在 iptables 里关闭刚才打开的端口。

这进一步有个小问题:客户端如何连接 knock-knock 服务?如果说 knock-knock 专门监听某个端口,岂不是前驱狼后遇虎,关了 ssh port,又开了一个其他有潜在风险的 port?好问题。还记得十年前有个好玩的技术叫 Wakeup-On-LAN 么?只要在局域网内向目标机器发特定的 ethernet frame,目标机器的网卡收到之后就打开机器的电源。我们也可以使用类似的技术,向目标机器发送特定的报文,而目标机器上运行的服务使用 libpcap 监听所有网络流量,遇到自己识别的特征便执行相应的操作即可。

这样的服务其实早有自己的名称,叫 port-knocking [2],而且有开源的实现,其中一个实现是:knock [3]。

如上所述,knock 可以帮助你动态打开和关闭 ssh port,进一步增强了服务器的安全性。它可以这样使用:

$ knock yourserver.yourdomain.com 1111:tcp 2222:udp 3333:tcp

当网络中依次接受到这样三个预先定义好的对特定端口访问的建连报文(对TCP而言,是SYN包)后,knock 会执行某个动作(打开本机的 ssh 端口)。

防火墙

大部分的云服务商都提供了基本的网络防火墙功能,可以在网络层面限制数据的流入流出,做好了以上的安全措施,再设置合理的 firewall rule(或 ACL)你的网络已经比较安全了。如果需要更多(更高级)的安全手段,可以考虑在网络的边缘部署软件或硬件防火墙。这里就不多说了。

以上所涉及的安全内容仅为网络安全。安全是个一揽子解决方案,在不同的层级上要做好不同的安全,网络再安全,如果应用层的安全没做好,一样会被攻击地体无完肤。

(本文会被修改收录在我正在撰写『构建安全的系统』一书中,如果你对如何打造安全的系统有任何问题,或者对这样一本书与什么样的期许,欢迎在公众号里联系我进行讨论)


1. 见:https://zh.wikipedia.org/wiki/%E6%9C%80%E5%B0%8F%E6%9D%83%E9%99%90%E5%8E%9F%E5%88%99

2. 见:https://en.wikipedia.org/wiki/Port_knocking

3. 见:https://github.com/jvinet/knock

原文发布于微信公众号 - 程序人生(programmer_life)

原文发表时间:2015-06-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏编程

前端异常监控系统

来源:子慕大诗人 http://www.cnblogs.com/1wen/p/7942608.html 导火索 有一天一个测试同事的一个移动端页面白屏了,看样子...

4387
来自专栏Java架构师进阶

浅谈Nginx负载均衡与F5的区别

笔者最近在负责某集团网站时,同时用到了Nginx与F5,如图所示,负载均衡器F5作为处理外界请求的第一道“墙”,将请求分发到web服务器后,web服务器上的Ng...

1341
来自专栏西安-晁州

使用pd从数据库逆向生成pdm文件

1533
来自专栏FreeBuf

Hacking Team间谍软件Soldier工程分析

Hacking Team这次泄露的信息包括很多监视代码。如Windows平台上的间谍软件工程Soldier(战士),用于非法监听用户的上网信息和本地信息。今天我...

19210
来自专栏CSDN技术头条

Linux 4.6促进了容器的安全性,添加对OrangeFS的支持

如预期一样,Linux的核心任务Linux Torvalds周日发布了Linux Kernel 4.6。新版本支持一个新型的分布式文件系统OrangeFS,采用...

1986
来自专栏前端布道

MEAN-全堆栈javascript开发框架

引言 使用JavaScript能够完整迅速做出Web应用程序,目前一套工具包括MongoDB、ExpressJS,AngularJS和Node.js越来越受到欢...

3525
来自专栏无题

在高并发的核心技术中如何实现幂等性

* 实际系统中有很多操作,是不管做多少次,都应该产生一样的效果或返回一样的结果。 例如: 前端重复提交选中的数据,应该后台只产生对应这个数据的一个反应结果。 ...

72911
来自专栏Golang语言社区

像iPhone一样好玩的Web服务器: Caddy

据Netcraft今年5月份放出了一篇统计文章中,Apache、Nginx和微软的IIS分别以45.61%、20.22%和7.83%市场占有率依然排在“活跃网站...

65211
来自专栏Netkiller

怎样入住IDC机房或迁移IDC机房

4.3. 机房迁移 总结一下5年前的工作,在不写下来自己都快忘光了,工作关系现在已经不涉及运维这块的工作。 4.3.1. 拓扑确立 首先制定服务器拓扑图,拓扑...

4165
来自专栏张戈的专栏

分享一个支持https的CDN及启用SSL后续问题汇总

之前张戈博客全站启用了 https,并分享了相关经验心得。用了一段时间,问题还是不少,所以继续整上一篇文章,汇总一下网站启用 https 之后出现的问题以及解决...

4.5K7

扫码关注云+社区

领取腾讯云代金券