前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >应用开发中的网络安全

应用开发中的网络安全

作者头像
tyrchen
发布2018-03-28 15:24:05
8230
发布2018-03-28 15:24:05
举报
文章被收录于专栏:程序人生程序人生

最近有个朋友让我帮忙看看他系统中的一个问题:他给了我一个用户名密码,让我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 V**。

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

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

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

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

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

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

动态安全

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

比如你有一个单独存放用户信用卡数据的 database cluster。该 cluster 里的服务器,只有一个叫 tyr 的管理员才能登录。tyr 需要通过 SSL V** 接入到内网,获得到达服务器的路由,然后使用自己的私钥通过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,进一步增强了服务器的安全性。它可以这样使用:

代码语言:javascript
复制
$ 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

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2015-06-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序人生 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 不要暴露不必要的服务
  • 打造安全的 ssh 服务
  • 动态安全
  • 防火墙
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档