avatar

青青子衿的拾枝杂谈

A text-focused Halo theme

  • 首页
  • linux基础
  • Linux系统
  • Linux高级
  • nginx
  • k8s
  • 网络
Home 网络协议与安全
文章

网络协议与安全

Posted recently Updated recently
By 青青子衿
118~152 min read

网络协议与安全 -- 从入门到实战


目录

  1. IP地址 -- 网络世界的门牌号
  2. TCP/IP协议 -- 数据快递的工作流程
  3. iptables防火墙 -- 经典门卫系统
  4. firewalld防火墙 -- 新一代智能门禁
  5. VPN虚拟专用通道 -- 公网中的秘密隧道
  6. 中间人攻击 -- 当心有人偷听你的对话
  7. sudo权限管理 -- 不是所有钥匙都要交给一个人
  8. SELinux -- 给系统穿上防弹衣

1. IP地址 -- 网络世界的门牌号

生活中的类比

想象一下:你住在一栋公寓楼里。你家的地址由两部分组成——小区名称(表示你住在哪个小区)和楼栋门牌号(表示你是小区里的哪一户)。

IP地址也是如此:它由 网络号(NetID) 和 主机号(HostID) 两部分组成。网络号标识你属于哪个网络,主机号标识你是该网络中的哪台设备。

1.1 IPv4地址结构

问题: 计算机是如何用一串数字来标识全球数十亿台设备的?

解答: IPv4地址是一个 32位的二进制数,为了方便人类阅读,我们把它分成4段,每段8位(1个字节),转换成十进制数,用小数点隔开。这种写法叫做 点分十进制表示法。

二进制形式:  11000000 . 10101000 . 00000001 . 00000001
十进制形式:  192      . 168      . 1        . 1

每段的取值范围是 0~255(因为8位二进制最大值为11111111 = 255)。

所以一个IPv4地址总共有 2^32 = 4,294,967,296 个可能的地址。

数学联系: 这里涉及到了二进制与十进制的转换,以及排列组合。32位地址空间 = 2^32 种组合,这就是IPv4地址总量约43亿个的由来。

1.2 IP地址的分类

问题: 全世界有大大小小的网络,有的公司只有一百台电脑,有的运营商有上百万台设备。怎么合理分配地址?

解答: 早期的互联网将IP地址划分为 A、B、C、D、E 五类,以适应不同规模的网络需求。

类别首位特征第一段范围默认子网掩码网络数每网络最大主机数适用场景
A类01~126255.0.0.0 (/8)12616,777,214超大型网络
B类10128~191255.255.0.0 (/16)16,38465,534中型网络
C类110192~223255.255.255.0 (/24)2,097,152254小型网络
D类1110224~239------组播地址
E类11110240~254------保留实验

数学联系: 主机数的计算公式是 2^n - 2,其中n是主机号的位数。减2是因为:

  • 全0的主机号 = 网络地址本身(如192.168.1.0)
  • 全1的主机号 = 广播地址(如192.168.1.255)

例如C类地址:主机号8位,可用主机 = 2^8 - 2 = 254个。

特殊地址须知:

  • 127.0.0.0/8:环回地址,用于本机测试(127.0.0.1 = localhost)
  • 169.254.0.0/16:当DHCP失败时,系统自动分配的临时地址
  • 0.0.0.0:表示当前主机或默认路由

1.3 子网掩码与CIDR

问题: 一个C类网络有254个可用地址。如果我只需要50个地址,剩下的200多个不就浪费了吗?

解答: 这就是 子网划分(Subnetting) 要解决的问题。我们通过借用主机号中的一些位来作为子网号,从而把一个大的网络分割成多个小的子网。

子网掩码就是用来标识IP地址中哪些位是网络号(含子网号)、哪些位是主机号的。掩码中 1 对应的位是网络部分,0 对应的位是主机部分。

计算示例

题目: IP地址为 192.168.1.130,子网掩码为 255.255.255.192,求该IP所在的网络地址、广播地址和可用主机范围。

解题步骤:

第一步:将掩码转为二进制,确定主机位数
255.255.255.192 = 11111111.11111111.11111111.11000000
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  ^^^^^^
                        网络部分(26位)                主机部分(6位)

第二步:CIDR表示法 → /26 (26个1)

第三步:IP与掩码做AND运算,得到网络地址
IP:   192.168.1.  10000010
掩码: 255.255.255.11000000
AND:  192.168.1.  10000000 = 192.168.1.128

第四步:主机位全0 → 网络地址: 192.168.1.128
        主机位全1 → 广播地址: 192.168.1.10111111 = 192.168.1.191

第五步:可用主机范围
  起始: 192.168.1.129
  结束: 192.168.1.190
  可用主机数: 2^6 - 2 = 62台

常见子网划分速查表

CIDR子网掩码可用主机数子网数量(C类中)
/24255.255.255.02541
/25255.255.255.1281262
/26255.255.255.192624
/27255.255.255.224308
/28255.255.255.2401416
/29255.255.255.248632
/30255.255.255.252264

课堂练习: 某学校需要将一个C类网络 192.168.10.0/24 划分为4个子网,每个子网至少能容纳50台主机。请问子网掩码应设为多少?

答案: 需要4个子网 → 借用2位主机位 → /26 → 掩码255.255.255.192,每个子网可用主机 2^6 - 2 = 62 > 50,满足需求。

1.4 私有IP与公网IP

问题: IPv4只有43亿个地址,全世界设备远不止这个数,怎么办?

解答: 使用 私有IP地址(Private IP)。私有IP在局域网内部使用,不需要全球唯一,多个不同的局域网可以使用相同的私有IP段。当需要访问互联网时,通过 NAT(网络地址转换) 将私有IP转换为公网IP。

类别私有IP范围CIDR表示可用地址数
A类10.0.0.0 ~ 10.255.255.25510.0.0.0/8约1677万
B类172.16.0.0 ~ 172.31.255.255172.16.0.0/12约104万
C类192.168.0.0 ~ 192.168.255.255192.168.0.0/16约6.5万

生活类比: 私有IP就像公司内部的分机号(如8001、8002),不同公司的分机号可以重复使用。公网IP才是对外的总机号码。

1.5 实用命令:ip命令替代ifconfig

# 查看网卡信息(含MAC地址、MTU等)
ip link show
ip -s link show eth0          # -s 显示数据包统计

# 启用/禁用网卡
ip link set eth0 up
ip link set eth0 down

# 修改MTU(最大传输单元,默认1500字节)
ip link set eth0 mtu 1400

# 查看IP地址
ip addr show

# 添加/删除IP地址(临时生效)
ip addr add 192.168.50.50/24 dev eth0
ip addr del 192.168.50.50/24 dev eth0

# 查看路由表
ip route show

# 添加默认网关
ip route add default via 192.168.1.1

# 添加静态路由
ip route add 10.10.10.0/24 via 192.168.1.254

# 查看ARP缓存(IP与MAC的映射表)
ip neigh show

提示: ip 命令的修改是 临时 的,重启后失效。永久修改需要编辑网卡配置文件(如 /etc/sysconfig/network-scripts/ifcfg-eth0)。


2. TCP/IP协议 -- 数据快递的工作流程

生活中的类比

