gitbook/安全攻防技能30讲/docs/186777.md
2022-09-03 22:05:03 +08:00

149 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 13 | Linux系统安全多人共用服务器如何防止别人干“坏事”
你好,我是何为舟。
从这一讲开始我们讨论Linux系统和应用安全。我们知道在开发一个应用的过程中需要涉及代码、操作系统、网络和数据库等多个方面。所以只是了解代码安全肯定是不够的我们还需要了解常见的基础环境和工具中的安全机制学会通过正确地配置这些安全机制来提升安全保障。
谈到Linux我相信你每天都在使用Linux进行各种开发和运维操作。但是大多数情况下公司不会给每一个员工分配专有的Linux服务器而是多个开发和运维共用一台Linux服务器。那么其他员工在使用Linux服务器的时候会不会对我们自己的数据和进程产生影响呢另外我在Web安全中讲过黑客可以通过很多漏洞控制Linux服务器那我们又该如何避免和控制黑客的破坏呢
## 如何理解Linux中的安全模型
要解决这些安全问题我们首先要了解一个安全模型Linux的安全模型。
我们先来看一下Linux的构成Linux可以分为内核层和用户层。用户层通过内核层提供的操作接口来执行各类任务。
内核层提供的权限划分、进程隔离和内存保护的安全功能,是用户层的安全基础。一旦内核安全被突破(比如黑客能够修改内核逻辑),黑客就可以任意地变更权限、操作进程和获取内存了。这个时候,任何用户层的安全措施都是没有意义的。
既然Linux的内核安全这么重要那我们是不是要在防护上付出大量的精力呢事实上正如我们不需要在开发应用时尤其是使用Java这类相对高层的语言时过多地关心操作系统相关的内容一样我们在考虑Linux安全时也不需要过多地考虑内核的安全更多的是要考虑用户层的安全。所以对于Linux内核层的安全我们只需要按照插件漏洞的防护方法确保使用官方的镜像并保持更新就足够了。
既然,使用最多的是用户层,那我们就来看一下,用户层的操作都有什么。
在Linux中用户层的所有操作都可以抽象为“主体->请求->客体”这么一个流程。比如,“打开/etc/passwd”这一操作的主体是实际的用户请求是读客体是/etc/passwd这个文件。
![](https://static001.geekbang.org/resource/image/6c/7d/6c581c176186ff38ab931210b7073a7d.jpeg)
在这个过程中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都定义了读、写和执行这三种权限。你可以通过我总结的这张对比表格看到文件和目录在这三种权限上的区别。
![](https://static001.geekbang.org/resource/image/fd/2c/fdea7d4bfebb7e8114ce64f82a32e22c.jpeg)
除此之外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等在后续的内容中我们会深入讲解这些工具。
最后,我把这一讲的重点内容梳理了一个脑图。你可以用它来查漏补缺,也可以自己来梳理看看,加深印象。
![](https://static001.geekbang.org/resource/image/46/72/46d1a126a68fe253eb8746d84b5d0272.jpg)
## 思考题
最后给你留一个思考题。
检查一下你的Linux服务器看一下哪些用户具备ROOT权限那些进程具备ROOT权限这些用户和进程真的需要ROOT权限吗我们是否可以利用今天学到的知识对这些ROOT权限进行限制呢
欢迎留言和我分享你的思考和疑惑,也欢迎你把文章分享给你的朋友。我们下一讲再见!