把网络通信想象成 寄快递:

  • 物理层 = 公路和卡车(实际运输的工具)
  • 数据链路层 = 快递分拣站(负责相邻站点间的传递)
  • 网络层 = 快递路由系统(决定包裹从北京到上海走哪条路线)
  • 传输层 = 快递保险服务(TCP=保价快递,丢件必赔;UDP=明信片,丢了不管)
  • 应用层 = 你寄的具体物品(网页、文件、邮件等)

2.1 OSI七层模型与TCP/IP模型

问题: 网络通信涉及硬件、软件、协议等众多环节,如何理解和管理这种复杂性?

解答: 采用 分层模型,每一层只负责一个特定的功能,层与层之间通过接口交互。这和数学中的 函数复合 思想相似——f(g(h(x))),每个函数只做一件事。

┌─────────────────────────────────────────────┐
│             OSI七层模型                      │
│                                              │
│  ┌──────────┐    ┌────────────────────────┐  │
│  │ 应用层   │←──→│ 应用层(HTTP/FTP/SSH) │  │
│  ├──────────┤    ├────────────────────────┤  │
│  │ 表示层   │    │                        │  │
│  ├──────────┤    │    TCP/IP四层模型       │  │
│  │ 会话层   │←──→│                        │  │
│  ├──────────┤    ├────────────────────────┤  │
│  │ 传输层   │←──→│ 传输层(TCP/UDP)       │  │
│  ├──────────┤    ├────────────────────────┤  │
│  │ 网络层   │←──→│ 网络层(IP/ICMP/ARP)  │  │
│  ├──────────┤    ├────────────────────────┤  │
│  │ 数据链路 │←──→│ 数据链路层+物理层       │  │
│  ├──────────┤    │ (以太网/WiFi)         │  │
│  │ 物理层   │    └────────────────────────┘  │
│  └──────────┘                                │
└─────────────────────────────────────────────┘

实际工作中,我们通常使用简化的TCP/IP四层模型。OSI七层模型主要用于教学和理论讨论。

2.2 TCP三次握手 -- 建立可靠连接

问题: 两台电脑要开始通信了,怎么确保双方都准备好了?

解答: TCP使用 三次握手(Three-way Handshake) 来建立连接。

生活类比: 打电话的过程就是"三次握手"

  • 你拨号 → 对方接起来 → 你说"喂,听得见吗?" → 对方说"听得见" → 你说"好的" → 开始聊正事
客户端 (Client)                    服务器 (Server)
    │                                    │
    │──── 1. SYN (seq=x) ──────────────→│  "我想和你通信"
    │                                    │
    │←─── 2. SYN+ACK (seq=y, ack=x+1) ──│  "好的,我也想和你通信"
    │                                    │
    │──── 3. ACK (ack=y+1) ────────────→│  "收到,我们开始吧"
    │                                    │
    │══════════ 连接建立,开始传输数据 ══════════│

关键标志位:

标志含义类比
SYN同步(Synchronize),发起连接拨号
ACK确认(Acknowledgment),确认收到"收到"
FIN结束(Finish),关闭连接"挂了"
RST重置(Reset),强制断开直接挂断电话
PSH推送(Push),立即传递数据"这个急,马上看"
URG紧急(Urgent),紧急数据优先处理"十万火急"

2.3 TCP四次挥手 -- 断开连接

客户端                              服务器
  │                                    │
  │──── 1. FIN ──────────────────────→│  "我说完了"
  │←─── 2. ACK ──────────────────────│  "收到你说完了"
  │                                    │  (服务器可能还有数据要发)
  │←─── 3. FIN ──────────────────────│  "我也说完了"
  │──── 4. ACK ──────────────────────→│  "好的,拜拜"
  │                                    │
  │ (等待2MSL时间后关闭)               │ (收到ACK后立即关闭)

为什么是四次而不是三次? 因为TCP是 全双工 通信(双方可以同时发送和接收),每个方向必须独立关闭。就像挂电话——你说完了不代表对方也说完了。

2.4 TCP vs UDP

特性TCP(挂号信)UDP(明信片)
连接方式面向连接(三次握手)无连接
可靠性可靠(确认、重传)不可靠
速度较慢较快
首部长度20~60字节8字节
适用场景网页、文件传输、SSH视频通话、DNS查询、游戏

类比: TCP就像挂号信——有回执、保证送到、但费用高速度慢。UDP就像明信片——便宜快速、但不保证对方能收到。视频通话偶尔丢一两帧画面无所谓,所以用UDP;但下载文件一个字节都不能丢,所以必须用TCP。

2.5 常见端口速查

端口协议用途传输层
20/21FTP文件传输(20=数据,21=控制)TCP
22SSH远程安全登录TCP
23Telnet远程登录(明文,不安全)TCP
25SMTP发送邮件TCP
53DNS域名解析UDP/TCP
80HTTP网页浏览TCP
110POP3接收邮件TCP
443HTTPS加密网页TCP
3306MySQL数据库TCP
8080HTTP-AltWeb代理/备用HTTPTCP

2.6 数据包流动全过程 -- 以ping为例

问题: 当你在电脑上输入 ping www.baidu.com 时,到底发生了什么?

解答: 让我们用 tcpdump 抓包工具来一探究竟。

# 安装抓包工具
yum install -y tcpdump

# 抓取ping的数据包(ICMP协议)
tcpdump -i eth0 -nn icmp and host 192.168.1.1

# 抓取指定端口的TCP数据包
tcpdump -i eth0 -nn -S host 192.168.1.1 and port 80

# 保存抓包结果到文件(可用Wireshark分析)
tcpdump -i eth0 -nn -w /tmp/capture.pcap host 192.168.1.1

一次ping的完整过程:

1. DNS解析: www.baidu.com → 180.101.50.242(使用UDP 53端口)
2. ARP查询: 180.101.50.242 的MAC地址是什么?(广播FF:FF:FF:FF:FF:FF)
3. ARP应答: 网关回复自己的MAC地址
4. 构造ICMP Echo Request(类型8),封装到IP数据报
5. 数据报 → 数据链路层封装以太网帧 → 物理层发送
6. 沿途路由器根据IP头部TTL逐跳转发
7. 目标收到后回复ICMP Echo Reply(类型0)
8. 本机收到回复,显示延迟时间

ICMP协议重点类型:

TypeCode含义常见触发场景
80Echo Request(ping请求)你ping别人
00Echo Reply(ping回复)别人回你
30网络不可达路由找不到目标网段
31主机不可达路由找到网段但找不到主机
33端口不可达目标主机上该端口未开放

动手实验: 使用 tcpdump 抓取ARP包,观察MAC地址解析过程:

# 先清空ARP缓存
arp -d
# 然后抓包并ping
tcpdump -i eth0 -nn arp &
ping -c 1 192.168.1.1

2.7 ARP协议 -- IP与MAC的桥梁

问题: 网络层用IP地址寻址,但以太网实际传输时用的是MAC地址(物理地址)。如何把IP转换为MAC?

解答: ARP(Address Resolution Protocol,地址解析协议) 就是完成这个翻译工作的。

类比: 你知道收件人的名字(IP地址),但快递员需要具体的门牌号(MAC地址)才能送达。ARP就像是你在小区群里喊了一声:"张三家住几号楼几单元?"——这就是ARP广播。

ARP工作流程:
1. 本机检查ARP缓存表,看有没有目标IP对应的MAC
2. 如果没有 → 发送ARP广播: "谁是192.168.1.1?请告诉我你的MAC"
3. 目标主机回复: "我是192.168.1.1,我的MAC是 AA:BB:CC:DD:EE:FF"
4. 本机更新ARP缓存表
# 查看ARP缓存表
arp -n
# 或者
ip neigh show

# 手动绑定IP和MAC(防止ARP欺骗)
arp -s 192.168.1.1 AA:BB:CC:DD:EE:FF

3. iptables防火墙 -- 经典门卫系统

生活中的类比

把防火墙想象成 公寓大楼的保安:

  • 保安手里有一份 访客规则表(规则链)
  • 每个来访者都要对照规则表逐条检查
  • 规则从上到下匹配,一旦匹配就执行对应动作,不再继续往下查
  • 如果所有规则都不匹配,就按 默认策略 处理(默认放行或默认拒绝)

iptables的工作方式就是这样——数据包进入后,依次匹配规则,匹配到就执行动作。

3.1 基础架构:表、链、规则

问题: 防火墙如何决定一个数据包是放行还是丢弃?

解答: iptables的核心架构是 表(Table)→ 链(Chain)→ 规则(Rule) 三级结构。

┌─────────────────────────────────────────────────────┐
│              iptables 规则处理流程                    │
│                                                      │
│  数据包进入                                           │
│      │                                               │
│      ▼                                               │
│  ┌─────────┐   ┌─────────┐   ┌───────┐   ┌────────┐│
│  │  raw表   │→│ mangle表 │→│ nat表  │→│filter表││
│  └─────────┘   └─────────┘   └───────┘   └────────┘│
│                                                      │
│  各表中的链:                                          │
│                                                      │
│  PREROUTING  ─── 数据包刚进入,还未路由               │
│       │                                              │
│       ▼                                              │
│  [路由判断] ──→ 是发给本机的?                        │
│       │              │                               │
│       │         不是(转发)                            │
│       │              │                               │
│       ▼              ▼                               │
│    INPUT链       FORWARD链                           │
│       │              │                               │
│       ▼              ▼                               │
│    本机进程     OUTPUT链                              │
│       │              │                               │
│       ▼              ▼                               │
│   POSTROUTING链 ─── 数据包即将离开                   │
│                                                      │
└─────────────────────────────────────────────────────┘

四张表的作用:

表名用途常用链
filter过滤数据包(最常用)INPUT, OUTPUT, FORWARD
nat地址转换(NAT)PREROUTING, POSTROUTING, OUTPUT
mangle修改数据包标记PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING
raw在连接跟踪前处理PREROUTING, OUTPUT

3.2 基本规则操作

# ===== 查看规则 =====
iptables -L -n -v --line-numbers       # 查看filter表所有规则,显示行号
iptables -t nat -L -n -v               # 查看nat表

# ===== 清除规则(慎用!先确保SSH不会被锁) =====
iptables -F                            # 清除filter表所有规则
iptables -t nat -F                     # 清除nat表所有规则
iptables -X                            # 删除自定义链
iptables -Z                            # 计数器清零

# ===== 添加规则 =====
# 语法: iptables [-t 表名] 操作 链名 匹配条件 -j 动作

# 禁止某IP访问本机
iptables -A INPUT -s 192.168.1.100 -j DROP

# 禁止某个网段访问
iptables -A INPUT -s 192.168.1.0/24 -j DROP

# 允许SSH访问(端口22)
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# 允许HTTP和HTTPS
iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT

# 禁止某IP的ICMP(不让ping)
iptables -A INPUT -s 192.168.1.100 -p icmp -j DROP

# ===== 插入规则(默认插到第1条) =====
iptables -I INPUT -p tcp --dport 22 -j ACCEPT      # 插到最前面
iptables -I INPUT 3 -p tcp --dport 80 -j ACCEPT    # 插到第3条

# ===== 删除规则 =====
iptables -D INPUT -s 192.168.1.100 -j DROP         # 按内容删除
iptables -D INPUT 3                                # 按行号删除

# ===== 设置默认策略 =====
iptables -P INPUT DROP         # 默认丢弃所有进入的数据包
iptables -P FORWARD DROP       # 默认不转发
iptables -P OUTPUT ACCEPT      # 默认允许本机发出的数据包

3.3 实战:搭建一个安全防火墙脚本

场景: 一台对外提供Web服务(80/443)和SSH管理(22)的服务器。

#!/bin/bash
# === 安全防火墙配置脚本 ===
# 原则:默认拒绝一切,只放行必要的服务(最小权限原则)

# 第一步:先允许已建立的连接(防止把自己锁在外面)
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 第二步:允许本地回环(很多服务依赖localhost通信)
iptables -A INPUT -i lo -j ACCEPT

# 第三步:放行SSH(管理用)
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# 第四步:放行HTTP和HTTPS(Web服务)
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 第五步:允许ping(可选,用于网络诊断)
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

# 第六步:设置默认策略为DROP
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# 保存规则(CentOS 7)
iptables-save > /etc/sysconfig/iptables

3.4 状态防火墙(state模块)

问题: 我允许了别人访问我的80端口,那服务器返回的响应数据包不就被OUTPUT链的默认DROP策略拦截了吗?

解答: 这就是 状态防火墙 的精妙之处。它能"记住"连接的状态,自动放行已建立连接的响应包。

四种连接状态:

状态含义举例
NEW新连接的第一个包客户端发来的SYN
ESTABLISHED已建立的连接三次握手后的所有数据包
RELATED与已建立连接相关的新连接FTP数据连接
INVALID无法识别的异常包损坏的数据包
# 状态防火墙的标准写法(必学!)
# 放行所有已建立连接和相关连接的数据包
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 只放行新的SSH连接请求
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j ACCEPT

# 只放行新的HTTP请求
iptables -A INPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT

3.5 高级匹配模块

# === IP地址范围匹配 ===
iptables -A INPUT -m iprange --src-range 192.168.1.10-192.168.1.50 -j DROP

# === MAC地址匹配 ===
iptables -A INPUT -m mac --mac-source 00:0C:29:AA:7A:ED -j DROP

# === 多端口匹配 ===
iptables -A INPUT -p tcp -m multiport --dports 22,80,443,8080 -j ACCEPT

# === 连接数限制(防止SSH暴力破解) ===
iptables -A INPUT -p tcp --dport 22 -m connlimit --connlimit-above 3 -j REJECT

# === 速率限制(防止ping flood攻击) ===
iptables -A INPUT -p icmp -m limit --limit 1/second --limit-burst 4 -j ACCEPT
iptables -A INPUT -p icmp -j DROP

# === SYN Flood防护 ===
iptables -A INPUT -p tcp --syn -m limit --limit 50/second -j ACCEPT
iptables -A INPUT -p tcp --syn -j DROP

3.6 NAT地址转换

类比: NAT就像公司前台。外人只能看到公司总机号码(公网IP),当你打电话出去时,前台帮你转接(SNAT);当外面有人打总机找某个部门时,前台帮你转接到对应分机(DNAT)。

SNAT -- 让内网机器上网

# 场景: 内网192.168.1.0/24 通过 NAT服务器(公网IP: 1.1.1.1)上网

# 第一步:开启路由转发
echo 1 > /proc/sys/net/ipv4/ip_forward
# 永久生效: 在 /etc/sysctl.conf 中添加 net.ipv4.ip_forward = 1

# 第二步:配置SNAT
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j SNAT --to-source 1.1.1.1

# 如果公网IP是动态的(如PPPoE拨号),使用MASQUERADE
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth1 -j MASQUERADE

DNAT -- 端口转发(将外网流量转给内网服务器)

# 场景: 外网用户访问 1.1.1.1:80 → 转发给内网的Web服务器 192.168.1.100:80
iptables -t nat -A PREROUTING -i eth1 -d 1.1.1.1 -p tcp --dport 80 \
    -j DNAT --to-destination 192.168.1.100:80

# 端口映射: 外网8080端口 → 内网服务器的80端口
iptables -t nat -A PREROUTING -p tcp --dport 8080 \
    -j DNAT --to-destination 192.168.1.100:80

动手实验: 在两台虚拟机之间配置iptables规则,实现:

  1. 禁止同桌ping你的机器
  2. 但允许你ping同桌的机器

提示: 使用 -m icmp --icmp-type echo-request 和 --icmp-type echo-reply 分别控制请求和响应。


4. firewalld防火墙 -- 新一代智能门禁

生活中的类比

如果iptables是保安拿着纸质名单逐条核对,那 firewalld 就是 智能门禁系统——

  • 你可以根据不同场景切换 安全区域(在公司用办公规则,回家用家庭规则)
  • 修改规则后 立即生效,不需要重启整个系统(不会断开现有连接)
  • 支持 富规则(rich rules),用更接近自然语言的方式写规则

4.1 firewalld vs iptables

对比项iptablesfirewalld
规则变更需要reload所有规则,断开现有连接增量更新,不影响现有连接
配置方式命令行直接操作区域(Zone)+ 服务(Service)
默认工具iptables命令firewall-cmd / firewall-config
底层引擎直接操作netfilter仍然是netfilter(firewalld是前端控制器)
适用系统CentOS 6及以前CentOS 7/8, Fedora, RHEL

重要理解: firewalld的底层仍然是iptables/netfilter,它只是一个更友好的 前端管理器。两者不能同时使用,需要选一个。

4.2 区域(Zone)概念

firewalld引入了 区域 的概念,每个区域代表不同的信任级别。

┌──────────────────────────────────────────────────┐
│           firewalld 区域模型                      │
│                                                   │
│  ┌─────────┐  ┌──────────┐  ┌─────────────────┐  │
│  │  public  │  │ internal │  │    trusted      │  │
│  │ (公共区) │  │ (内部区)  │  │  (完全信任区)   │  │
│  │ 默认拒绝 │  │ 允许部分 │  │  全部放行        │  │
│  └─────────┘  └──────────┘  └─────────────────┘  │
│                                                   │
│  ┌─────────┐  ┌──────────┐  ┌─────────────────┐  │
│  │  home    │  │  work    │  │     dmz         │  │
│  │ (家庭区) │  │ (工作区)  │  │  (隔离区)       │  │
│  │ 允许部分 │  │ 允许部分 │  │  仅允许指定服务  │  │
│  └─────────┘  └──────────┘  └─────────────────┘  │
│                                                   │
│  ┌─────────┐  ┌──────────┐  ┌─────────────────┐  │
│  │external │  │  block   │  │     drop        │  │
│  │(外部区) │  │ (阻止区) │  │   (丢弃区)       │  │
│  │ 含NAT   │  │ 全部拒绝 │  │  静默丢弃        │  │
│  └─────────┘  └──────────┘  └─────────────────┘  │
└──────────────────────────────────────────────────┘
区域信任级别典型用途
trusted完全信任测试环境、内部可信网络
home较信任家庭网络
internal较信任公司内部网络
work较信任办公网络
public不信任(默认)互联网、公共WiFi
external不信任路由器外网接口(含NAT伪装)
dmz不信任DMZ区域(对外服务器)
block拒绝拒绝一切,返回icmp错误
drop丢弃静默丢弃一切,不回应

4.3 firewalld常用命令

# ===== 基础信息 =====
systemctl status firewalld               # 查看状态
firewall-cmd --state                     # 是否运行中
firewall-cmd --get-default-zone          # 查看默认区域
firewall-cmd --get-active-zones          # 查看活跃区域及绑定的网卡

# ===== 服务管理 =====
# 查看当前区域已开放的服务
firewall-cmd --list-services

# 添加HTTP服务(临时生效,重启丢失)
firewall-cmd --add-service=http

# 永久添加HTTP和HTTPS服务
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https

# 添加端口
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --permanent --add-port=3306/tcp

# 移除服务
firewall-cmd --permanent --remove-service=telnet

# 重新加载配置(永久规则生效)
firewall-cmd --reload

4.4 富规则(Rich Rules)

问题: 我需要更精细的控制——比如只允许特定IP段访问MySQL端口,firewalld的基本命令做不到。

解答: 使用 富规则(Rich Rules),语法更接近自然语言。

# 只允许192.168.1.0/24网段访问3306端口
firewall-cmd --permanent --add-rich-rule \
  'rule family="ipv4" source address="192.168.1.0/24" port port="3306" protocol="tcp" accept'

# 拒绝某个IP的所有访问
firewall-cmd --permanent --add-rich-rule \
  'rule family="ipv4" source address="10.0.0.100" drop'

# 限制SSH连接速率(每分钟最多3个新连接)
firewall-cmd --permanent --add-rich-rule \
  'rule family="ipv4" service name="ssh" limit value="3/m" accept'

# 查看已配置的富规则
firewall-cmd --list-rich-rules

# 删除富规则
firewall-cmd --permanent --remove-rich-rule \
  'rule family="ipv4" source address="10.0.0.100" drop'

4.5 实战:Web服务器防火墙配置

# 完整配置流程
# 1. 设置默认区域为public
firewall-cmd --set-default-zone=public

# 2. 允许SSH管理
firewall-cmd --permanent --add-service=ssh

# 3. 允许Web服务
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https

# 4. 允许ICMP(ping)
# firewalld默认已允许ping,如被禁用可重新启用
firewall-cmd --permanent --remove-icmp-block=echo-request

# 5. 只允许特定IP段访问管理端口(富规则)
firewall-cmd --permanent --add-rich-rule \
  'rule family="ipv4" source address="10.0.0.0/8" port port="22" protocol="tcp" accept'

# 6. 生效配置
firewall-cmd --reload

# 7. 验证
firewall-cmd --list-all

课堂讨论: 如果你的学校机房有一台Web服务器,既要让全校学生访问网站,又要限制只有管理员的IP段可以SSH登录,你会怎么配置防火墙?


5. VPN虚拟专用通道 -- 公网中的秘密隧道

生活中的类比

想象你在一条 繁忙的高速公路(互联网)上开车。所有人都能看到你的车牌号和你走哪条路。

VPN 就像在高速公路上建了一条 只有你知道入口的密封隧道。你的车进入隧道后,外面的人既看不到你走了哪条路,也看不到你车上装了什么。

技术上说:VPN在公共网络上创建一条 加密隧道,你的所有数据都通过这条隧道传输,外面的人即使截获了数据包,也无法解密。

5.1 为什么需要VPN?

场景问题VPN解决方案
远程办公员工在家需要访问公司内部服务器通过VPN连接到公司内网
分支机构互联北京和上海办公室需要互通两端建立VPN隧道
公共WiFi安全咖啡厅WiFi可能被窃听VPN加密所有流量
隐私保护ISP可能记录上网行为流量通过VPN中转

5.2 OpenVPN基本原理

OpenVPN 是Linux下最流行的开源VPN方案,核心技术是:

  1. 虚拟网卡: 在系统中创建一个虚拟的网络接口
  2. SSL/TLS加密: 使用OpenSSL库加密数据与控制信息
  3. 隧道模式: TUN(三层IP隧道)或 TAP(二层以太网桥接)
┌─────────────────────────────────────────────────┐
│           OpenVPN 工作原理                       │
│                                                  │
│  你的电脑                   VPN服务器             │
│  ┌─────┐    加密隧道       ┌─────────┐           │
│  │应用层│ ═══════════════ →│ 解密    │→ 内网资源  │
│  │数据  │    (SSL/TLS)     │ 转发    │           │
│  └─────┘                   └─────────┘           │
│                                                  │
│  默认端口: 1194/UDP                              │
│  加密算法: AES, Blowfish, 3DES等                 │
│  压缩: LZO算法                                   │
│  认证方式: 证书 / 预共享密钥 / 用户名密码         │
└─────────────────────────────────────────────────┘

5.3 OpenVPN服务端部署(证书认证方式)

# ===== 第一步:安装软件 =====
yum install -y epel-release
yum install -y openvpn easy-rsa

# ===== 第二步:初始化PKI证书体系 =====
cd /usr/share/easy-rsa/3.0.3/
./easyrsa init-pki                    # 初始化PKI目录

# ===== 第三步:创建CA证书(证书颁发机构) =====
./easyrsa build-ca                    # 按提示设置CA密码

# ===== 第四步:生成服务端证书和密钥 =====
./easyrsa build-server-full vpnserver # 生成服务端证书

# ===== 第五步:生成客户端证书 =====
./easyrsa build-client-full client1   # 为客户端1生成证书

# ===== 第六步:生成DH参数(密钥交换用) =====
./easyrsa gen-dh

# ===== 第七步:复制证书到OpenVPN配置目录 =====
cp pki/ca.crt pki/private/vpnserver.key pki/issued/vpnserver.crt /etc/openvpn/
cp pki/dh.pem /etc/openvpn/

# ===== 第八步:编辑服务端配置 =====
cp /usr/share/doc/openvpn-*/sample/sample-config-files/server.conf /etc/openvpn/server.conf

服务端配置文件关键参数:

# /etc/openvpn/server.conf 关键配置
local 0.0.0.0               # 监听所有网卡(或指定公网IP)
port 1194                    # VPN端口
proto udp                    # 使用UDP协议(延迟高时改TCP)
dev tun                      # TUN模式(三层路由)

ca ca.crt                    # CA证书
cert vpnserver.crt           # 服务端证书
key vpnserver.key            # 服务端私钥
dh dh.pem                    # DH参数

server 10.8.0.0 255.255.255.0  # VPN内网网段

push "route 192.168.1.0 255.255.255.0"  # 推送内网路由给客户端

keepalive 10 120             # 心跳检测:每10秒ping,120秒无响应认为断开
comp-lzo                     # 启用LZO压缩
max-clients 100              # 最大客户端数

user nobody                  # 降权运行(安全!)
group nobody

persist-key                  # 重启时保留密钥
persist-tun                  # 重启时保留隧道
# ===== 第九步:启动服务 =====
# 如果CA有密码,去掉私钥密码
openssl rsa -in /etc/openvpn/vpnserver.key -out /etc/openvpn/vpnserver.key

systemctl start openvpn@server
systemctl enable openvpn@server

# ===== 第十步:开启NAT转发(让VPN客户端能访问内网) =====
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -j MASQUERADE

5.4 OpenVPN客户端配置

# 客户端配置文件 /etc/openvpn/client.conf
client
dev tun
proto udp
remote vpn.example.com 1194       # VPN服务器地址
nobind

ca ca.crt
cert client1.crt
key client1.key

comp-lzo
persist-key
persist-tun
verb 3
# 启动客户端
openvpn --config /etc/openvpn/client.conf --daemon

# 验证连接
ip addr show tun0                  # 应该看到10.8.0.x的虚拟IP
ping 10.8.0.1                      # ping VPN服务器内网地址

5.5 TUN vs TAP模式选择

模式工作层级特点适用场景
TUN三层(IP层)只处理IP包,效率高远程办公、上网
TAP二层(以太网层)处理以太网帧,支持广播网桥、游戏局域网

建议: 大多数场景下使用 TUN 模式,除非你需要传输非IP协议(如NetBIOS广播)。


6. 中间人攻击 -- 当心有人偷听你的对话

生活中的类比

你和朋友通过 信件 通信。正常情况下:你 → 邮局 → 朋友。

中间人攻击(MITM): 有个骗子冒充邮局工作人员,他拆开你的信看了一遍,然后重新封好送给你的朋友。你的朋友收到的信看起来完好无损,但内容已经被偷看了。更坏的情况是,骗子可能 篡改 了信的内容。

在网络世界中,ARP欺骗就是一种典型的中间人攻击手段。

6.1 中间人攻击的三种手段

┌──────────────────────────────────────────────────────────┐
│                 网络通信的三大威胁                         │
│                                                           │
│  1. 窃听 (Eavesdropping)                                  │
│     A ←────────────────────→ B                           │
│              ↑ 偷看                                      │
│              C                                           │
│     对策: 加密 (Encryption)                               │
│                                                           │
│  2. 篡改 (Tampering)                                      │
│     A ←────→ C(修改内容)←────→ B                         │
│     对策: 哈希校验 (Hash / HMAC)                          │
│                                                           │
│  3. 伪装 (Impersonation)                                  │
│     A ←────→ C(冒充B)                                    │
│     对策: 数字证书 + CA认证 (Certificate)                 │
│                                                           │
└──────────────────────────────────────────────────────────┘

6.2 ARP欺骗原理与防范

问题: ARP协议有个设计缺陷——它 无条件信任 收到的ARP应答,即使你没有发出请求。攻击者利用这个缺陷,向你发送伪造的ARP应答。

攻击过程:

正常情况:
  A的ARP缓存: 192.168.1.1 (网关) → AA:BB:CC:DD:EE:FF (网关MAC)

攻击者C发送伪造ARP应答:
  "我是192.168.1.1,我的MAC是 11:22:33:44:55:66"

被攻击后A的ARP缓存:
  192.168.1.1 (网关) → 11:22:33:44:55:66 (攻击者C的MAC!)

结果: A发往网关的数据全部被C截获

防范措施:

# 方法1: 静态ARP绑定(简单有效)
# 将网关的IP和MAC永久绑定,不再接受动态更新
arp -s 192.168.1.1 AA:BB:CC:DD:EE:FF

# 方法2: 使用ARP防护工具
# 安装arpon等工具,持续监控ARP表变化
yum install -y arpon

# 方法3: 交换机端口安全(企业级方案)
# 在交换机上配置端口安全策略,阻止伪造ARP

6.3 加密技术 -- 防窃听

对称加密(一把钥匙)

类比: 你和朋友约定一个暗号(密钥),用这个暗号加密和解密信件。问题是——暗号怎么安全地告诉对方?

# 使用openssl进行对称加密(DES算法)
openssl enc -e -des -in /etc/passwd -out /tmp/passwd.des
# 输入加密密码

# 解密
openssl enc -d -des -in /tmp/passwd.des -out /tmp/passwd.dec

常见对称加密算法:DES(已过时)、3DES、AES(目前推荐)。

非对称加密(公钥+私钥)

类比: 你做一个特殊的 信箱——任何人都可以往里投信(用公钥加密),但只有你有钥匙打开信箱取出信(用私钥解密)。

# 使用GPG(GNU Privacy Guard)生成密钥对

# 第一步:生成密钥对
gpg --gen-key
# 按提示输入姓名、邮箱,选择RSA算法和2048位密钥长度

# 第二步:查看密钥
gpg --list-keys           # 查看公钥
gpg --list-secret-keys    # 查看私钥

# 第三步:导出公钥给朋友
gpg --export -armor yourname > /tmp/yourname.pub

# 第四步:朋友导入你的公钥
gpg --import < yourname.pub

# 第五步:朋友用你的公钥加密文件
gpg --encrypt --armor --recipient yourname secret.txt

# 第六步:你用自己的私钥解密
gpg --decrypt secret.txt.asc > secret_decrypted.txt

6.4 哈希校验 -- 防篡改

类比: 你在信末尾附一个 指纹(哈希值)。对方收到信后也计算一下指纹,如果两个指纹一致,说明信没被动过手脚。

哈希函数的三个特性:

  1. 确定性: 相同输入 → 相同输出(永远不变)
  2. 固定长度: 不管输入多长,输出长度固定
  3. 不可逆: 无法从哈希值反推原始内容
# 计算文件的MD5哈希值
md5sum /etc/passwd
# 输出: bffc5857b2cf07ed48dd2a7535f11a31  /etc/passwd

# 计算SHA256哈希值(更安全)
sha256sum /etc/passwd

# 下载文件后验证完整性
# 1. 从官网获取文件的官方SHA256值
# 2. 下载后自己计算SHA256值
# 3. 两者一致 = 文件没有被篡改

6.5 SSL/TLS与HTTPS -- 综合防护

问题: 对称加密快但密钥分发困难,非对称加密安全但速度慢。怎么兼顾?

解答: HTTPS = HTTP + SSL/TLS,它巧妙地结合了对称加密和非对称加密:

HTTPS 握手过程(简化版):

1. 客户端发起连接 → 服务器出示"身份证"(数字证书)
2. 客户端向CA机构核实证书真伪
3. 客户端生成一个随机密码(对称密钥),用服务器的公钥加密后发送
4. 服务器用私钥解密,得到对称密钥
5. 此后双方用这个对称密钥加密所有通信数据

总结: 非对称加密用来安全地交换密钥,对称加密用来高效地传输数据

动手实验: 使用 openssl 创建自签名证书,配置Apache启用HTTPS:

# 生成自签名证书
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
  -keyout /etc/httpd/ssl/server.key \
  -out /etc/httpd/ssl/server.crt \
  -subj "/CN=www.example.com"

# 在Apache SSL配置中指定证书路径
# SSLCertificateFile /etc/httpd/ssl/server.crt
# SSLCertificateKeyFile /etc/httpd/ssl/server.key

7. sudo权限管理 -- 不是所有钥匙都要交给一个人

生活中的类比

想象你是一个大楼的物业经理(root)。

  • su命令: 相当于把你的 万能钥匙 交给别人——他拿到后可以开任何门。缺点是他必须知道你的密码。
  • sudo命令: 相当于给每个员工一张 门禁卡,只能开指定的门。你不需要告诉他万能钥匙的密码,而且你可以随时收回他的门禁卡。

sudo的核心思想:分权管理,最小权限原则。

7.1 su vs sudo

对比项susudo
切换方式输入 root密码输入 自己的密码
权限范围完全获得root权限只获得被授权的权限
安全性低(需共享root密码)高(无需共享root密码)
审计追踪无法追踪谁在使用有日志记录每次使用
推荐度不推荐日常使用推荐

7.2 配置sudo权限

问题: 如何让普通用户执行特定的管理命令,而无需root密码?

解答: 编辑 /etc/sudoers 文件,推荐使用 visudo 命令(它会进行语法检查,防止写错导致系统无法使用sudo)。

# 编辑sudoers文件(推荐方式,带语法检查)
visudo

# 或者直接编辑(不推荐,没有语法检查)
vim /etc/sudoers

sudoers规则语法

# 格式: 用户  主机=(以谁的身份运行)  可执行的命令
# user  MACHINE=(RUNAS_USER) COMMANDS

# 示例1: 让robin可以在任何主机上以任何身份运行任何命令
robin ALL=(ALL) ALL

# 示例2: 让zorro可以执行网络和磁盘管理命令,且不需要密码
zorro ALL=(ALL) NOPASSWD: /sbin/ip, /sbin/fdisk

# 示例3: 让robin只能执行ip和fdisk命令
robin ALL=(ALL) /sbin/ip, /sbin/fdisk

# 示例4: 禁止执行某个命令(在命令前加!)
zorro ALL=(ALL) /usr/bin/passwd [a-zA-Z]*, !/usr/bin/passwd root
# 解释: zorro可以改普通用户的密码,但不能改root的密码

7.3 使用命令别名 -- 批量管理

当规则很多时,可以使用 别名(Alias) 来简化配置:

# ===== 在sudoers文件中定义别名 =====

# 命令别名: 把一组相关命令打包成一个别名
Cmnd_Alias NETWORKING = /sbin/route, /sbin/ifconfig, /bin/ping, \
    /sbin/dhclient, /sbin/iptables, /sbin/iwconfig, /sbin/mii-tool

Cmnd_Alias STORAGE = /sbin/fdisk, /sbin/sfdisk, /sbin/parted, \
    /sbin/partprobe, /bin/mount, /bin/umount

Cmnd_Alias SERVICES = /sbin/service, /sbin/chkconfig, \
    /usr/bin/systemctl start, /usr/bin/systemctl stop, \
    /usr/bin/systemctl restart, /usr/bin/systemctl status, \
    /usr/bin/systemctl enable, /usr/bin/systemctl disable

Cmnd_Alias USER = /usr/sbin/useradd, /usr/sbin/usermod, /usr/sbin/userdel, \
    /usr/bin/passwd [a-zA-Z0-9]*, !/usr/bin/passwd root

Cmnd_Alias GROUP = /usr/sbin/groupadd, /usr/sbin/groupmod, /usr/sbin/groupdel

Cmnd_Alias SOFTWARE = /bin/rpm, /usr/bin/yum, /usr/bin/dnf

# 用户别名: 把一组用户打包
User_Alias ADMINS = tom, jerry
User_Alias OPERATORS = alice, bob

# ===== 使用别名分配权限 =====
# 管理员可以管理网络、软件和服务
ADMINS ALL=(ALL) NETWORKING, SOFTWARE, SERVICES

# 运维人员可以管理用户、组和存储
OPERATORS ALL=(ALL) USER, GROUP, STORAGE

# 按组授权(%表示组名)
%developers ALL=(ALL) NOPASSWD: SERVICES

7.4 sudo安全最佳实践

# ===== 实用命令 =====

# 查看当前用户的sudo权限
sudo -l

# 以root身份执行命令
sudo /usr/sbin/useradd newuser

# 以其他用户身份执行命令
sudo -u apache /usr/bin/systemctl restart httpd

# 切换到root shell(需输入自己的密码)
sudo -i
sudo su -

# 查看sudo日志(审计谁在什么时候执行了什么命令)
tail -f /var/log/secure | grep sudo

# 强制要求输入密码(清除sudo缓存的密码)
sudo -k

安全建议清单:

  1. 最小权限原则: 只授权用户需要的具体命令,不要用 ALL
  2. 使用visudo: 永远用 visudo 编辑,避免语法错误
  3. 慎用NOPASSWD: 只在自动化脚本等场景使用,正常情况下应要求输入密码
  4. 禁止危险操作: 使用 ! 排除危险命令(如 !/usr/bin/passwd root)
  5. 定期审计: 检查 /var/log/secure 中的sudo使用记录
  6. 避免ALL=(ALL) ALL: 除非真的需要完全root权限

课堂练习: 某学校服务器需要让张老师能管理用户(增删改用户、修改普通用户密码但不能改root密码),让李老师能管理网络和服务。请写出对应的sudoers配置。


8. SELinux -- 给系统穿上防弹衣

生活中的类比

假设你住在一栋安保严格的大楼里。

  • 传统Linux权限(DAC): 就像你自己家——你是房主,想给谁钥匙就给谁。问题是你可能不小心给了坏人钥匙。
  • SELinux(MAC): 就像大楼有一套 中央安保系统——即使你是房主,你也只能在安保系统允许的范围内行事。每个房间、每个人、每把钥匙都有标签(安全上下文),只有标签匹配才能访问。

即使黑客获得了root权限,如果SELinux策略不允许,他依然无法访问某些文件。

8.1 DAC vs MAC -- 两种安全模型

对比项DAC(自主访问控制)MAC(强制访问控制)
代表传统Linux文件权限 (rwx)SELinux
权限决定者文件所有者系统策略(管理员不能随意更改)
灵活性高(所有者随意授权)低(由策略统一控制)
安全性较低(root可以为所欲为)高(即使root也受策略约束)
SUID风险有(SUID程序漏洞可被利用)低(进程权限被严格限制)

8.2 SELinux三种运行模式

# 查看当前模式
getenforce
# 输出: Enforcing / Permissive / Disabled

# 查看详细状态
sestatus

# 临时切换模式(Enforcing ↔ Permissive)
setenforce 0       # 切换到 Permissive(宽容模式:记录违规但不阻止)
setenforce 1       # 切换到 Enforcing(强制模式:阻止并记录)
模式行为适用场景
Enforcing严格执行策略,阻止违规访问生产环境
Permissive记录违规但不阻止(相当于审计模式)调试排错
Disabled完全关闭SELinux不推荐(除非兼容性问题)
# 永久修改模式(需要重启)
vim /etc/selinux/config
# SELINUX=enforcing     # 改为 enforcing / permissive / disabled

强烈建议: 不要关闭SELinux!如果遇到权限问题,先切到Permissive模式排查,而不是直接Disabled。

8.3 安全上下文(Security Context)

SELinux给每个文件、进程、端口都打上了 安全上下文标签。访问控制基于标签之间的匹配。

安全上下文格式: 用户:角色:类型:敏感度

示例:
  system_u:object_r:httpd_sys_content_t:s0
  ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ ^^
  用户      角色       类型(最重要!)        敏感度级别
组成部分说明常见值
UserSELinux用户身份system_u, user_u, unconfined_u
Role角色object_r(文件), system_r(进程)
Type类型(核心!)httpd_sys_content_t, etc_t, var_log_t
Sensitivity敏感度s0(默认,Target策略)

关键点: SELinux的 类型强制(Type Enforcement) 是最核心的机制。规则可以简化为:
进程类型 能访问 文件类型,当且仅当策略中有明确的允许规则。

# 查看文件的安全上下文
ls -Z /var/www/html/
# 输出: system_u:object_r:httpd_sys_content_t:s0 index.html

# 查看进程的安全上下文
ps auxZ | grep httpd
# 输出: system_u:system_r:httpd_t:s0  1234 ?  00:00:00 httpd

# 查看端口的安全上下文
semanage port -l | grep http

8.4 修改文件安全上下文

问题: 我把网站文件放在了非默认目录 /web2 下,Apache报权限错误。

解答: Apache进程的类型是 httpd_t,它只能访问 httpd_sys_content_t 类型的文件。新目录的类型默认不是这个,需要手动修改。

# ===== 方法一:chcon(临时修改,不持久) =====

# 直接指定类型
chcon -R -t httpd_sys_content_t /web2

# 参考已有目录的类型
chcon -R --reference /var/www/html /web2

# ===== 方法二:semanage fcontext(推荐,持久化) =====

# 第一步:安装semanage工具
yum install -y policycoreutils-python

# 第二步:为目录添加默认文件上下文规则
semanage fcontext -a -t httpd_sys_content_t '/web2(/.*)?'
# 解释: '/web2(/.*)?' 是正则表达式,匹配/web2及其所有子文件

# 第三步:应用规则(恢复/设置文件的实际上下文)
restorecon -Rv /web2

# 验证
ls -Zd /web2
ls -Z /web2/

cp和mv对上下文的影响

# cp(复制):文件继承目标目录的上下文
cp /tmp/file1 /var/www/html/
# file1 获得 httpd_sys_content_t(正确!)

# mv(移动):文件保留原来的上下文!
mv /tmp/file2 /var/www/html/
# file2 仍然是 tmp_t(Apache无法访问!)

# 解决:移动后手动恢复上下文
restorecon -Rv /var/www/html/

8.5 SELinux布尔值 -- 策略开关

SELinux布尔值就像是策略的 开关,可以在不修改策略文件的情况下调整行为。

# 查看所有与httpd相关的布尔值
getsebool -a | grep httpd

# 查看特定布尔值
getsebool httpd_enable_homedirs

# 修改布尔值(临时)
setsebool httpd_enable_homedirs on

# 修改布尔值(永久,-P写入策略文件)
setsebool -P httpd_enable_homedirs on

# 或使用semanage查看(含持久性信息)
semanage boolean -l | grep httpd_enable_homedirs

常用布尔值:

布尔值作用
httpd_enable_homedirs允许Apache访问用户家目录
httpd_can_network_connect允许Apache发起网络连接
httpd_can_sendmail允许Apache发送邮件
ftp_home_dir允许FTP访问用户家目录
nis_enabled允许NIS服务

8.6 SELinux端口管理

问题: 我把Apache的监听端口改为8888,启动失败:Permission denied。

解答: SELinux限制了httpd进程只能绑定特定的端口。需要把新端口加入允许列表。

# 查看httpd允许的端口
semanage port -l | grep http_port_t
# 输出: http_port_t  tcp  80, 443, 488, 8008, 8009, 8443

# 添加8888端口到httpd允许列表
semanage port -a -t http_port_t -p tcp 8888

# 验证
semanage port -l | grep http_port_t
# 输出: http_port_t  tcp  8888, 80, 443, 488, 8008, 8009, 8443

# 现在可以正常启动Apache了
systemctl start httpd

8.7 SELinux故障排查流程

┌───────────────────────────────────────────────────┐
│           SELinux 故障排查四步法                    │
│                                                    │
│  1. 确认是否是SELinux导致的问题                     │
│     setenforce 0   ← 临时切到Permissive           │
│     如果问题解决 → 确认是SELinux的问题              │
│     setenforce 1   ← 切回Enforcing继续排查         │
│                                                    │
│  2. 安装排错工具                                    │
│     yum install -y setroubleshoot-server           │
│     systemctl restart rsyslog                      │
│     systemctl restart auditd                       │
│                                                    │
│  3. 查看日志                                        │
│     grep "avc: denied" /var/log/audit/audit.log    │
│     tail -f /var/log/messages | grep setroubleshoot│
│                                                    │
│  4. 根据日志修复                                    │
│     - 文件上下文不对 → restorecon / chcon / semanage│
│     - 端口不对 → semanage port                     │
│     - 需要开启布尔值 → setsebool -P                │
│                                                    │
└───────────────────────────────────────────────────┘

实战排错示例:

# 场景: Apache无法访问 /virtual/index.html

# 第一步:确认问题
setenforce 0
curl http://localhost/virtual/index.html    # 能访问 → SELinux问题
setenforce 1

# 第二步:查看当前上下文
ls -Zd /virtual
# 输出: unconfined_u:object_r:default_t:s0  ← 类型是default_t,不是httpd能访问的

# 第三步:修复
semanage fcontext -a -t httpd_sys_content_t '/virtual(/.*)?'
restorecon -Rv /virtual

# 第四步:验证
ls -Zd /virtual
# 输出: system_u:object_r:httpd_sys_content_t:s0  ← 正确!
curl http://localhost/virtual/index.html    # 能访问了

排错神器: man -k selinux | grep http 可以查看与Apache相关的SELinux帮助文档。


综合实验:构建安全的网络服务器

实验目标

在一台CentOS虚拟机上完成以下配置,综合运用本章所学知识:

序号任务涉及知识点
1配置静态IP地址,划分子网IP地址、ip命令
2配置firewalld,只开放SSH/HTTP/HTTPSfirewalld、区域、服务
3部署Apache Web服务,使用自定义目录SELinux上下文、semanage
4配置sudo,让webadmin用户只能管理httpd服务sudoers、visudo
5抓包分析一次HTTP请求的完整过程TCP/IP、tcpdump
6配置OpenVPN,实现远程安全访问VPN、证书、加密

实验参考步骤

# 任务1: 配置IP
ip addr add 192.168.1.100/24 dev eth0
ip route add default via 192.168.1.1

# 任务2: 配置firewalld
systemctl start firewalld
firewall-cmd --permanent --add-service=ssh
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload

# 任务3: 部署Apache + SELinux
yum install -y httpd
mkdir -p /myweb
echo "<h1>Hello World</h1>" > /myweb/index.html
semanage fcontext -a -t httpd_sys_content_t '/myweb(/.*)?'
restorecon -Rv /myweb
# 编辑/etc/httpd/conf/httpd.conf,设置DocumentRoot "/myweb"
systemctl start httpd

# 任务4: 配置sudo
visudo
# 添加: webadmin ALL=(ALL) /usr/bin/systemctl * httpd

# 任务5: 抓包分析
tcpdump -i eth0 -nn -S -w /tmp/http_capture.pcap port 80
# 另一台机器: curl http://192.168.1.100
# 用Wireshark打开/tmp/http_capture.pcap分析

附录:常用命令速查表

网络诊断

ip addr show              # 查看IP地址
ip route show             # 查看路由表
ip neigh show             # 查看ARP缓存
ss -tunlp                 # 查看端口监听
ping -c 4 目标IP          # 测试连通性
traceroute 目标IP         # 追踪路由路径
nslookup 域名             # DNS解析
dig 域名                  # 详细DNS查询
netstat -rn               # 查看路由表

防火墙

# iptables
iptables -L -n -v --line-numbers
iptables -t nat -L -n -v
iptables-save > /etc/sysconfig/iptables

# firewalld
firewall-cmd --list-all
firewall-cmd --permanent --add-service=http
firewall-cmd --reload

SELinux

getenforce                # 查看模式
sestatus                  # 详细状态
ls -Z 文件                # 查看文件上下文
ps auxZ                   # 查看进程上下文
restorecon -Rv 目录       # 恢复默认上下文
semanage fcontext -l      # 查看文件上下文规则
semanage port -l          # 查看端口上下文
getsebool -a              # 查看所有布尔值

安全加固

# SSH加固(/etc/ssh/sshd_config)
PermitRootLogin no        # 禁止root直接登录
PasswordAuthentication no # 禁止密码登录,使用密钥
Port 2222                 # 修改默认端口

# 系统更新
yum update -y             # 更新所有软件包

# 检查可疑登录
last                      # 查看登录历史
lastb                     # 查看失败的登录尝试

术语表

术语英文解释
IP地址IP Address网络中设备的唯一标识
子网掩码Subnet Mask区分IP中网络号和主机号的掩码
CIDRClassless Inter-Domain Routing无类别域间路由,如/24
NATNetwork Address Translation网络地址转换
TCPTransmission Control Protocol传输控制协议(可靠)
UDPUser Datagram Protocol用户数据报协议(不可靠)
ARPAddress Resolution Protocol地址解析协议(IP→MAC)
ICMPInternet Control Message Protocol互联网控制报文协议
DNSDomain Name System域名系统
VPNVirtual Private Network虚拟专用网络
MITMMan In The Middle中间人攻击
SSL/TLSSecure Sockets Layer / Transport Layer Security安全传输协议
MACMandatory Access Control强制访问控制
DACDiscretionary Access Control自主访问控制
MTUMaximum Transmission Unit最大传输单元(默认1500字节)
TTLTime To Live生存时间(跳数限制)
MSSMaximum Segment Size最大报文段长度

寄语: 网络安全和服务器管理是一门实践性很强的学科。理论只是基础,真正的能力来自于大量的动手练习。建议在实际操作中加深理解。遇到SELinux报错不要怕——把它当成解谜游戏,每一步排查都会让你对Linux的理解更深一层。

默认分类
网络 安全
License:  CC BY 4.0
Share

Further Reading

Jul 4, 2026

Nginx与Tomcat

Nginx 与 Tomcat 完全指南 目录 第一部分:Nginx 篇 1. Nginx 介绍 -- 你的网站为什么需要一位"前台接待员"?

Jul 4, 2026

网络协议与安全

网络协议与安全 -- 从入门到实战 目录 IP地址 -- 网络世界的门牌号 TCP/IP协议 -- 数据快递的工作流程 iptables防火墙

Jul 4, 2026

数据库与自动化运维

第四篇:数据库与自动化运维 本篇从"为什么需要数据库"这个根本问题出发,逐步带你掌握 MySQL 关系型数据库、Redis 内存数据库,以及自动化运维的核心技能。每一个知识点都遵循"遇到问题 -> 分析原因 -> 动手解决"的思路。 目录 第一部分:MySQL 数据库 数据库介绍 | 2. MySQ

OLDER

Nginx与Tomcat

NEWER

数据库与自动化运维

Recently Updated

  • 监控虚拟化与集群
  • Docker与Kubernetes
  • Nginx与Tomcat
  • 网络协议与安全
  • 数据库与自动化运维

Trending Tags

安全 Linux系统 nginx 日志管理 Linux服务 网络 Linux高级 pxe 中间件 python

Contents

©2026 青青子衿的拾枝杂谈 . Some rights reserved.

Using the Halo theme Chirpy