Linux权限体系是系统管理工作的基石。无论是维护单台服务器还是管理大型集群,由权限配置不当引发的故障都占据了相当大的比例。本文将从一线运维工程师的视角出发,系统地拆解Linux权限模型的核心概念、常见应用场景、高效的排障方法以及至关重要的安全最佳实践。掌握本文内容,你将能独立解决绝大多数与权限相关的实际问题。
前置知识:本文假设你已掌握Linux的基本操作,包括文件导航、查看目录内容等基础命令。
环境说明:本文所有示例基于Rocky Linux 9.4(等同于RHEL 9.4),内核版本6.8.5,GNU Coreutils 9.1。不同发行版在细节上可能略有差异,但核心原理完全一致。
1. Linux权限体系概述
1.1 为什么运维必须精通权限管理?
权限问题是Linux系统中最常见的故障源头之一。根据实际的运维数据统计,约30%的文件访问故障、20%的服务启动失败以及15%的安全事件,都直接与不当的权限配置相关。管理不善通常会导致以下几类典型问题:
- 服务无法启动:像Nginx、Apache这类Web服务,通常以特定用户(如
www-data, nginx)身份运行。如果网站文件或目录的权限不允许该用户读取,服务启动后便会返回恼人的403错误。
- 日志无法写入:应用程序需要向日志文件写入运行信息。如果日志文件或其所在目录的权限配置不足,将导致日志写入失败,并在系统日志中产生大量错误记录。
- 备份脚本失效:自动化备份脚本常常以
root权限运行。但如果备份目标目录的权限配置异常,可能会导致备份过程不完整,甚至完全失败。
- 安全漏洞:过于宽松的权限配置(例如将文件权限设为
777)会被安全扫描工具标记为高危漏洞。在严重情况下,这可能成为攻击者入侵服务器的突破口。
1.2 Linux权限模型的基本构成
Linux采用经典的UGO(User/Group/Others)三元组权限控制模型。每个文件(在Linux中,目录也被视作一种特殊文件)都关联着三组权限位:
- Owner(所有者):文件所属的用户,由U位控制。
- Group(所属组):文件所属的用户组,由G位控制。
- Others(其他人):既不是所有者,也不属于所属组的其他所有用户,由O位控制。
每组权限包含三种基本操作权限:
- r(Read):读取权限,对应数值4。
- w(Write):写入权限,对应数值2。
- x(Execute):执行权限,对应数值1。
这种设计的巧妙之处在于,三位二进制数恰好可以表示rwx三种状态的有无。例如,rwx用数字表示就是4+2+1=7,rw-是4+2=6,而r--则是4。
2. 基本权限模型详解
2.1 查看文件权限
使用ls -l命令可以查看文件的详细权限信息:
$ ls -l /etc/passwd
-rw-r--r-- 1 root root 4096 Apr 3 10:00 /etc/passwd
$ ls -ld /tmp
drwxrwxrwt 15 root root 4096 Apr 3 10:00 /tmp
输出结果的第一列是权限字符串,共10位字符:
- rw- r-- r--
| | | |
| | | +-- Others权限
| | +------ Group权限
| +---------- Owner权限
+------------- 文件类型(-为普通文件,d为目录,l为符号链接)
权限字符串之后依次是硬链接数、所有者、所属组、文件大小、最后修改时间和文件名。
2.2 权限位数字表示法
每组权限可以用一个三位八进制数字来表示,这是最常用、最直观的权限设置方式:
| 权限字符串 |
数字表示 |
计算方式 |
| rwx |
7 |
4+2+1 |
| rw- |
6 |
4+2+0 |
| r-x |
5 |
4+0+1 |
| r-- |
4 |
4+0+0 |
| -wx |
3 |
0+2+1 |
| -w- |
2 |
0+2+0 |
| --x |
1 |
0+0+1 |
| --- |
0 |
0+0+0 |
完整的三位权限数字表示法示例如下:
# rwxrw-r-- 用数字表示就是 764
# 第1位7:所有者权限为 rwx
# 第2位6:所属组权限为 rw-
# 第3位4:其他人权限为 r--
chmod 764 /path/to/file
2.3 chmod命令详解
chmod是修改文件权限的核心命令,支持两种语法风格:
符号模式:使用u/g/o/a(代表user/group/others/all)和+/-/=操作符。
# 给所有者添加执行权限
chmod u+x script.sh
# 移除所属组和其他人的写权限
chmod go-w file.txt
# 设置所有者为rwx,所属组为rx,其他人无权限
chmod u=rwx,g=rx,o= file.conf
# 给所有人添加读权限
chmod a+r document.txt
# 同时设置多组权限
chmod u+rwx,g+rx,o+r file
数字模式:使用八进制数字直接指定完整的三组权限。
# 设置为755(rwxr-xr-x)
chmod 755 /usr/local/bin/app
# 设置为644(rw-r--r--)
chmod 644 /etc/config.conf
# 设置为600(rw-------)
chmod 600 /root/.ssh/id_rsa
# 递归设置目录内所有文件
chmod -R 644 /var/www/html/
注意:使用-R参数递归修改时,默认只修改目录下的文件本身,而不会改变目录本身的权限。如果需要同时、分别设置目录和文件的权限,可以这样做:
# 将目录设为755,文件设为644
find /var/www -type d -exec chmod 755 {} \;
find /var/www -type f -exec chmod 644 {} \;
# 或者使用GNU find的+速记和xargs命令
find /var/www -type d -print0 | xargs -0 chmod 755
find /var/www -type f -print0 | xargs -0 chmod 644
2.4 chown和chgrp命令
chown 用于更改文件的所有者:
# 更改文件所有者
chown nginx /var/www/html/index.html
# 同时更改所有者和所属组
chown nginx:nginx /var/www/html/index.html
# 只更改所属组(使用:前缀)
chown :www-data /var/www/html/index.html
# 递归更改目录下所有文件
chown -R nginx:nginx /var/www/html/
# 保持用户组不变,只更改用户
chown nginx /var/www/html/index.html
chgrp 用于仅更改文件的所属组:
# 更改文件所属组
chgrp www-data /var/www/html/index.html
# 递归更改
chgrp -R www-data /var/www/html/
2.5 默认权限与umask
当新建文件或目录时,系统会根据当前的umask值计算出它们的默认权限。普通文件的默认基础权限是666(rw-rw-rw-),目录的默认基础权限是777(rwxrwxrwx)。umask值的作用是从这些基础权限中“扣除”相应的位。
# 查看当前umask
$ umask
0022
# 计算默认权限:
# 文件:666 - 022 = 644 (rw-r--r--)
# 目录:777 - 022 = 755 (rwxr-xr-x)
常见的umask场景:
root用户默认umask为0022,因此创建的文件权限为644,目录为755。
- 普通用户默认umask通常为
0002,这使得同组(group)的其他成员拥有写权限,适用于团队协作场景。
# 修改umask(临时生效,仅影响当前shell会话)
umask 0027
# 永久修改需要编辑 ~/.bashrc 或 /etc/profile 等配置文件
echo "umask 0027" >> ~/.bashrc
source ~/.bashrc
3. 特殊权限详解
除了基本的rwx权限,Linux还提供了三种特殊权限位:SUID、SGID和Sticky Bit。它们在系统安全和服务配置中扮演着重要角色。
3.1 SUID(Set User ID)
SUID位允许一个可执行文件在运行时,使用文件所有者的权限来执行,而不是调用该文件的用户的权限。这在某些需要临时提升权限的场景下非常有用,但也因此成为了一个常见的安全风险点。
设置SUID:
# 设置SUID(符号模式)
chmod u+s /usr/bin/passwd
# 数字方式设置(最前面的4表示SUID)
chmod 4755 /usr/bin/passwd
# 查找系统中已设置SUID的文件
find /usr -perm +4000 -ls 2>/dev/null
典型应用案例:passwd命令
$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 68208 Jan 31 2026 /usr/bin/passwd
# ^
# 注意这里的`s`替代了`x`,表示SUID已设置
普通用户修改自己的密码需要写入/etc/shadow文件,但该文件对普通用户是不可写的。passwd命令设置了SUID后,普通用户执行它时会暂时获得root权限,从而能够修改shadow文件。
安全风险警示:
SUID是Linux系统中潜在危险较高的机制之一。错误地给Shell脚本设置SUID可能导致严重的安全漏洞,因为攻击者有可能通过该脚本获得一个root权限的shell。
# 高危操作示例 - 绝对不要在生产环境这样做!
chmod 4777 /bin/bash # 极度危险!
# 用于安全审计:查找系统中所有SUID文件
find / -perm +4000 -type f -exec ls -la {} \; 2>/dev/null
3.2 SGID(Set Group ID)
SGID与SUID类似,但它的作用对象是文件的所属组。它主要有两种用途:
- 在文件上设置SGID:执行时使用文件所属组的权限。
- 在目录上设置SGID:在该目录下新建的文件会自动继承该目录的所属组,这对于协作项目非常有用。
# 在目录上设置SGID
chmod g+s /shared/project
# 查看目录SGID设置
$ ls -ld /shared/project
drwxrwsr-x 2 root developers shared 4096 Apr 3 10:00 /shared/project
# 验证:新建的文件自动继承了目录的所属组
$ touch /shared/project/test.txt
$ ls -l /shared/project/test.txt
-rw-r--r-- 1 user1 developers 0 Apr 3 10:01 /shared/project/test.txt
# ^^^^^^^^^^
# 注意:文件所属组是`developers`,继承了目录的设置
数字方式设置SGID:
# 最前面的2表示SGID
chmod 2775 /shared/project
3.3 Sticky Bit(粘滞位)
Sticky Bit主要应用于共享目录。它的作用是确保目录内的文件只能被其所有者删除,即使其他用户拥有对该目录的写权限。
# 设置Sticky Bit(符号模式)
chmod +t /tmp
# 或者用数字方式(最前面的1表示Sticky Bit)
chmod 1777 /tmp
# 查看效果
$ ls -ld /tmp
drwxrwxrwt 17 root root 4096 Apr 3 10:00 /tmp
# ^
# 注意最后的`t`。小写`t`表示同时有`x`权限,大写`T`表示没有`x`权限。
/tmp目录的典型权限:
# 1777 = rwx rwx rwx + t
# 任何用户都可以在/tmp中创建文件
# 但只能删除自己创建的文件
实际验证:
# 用户A创建文件
$ su - userA
$ touch /tmp/file_a.txt
# 用户B尝试删除用户A的文件
$ su - userB
$ rm /tmp/file_a.txt
rm: cannot remove '/tmp/file_a.txt': Operation not permitted
# Sticky Bit成功起到了保护作用!
3.4 特殊权限组合示例
# 完整权限示例:rwsr-sr-x (SUID + SGID)
# 数字表示:6755
chmod 6755 /some/executable
# /tmp格式的目录:drwxrwxrwt
# 数字表示:1777
chmod 1777 /my/temp/dir
4. ACL访问控制列表
传统的UGO权限模型在复杂的权限管理场景下显得不够灵活。例如,当需要让多个特定的用户或组对同一个文件拥有不同的访问权限时,UGO模型就无能为力了。ACL(Access Control List,访问控制列表)正是为了解决这一问题而生的,它提供了更为精细的权限控制能力。
4.1 ACL查看:getfacl
# 查看文件的ACL
$ getfacl /data/reports/sales.csv
# file: sales.csv
# owner: root
# group: finance
user::rw-
user:manager:rw-
group::r--
group:analytics:r--
mask::rw-
other::r--
输出解释:
user::rw-:文件所有者(owner)的权限。
user:manager:rw-:特定用户manager的权限。
group::r--:文件所属组(group)的权限。
group:analytics:r--:特定组analytics的权限。
mask::rw-:ACL有效权限掩码(后面会详细解释)。
other::r--:其他用户(others)的权限。
4.2 ACL设置:setfacl
添加用户ACL:
# 给特定用户添加读权限
setfacl -m u:username:r /path/to/file
# 给特定用户添加读写执行权限
setfacl -m u:username:rwx /path/to/file
# 设置用户的读写权限
setfacl -m u:username:rw /path/to/file
添加组ACL:
# 给特定组添加读权限
setfacl -m g:groupname:r /path/to/file
# 给特定组添加读写权限
setfacl -m g:groupname:rw /path/to/file
设置默认ACL(针对目录):
# 设置目录的默认ACL,此后在该目录下新建的文件会自动继承此ACL
setfacl -m d:u:username:rw /shared/folder/
# 查看目录的默认ACL
getfacl /shared/folder/
删除ACL:
# 删除特定用户的ACL条目
setfacl -x u:username /path/to/file
# 删除特定组的ACL条目
setfacl -x g:groupname /path/to/file
# 删除所有扩展ACL,恢复为传统的UGO权限
setfacl -b /path/to/file
4.3 ACL掩码(mask)
ACL掩码限制了所有ACL条目的最大有效权限。mask中设置的权限,是所有非所有者ACL条目的实际上限。
# 查看mask
getfacl file | grep mask
# 设置mask(所有ACL条目都将受此限制)
setfacl -m m::rw /path/to/file
mask的作用示例:
# 如果mask是r--,那么即使你设置了u:alice:rwx,alice实际生效的权限也只有r--
# 这提供了一层安全保证,防止ACL被意外配置为过高的权限。
$ setfacl -m u:alice:rwx /shared.txt
$ setfacl -m m::r-- /shared.txt
$ getfacl /shared.txt
user:alice:rwx #effective:r--
# alice的有效权限被mask限制为了r--
4.4 ACL权限继承
通过设置目录的默认ACL,可以实现权限的自动继承,这在需要精细控制运维 & 测试环境下的项目文件权限时非常有用。
# 创建项目目录
mkdir -p /projects/webapp
# 设置目录默认ACL(子目录和文件将继承)
setfacl -R -m d:u:developer:rwX /projects/webapp/
# 设置组的默认ACL
setfacl -R -m d:g:devteam:rwX /projects/webapp/
# 验证继承效果
cd /projects/webapp
touch test.txt
mkdir subdir
ls -la # 应该能看到文件名后的`+`号,表示该文件/目录设置了ACL
getfacl test.txt
4.5 ACL实用脚本
批量设置目录ACL:
#!/bin/bash
# script: batch_setfacl.sh
# 用途:批量为项目目录设置ACL权限
PROJECT_DIR="/projects"
DEVELOPER="developer"
DEVTEAM="devteam"
# 设置目录基础所有权
chown -R ${DEVELOPER}:${DEVTEAM} ${PROJECT_DIR}
# 设置目录ACL继承规则
for dir in ${PROJECT_DIR}/*/; do
echo "Setting ACL for: ${dir}"
setfacl -R -m u:${DEVELOPER}:rwX "${dir}"
setfacl -R -m g:${DEVTEAM}:rwX "${dir}"
setfacl -R -m d:u:${DEVELOPER}:rwX "${dir}"
setfacl -R -m d:g:${DEVTEAM}:rwX "${dir}"
done
echo "ACL setup completed"
备份ACL权限:
#!/bin/bash
# script: backup_acl.sh
# 用途:备份指定目录的ACL权限到文件
BACKUP_DIR="/var/backup/acl"
TARGET_DIR="/home"
mkdir -p "${BACKUP_DIR}"
# 使用getfacl -R备份,-p选项可以去掉注释行
getfacl -R "${TARGET_DIR}" 2>/dev/null > "${BACKUP_DIR}/acl_backup_$(date +%Y%m%d).txt"
echo "ACL backed up to ${BACKUP_DIR}"
恢复ACL权限:
#!/bin/bash
# script: restore_acl.sh
# 用途:从备份文件恢复ACL权限
BACKUP_FILE="/var/backup/acl/acl_backup_20260403.txt"
if [ ! -f "${BACKUP_FILE}" ]; then
echo "Backup file not found!"
exit 1
fi
# 使用setfacl --restore从文件恢复
setfacl --restore="${BACKUP_FILE}"
echo "ACL restored successfully"
5. 文件属性
除了权限位,Linux还提供了一套文件属性(Attributes)机制,用于控制文件的一些底层行为。文件属性通过chattr和lsattr命令进行管理。
5.1 查看文件属性
# 使用lsattr查看
$ lsattr /etc/passwd
-------------e-- /etc/passwd
# 常用属性位说明:
# e = extent format(扩展格式,ext4文件系统默认)
# i = immutable(不可修改)
# a = append only(只能追加)
# d = no dump(使用dump备份时忽略此文件)
# s = secure deletion(安全删除)
5.2 设置不可修改属性
chattr +i:这是最常用的安全属性。设置后,文件不能被删除、修改、重命名,甚至连root用户也无法直接操作(除非先移除该属性)。
# 保护重要的系统配置文件
chattr +i /etc/passwd
chattr +i /etc/shadow
chattr +i /etc/group
chattr +i /etc/gshadow
# 验证保护效果
rm /etc/passwd
rm: cannot remove '/etc/passwd': Operation not permitted
# 取消保护
chattr -i /etc/passwd
典型应用场景脚本:
#!/bin/bash
# script: protect_system_files.sh
# 用途:保护关键系统文件不被误删或篡改
PROTECTED_FILES=(
"/etc/passwd"
"/etc/shadow"
"/etc/group"
"/etc/gshadow"
"/etc/inittab"
"/etc/fstab"
)
for file in "${PROTECTED_FILES[@]}"; do
if [ -f "$file" ]; then
chattr +i "$file" 2>/dev/null && echo "Protected: $file"
fi
done
echo "System files protection completed"
5.3 设置追加属性
chattr +a:文件只能追加数据,不能删除或覆盖已有内容。非常适合用于保护日志文件和某些配置文件。
# 保护日志文件
chattr +a /var/log/messages
chattr +a /var/log/secure
# 可以正常追加日志内容
echo "new log entry" >> /var/log/messages
# 尝试覆盖内容(会失败)
echo "overwrite" > /var/log/messages
-bash: /var/log/messages: Operation not permitted
# 取消追加属性
chattr -a /var/log/messages
5.4 组合使用属性
# 同时设置不可修改和追加属性(例如用于审计日志)
chattr +i /var/log/audit.log
chattr +a /var/log/audit.log
# 目录的属性设置
# +i属性对目录设置后,将无法在该目录下新建或删除文件
mkdir /secure_dir
chattr +i /secure_dir
touch /secure_dir/test.txt
touch: cannot touch '/secure_dir/test.txt': Permission denied
6. 权限相关命令实战
6.1 权限检查脚本集合
检查可疑权限:
#!/bin/bash
# script: check_suspicious_perms.sh
# 用途:检查系统中权限配置异常的文件
REPORT="/tmp/permission_report_$(date +%Y%m%d).txt"
echo "=== Permission Check Report ===" > "${REPORT}"
echo "Generated: $(date)" >> "${REPORT}"
echo "" >> "${REPORT}"
# 1. 检查777权限的文件
echo "=== Files with 777 permission ===" >> "${REPORT}"
find / -type f -perm 777 2>/dev/null >> "${REPORT}"
echo "" >> "${REPORT}"
# 2. 检查SUID文件
echo "=== SUID Files ===" >> "${REPORT}"
find / -type f -perm +4000 2>/dev/null >> "${REPORT}"
echo "" >> "${REPORT}"
# 3. 检查SGID文件
echo "=== SGID Files ===" >> "${REPORT}"
find / -type f -perm +2000 2>/dev/null >> "${REPORT}"
echo "" >> "${REPORT}"
# 4. 检查无主文件(所有者或所属组不存在的文件)
echo "=== Unowned Files ===" >> "${REPORT}"
find / -nouser -o -nogroup 2>/dev/null >> "${REPORT}"
echo "" >> "${REPORT}"
# 5. 检查全局可写目录(排除/proc等虚拟文件系统)
echo "=== World-Writable Directories ===" >> "${REPORT}"
find / -type d -perm -002 2>/dev/null | grep -v '/proc' | grep -v '/sys' >> "${REPORT}"
cat "${REPORT}"
echo ""
echo "Report saved to: ${REPORT}"
修正常见权限问题:
#!/bin/bash
# script: fix_common_perms.sh
# 用途:修正常见的权限配置问题
set -e
echo "Starting permission fixes..."
# 1. 修正用户home目录权限
echo "Fixing home directory permissions..."
for user in $(ls /home/); do
if [ -d "/home/$user" ]; then
chmod 700 "/home/$user"
chown "$user:$user" "/home/$user"
echo " Fixed: /home/$user"
fi
done
# 2. 修正SSH密钥权限
echo "Fixing SSH key permissions..."
if [ -d "/root/.ssh" ]; then
chmod 700 /root/.ssh
chmod 600 /root/.ssh/id_rsa
chmod 644 /root/.ssh/id_rsa.pub
chmod 600 /root/.ssh/authorized_keys
echo " Fixed: /root/.ssh"
fi
# 3. 修正系统日志目录权限
echo "Fixing log directory permissions..."
chmod 755 /var/log
chmod 755 /var/log/httpd 2>/dev/null || true
chmod 755 /var/log/nginx 2>/dev/null || true
# 4. 修正配置文件权限(保留读取权限但移除组和其他写权限)
echo "Fixing config file permissions..."
find /etc -type f -name "*.conf" -exec chmod 644 {} \; 2>/dev/null
find /etc -type f -name "*.cfg" -exec chmod 644 {} \; 2>/dev/null
echo "Permission fixes completed!"
6.2 Web服务权限配置
Nginx权限配置:
#!/bin/bash
# script: setup_nginx_perms.sh
# 用途:配置Web目录的标准权限
WEB_ROOT="/var/www/html"
NGINX_USER="nginx"
NGINX_GROUP="nginx"
echo "Setting up Nginx permissions..."
# 设置目录基础所有权
chown -R ${NGINX_USER}:${NGINX_GROUP} "${WEB_ROOT}"
# 目录设为755
find "${WEB_ROOT}" -type d -exec chmod 755 {} \;
# 文件设为644
find "${WEB_ROOT}" -type f -exec chmod 644 {} \;
# 上传目录单独处理(通常需要执行权限以支持文件上传)
if [ -d "${WEB_ROOT}/uploads" ]; then
chown -R ${NGINX_USER}:${NGINX_GROUP} "${WEB_ROOT}/uploads"
chmod 755 "${WEB_ROOT}/uploads"
# 上传目录内的文件一般不给执行权限
find "${WEB_ROOT}/uploads" -type f -exec chmod 644 {} \;
echo " Special handling for uploads directory"
fi
# 配置文件权限
chown root:root /etc/nginx/nginx.conf
chmod 644 /etc/nginx/nginx.conf
echo "Nginx permissions configured successfully"
PHP-FPM权限配置:
#!/bin/bash
# script: setup_phpfpm_perms.sh
# 用途:配置PHP-FPM与Web服务的协同权限
WEB_ROOT="/var/www/html"
PHP_USER="php-fpm"
PHP_GROUP="php-fpm"
NGINX_USER="nginx"
echo "Configuring PHP-FPM permissions..."
# 配置PHP-FPM运行用户(修改/etc/php-fpm.d/www.conf)
sed -i "s/^user = .*/user = ${PHP_USER}/" /etc/php-fpm.d/www.conf
sed -i "s/^group = .*/group = ${PHP_GROUP}/" /etc/php-fpm.d/www.conf
# 设置Socket文件权限,让Nginx能够连接
SOCKET_FILE="/var/run/php-fpm/php-fpm.sock"
if [ -S "${SOCKET_FILE}" ]; then
chown ${PHP_USER}:${NGINX_USER} "${SOCKET_FILE}"
chmod 660 "${SOCKET_FILE}"
echo " Socket permissions configured"
fi
# Web目录权限:PHP用户需要读写,Nginx用户需要读
chown -R ${PHP_USER}:${NGINX_USER} "${WEB_ROOT}"
find "${WEB_ROOT}" -type d -exec chmod 755 {} \;
find "${WEB_ROOT}" -type f -exec chmod 644 {} \;
# 缓存目录(PHP需要写权限)
for dir in "${WEB_ROOT}"/{cache,tmp,uploads}; do
if [ -d "$dir" ]; then
chown -R ${PHP_USER}:${NGINX_USER} "$dir"
chmod 755 "$dir"
fi
done
echo "PHP-FPM permissions configured"
6.3 数据库权限配置
MySQL数据目录权限:
#!/bin/bash
# script: setup_mysql_perms.sh
# 用途:配置MySQL标准权限
MYSQL_USER="mysql"
MYSQL_GROUP="mysql"
MYSQL_DATA="/var/lib/mysql"
MYSQL_LOG="/var/log/mysql"
MYSQL_RUN="/var/run/mysql"
echo "Setting MySQL permissions..."
# 数据目录(权限应非常严格)
chown -R ${MYSQL_USER}:${MYSQL_GROUP} "${MYSQL_DATA}"
chmod 700 "${MYSQL_DATA}"
# 日志目录
if [ -d "${MYSQL_LOG}" ]; then
chown -R ${MYSQL_USER}:${MYSQL_GROUP} "${MYSQL_LOG}"
chmod 750 "${MYSQL_LOG}"
fi
# Socket目录
if [ -d "${MYSQL_RUN}" ]; then
chown -R ${MYSQL_USER}:${MYSQL_GROUP} "${MYSQL_RUN}"
chmod 755 "${MYSQL_RUN}"
fi
# 配置文件
chown root:root /etc/my.cnf
chmod 644 /etc/my.cnf
echo "MySQL permissions configured"
PostgreSQL权限配置:
#!/bin/bash
# script: setup_postgres_perms.sh
# 用途:配置PostgreSQL标准权限
PSQL_USER="postgres"
PSQL_GROUP="postgres"
PSQL_DATA="/var/lib/pgsql/data"
PSQL_LOG="/var/log/postgresql"
echo "Setting PostgreSQL permissions..."
# 数据目录(权限极其严格,通常只允许postgres用户访问)
chown -R ${PSQL_USER}:${PSQL_GROUP} "${PSQL_DATA}"
chmod 700 "${PSQL_DATA}"
# HBA配置文件(认证配置,应严格限制)
chown ${PSQL_USER}:${PSQL_GROUP} /var/lib/pgsql/data/pg_hba.conf
chmod 600 /var/lib/pgsql/data/pg_hba.conf
echo "PostgreSQL permissions configured"
6.4 备份权限处理
带权限的完整备份:
#!/bin/bash
# script: backup_with_perms.sh
# 用途:完整备份文件和目录及其所有权限属性
SOURCE_DIR="/data/app"
BACKUP_DIR="/backup/$(date +%Y%m%d_%H%M%S)"
TAR_FILE="${BACKUP_DIR}/backup.tar.gz"
echo "Starting backup with permissions..."
mkdir -p "${BACKUP_DIR}"
# 使用tar并保留权限、ACL、扩展属性等
tar -czpf "${TAR_FILE}" \
--acls \
--xattrs \
--selinux \
-C "$(dirname "${SOURCE_DIR}")" "$(basename "${SOURCE_DIR}")"
# 单独创建权限信息文件作为额外备份
getfacl -R "${SOURCE_DIR}" > "${BACKUP_DIR}/permissions.acl"
# 创建校验和以验证备份完整性
sha256sum "${TAR_FILE}" > "${BACKUP_DIR}/checksum.sha256"
echo "Backup completed: ${TAR_FILE}"
echo "ACL backup: ${BACKUP_DIR}/permissions.acl"
恢复备份并校验权限:
#!/bin/bash
# script: restore_with_perms.sh
# 用途:从备份恢复文件及完整的权限属性
BACKUP_FILE="/backup/20260403/backup.tar.gz"
ACL_FILE="/backup/20260403/permissions.acl"
TARGET_DIR="/data/app"
VERIFY_FILE="/tmp/restore_verify.txt"
echo "Starting restore with permissions..."
# 验证备份完整性(如果存在校验文件)
if [ -f "${BACKUP_FILE}.sha256" ]; then
echo "Verifying backup integrity..."
cd "$(dirname "${BACKUP_FILE}")"
if ! sha256sum -c checksum.sha256; then
echo "ERROR: Backup checksum mismatch!"
exit 1
fi
echo " Checksum verified"
fi
# 备份当前权限(以防万一需要回滚)
getfacl -R "${TARGET_DIR}" > "/tmp/pre_restore_acl.txt" 2>/dev/null || true
# 提取备份文件
tar -xzpf "${BACKUP_FILE}" -C "$(dirname "${TARGET_DIR}")"
# 从备份文件恢复ACL
if [ -f "${ACL_FILE}" ]; then
echo "Restoring ACLs..."
setfacl --restore="${ACL_FILE}"
fi
# 验证恢复结果
getfacl -R "${TARGET_DIR}" > "${VERIFY_FILE}"
echo "Restore completed. Verification saved to: ${VERIFY_FILE}"
7. 常见权限问题排障
7.1 排障思路框架
遇到权限问题,建议遵循以下系统化的排查思路:
权限问题发生
|
v
确认问题现象(读失败?写失败?错误信息是什么?)
|
v
定位相关文件和目录(哪些文件被访问?路径是什么?)
|
v
检查文件所有权(ls -la)
|
v
检查路径上所有父目录的权限
|
v
检查ACL(getfacl)
|
v
检查文件属性(lsattr)
|
v
如果是服务,检查服务运行用户(ps aux)
|
v
如果是服务,检查SELinux/AppArmor状态
|
v
修复问题
|
v
验证修复(测试操作是否成功)
7.2 典型故障:服务无法访问文件(403 Forbidden)
故障现象:Nginx返回403 Forbidden错误,但确认文件确实存在。
排查脚本:
#!/bin/bash
# script: troubleshoot_403.sh
# 用途:排查Nginx 403错误
echo "=== Nginx 403 Troubleshooting ==="
echo ""
# 检查Nginx运行用户
echo "1. Nginx worker process user:"
ps aux | grep "nginx: worker" | head -1
echo ""
# 检查文件所有者
echo "2. Target file owner:"
ls -la /var/www/html/index.html
echo ""
# 检查文件所在目录的权限链
echo "3. Permission chain:"
TARGET="/var/www/html/index.html"
while [ "$TARGET" != "/" ]; do
ls -ld "$TARGET"
TARGET=$(dirname "$TARGET")
done
echo ""
# 检查SELinux上下文
echo "4. SELinux context:"
ls -Z /var/www/html/index.html
echo ""
# 检查ACL
echo "5. ACL settings:"
getfacl /var/www/html/index.html 2>/dev/null || echo "No ACL"
echo ""
# 检查nginx配置中的用户指令
echo "6. Nginx config user directive:"
grep -r "^user" /etc/nginx/nginx.conf
echo ""
# 尝试以nginx用户身份读取文件
echo "7. Test read as nginx user:"
su -s /bin/bash nginx -c "cat /var/www/html/index.html" 2>&1 || echo "Cannot read as nginx user"
常见原因及修复:
# 原因1:文件所有者不对
chown nginx:nginx /var/www/html/index.html
# 原因2:目录权限不足
chmod 755 /var/www/html
# 原因3:上级目录权限问题
chmod 755 /var/www
# 原因4:SELinux上下文问题
chcon -t httpd_sys_content_t /var/www/html/index.html
restorecon -R /var/www/html
# 原因5:ACL阻止了访问
setfacl -b /var/www/html/index.html
7.3 典型故障:无法写入文件
故障现象:应用程序(如Web服务、自定义脚本)无法写入日志文件或数据文件。
排查脚本:
#!/bin/bash
# script: troubleshoot_write.sh
# 用途:排查写入权限问题
TARGET_PATH="$1"
APP_USER="$2"
if [ -z "$TARGET_PATH" ] || [ -z "$APP_USER" ]; then
echo "Usage: $0 <target_path> <app_user>"
exit 1
fi
echo "=== Write Permission Troubleshooting ==="
echo "Target: ${TARGET_PATH}"
echo "App User: ${APP_USER}"
echo ""
# 1. 检查路径上所有目录的写权限
echo "1. Write permission check (directory chain):"
TARGET="$TARGET_PATH"
while [ "$TARGET" != "/" ]; do
PARENT=$(dirname "$TARGET")
if [ -d "$TARGET" ]; then
PERMS=$(stat -c "%a" "$TARGET")
OWNER=$(stat -c "%U:%G" "$TARGET")
echo " $TARGET: $PERMS ($OWNER)"
# 检查当前用户是否有写权限
if [ -w "$TARGET" ]; then
echo " -> Current user CAN write"
else
echo " -> Current user CANNOT write"
fi
fi
TARGET="$PARENT"
done
echo ""
# 2. 检查目标文件的写权限(如果文件存在)
echo "2. File write permission:"
if [ -f "$TARGET_PATH" ]; then
ls -la "$TARGET_PATH"
if [ -w "$TARGET_PATH" ]; then
echo " -> File is writable"
else
echo " -> File is NOT writable"
fi
else
echo " -> File does not exist, checking parent directory"
if [ -w "$(dirname "$TARGET_PATH")" ]; then
echo " -> Parent directory is writable (can create)"
else
echo " -> Parent directory is NOT writable"
fi
fi
echo ""
# 3. 检查ACL
echo "3. ACL check:"
getfacl "$TARGET_PATH" 2>/dev/null | grep -E "^user:|^group:|^mask:"
echo ""
# 4. 检查文件系统属性(如不可修改标志)
echo "4. File attributes (immutable flag):"
lsattr "$TARGET_PATH" 2>/dev/null || echo "Cannot read attributes"
echo ""
# 5. 模拟应用用户测试写入能力
echo "5. Test as ${APP_USER}:"
su -s /bin/bash "$APP_USER" -c "touch ${TARGET_PATH}.test 2>&1" && {
rm -f "${TARGET_PATH}.test"
echo " -> ${APP_USER} CAN create files"
} || echo " -> ${APP_USER} CANNOT create files"
7.4 权限问题综合检查脚本
#!/bin/bash
# script: full_permission_audit.sh
# 用途:全面审计系统权限状态
OUTPUT_DIR="/tmp/perm_audit_$(date +%Y%m%d)"
mkdir -p "${OUTPUT_DIR}"
echo "=== Full System Permission Audit ==="
echo "Output directory: ${OUTPUT_DIR}"
echo ""
# 1. 系统关键目录权限基线
{
echo "=== Critical Directory Permissions ==="
for dir in /etc /var /usr /home /root /tmp /boot; do
if [ -d "$dir" ]; then
ls -ld "$dir"
fi
done
} > "${OUTPUT_DIR}/01_critical_dirs.txt"
# 2. SUID/SGID文件清单
{
echo "=== SUID Files ==="
find / -type f -perm -4000 2>/dev/null | head -100
echo ""
echo "=== SGID Files ==="
find / -type f -perm -2000 2>/dev/null | head -100
} > "${OUTPUT_DIR}/02_suid_sgid.txt"
# 3. World-writable文件和目录
{
echo "=== World-Writable Files (excluding /proc) ==="
find / -type f -perm -2 ! -path "/proc/*" ! -path "/sys/*" 2>/dev/null | head -50
echo ""
echo "=== World-Writable Directories ==="
find / -type d -perm -2 ! -path "/proc/*" ! -path "/sys/*" 2>/dev/null | head -50
} > "${OUTPUT_DIR}/03_world_writable.txt"
# 4. 无主文件
{
echo "=== Unowned Files ==="
find / -nouser -o -nogroup 2>/dev/null | head -50
} > "${OUTPUT_DIR}/04_unowned.txt"
# 5. 异常权限检查
{
echo "=== Files with 777 Permission ==="
find / -type f -perm 777 2>/dev/null | head -50
echo ""
echo "=== Root-owned files in /home ==="
find /home -type f -user root 2>/dev/null | head -20
} > "${OUTPUT_DIR}/05_anomalies.txt"
# 6. SSH目录权限
{
echo "=== SSH Directory and Key Permissions ==="
for dir in /root/.ssh /home/*/.ssh; do
if [ -d "$dir" ]; then
echo "Directory: $dir"
ls -la "$dir"
echo ""
fi
done
} > "${OUTPUT_DIR}/06_ssh_perms.txt"
# 7. 重要配置文件权限
{
echo "=== Critical Config File Permissions ==="
for file in /etc/passwd /etc/shadow /etc/group /etc/gshadow /etc/services; do
if [ -f "$file" ]; then
ls -la "$file"
fi
done
} > "${OUTPUT_DIR}/07_critical_configs.txt"
echo "Audit completed. Files in: ${OUTPUT_DIR}"
ls -la "${OUTPUT_DIR}"
8. 安全最佳实践
8.1 权限配置原则
最小权限原则:只授予完成任务所必需的最小权限,切忌过度授权。
# 不好:给所有用户读和执行权限
chmod 755 file.txt # 如果file.txt是配置文件,通常不需要执行权限
# 好:只给所有者读写权限,其他用户无权限
chmod 600 file.txt
# 目录例外:需要被浏览但不能写入的共享目录
chmod 755 /shared/readonly
目录权限优先:记住,对目录的写权限决定了能否在该目录下创建或删除文件,这往往比文件本身的权限更重要。
# 用户A创建了文件
touch /shared/file.txt # 所有者为A
# 如果用户B对/shared目录有写权限,即使file.txt属于A,B也可以删除它
# 解决方案:在共享目录上设置Sticky Bit
chmod 1775 /shared
敏感文件特殊处理:对关键的系统配置文件使用文件属性加固。
# 防止系统配置文件被篡改
chattr +i /etc/passwd /etc/shadow /etc/group /etc/gshadow
# 日志文件设为只追加模式,防止被覆盖
chattr +a /var/log/messages /var/log/secure
# 验证
lsattr /etc/passwd
# 应该显示 ----i------------- /etc/passwd
8.2 服务运行用户配置
原则:为每个服务创建并使用独立的、低权限的专用用户来运行,避免某个服务被攻破后危及整个系统。
# 创建专用系统服务用户(-r创建系统用户,-s指定不可登录shell,-d指定家目录)
useradd -r -s /sbin/nologin -d /var/lib/myapp myapp
# 设置服务相关目录的所有权
chown -R myapp:myapp /var/lib/myapp
chown -R myapp:myapp /var/log/myapp
# 确保目录权限正确
chmod 755 /var/lib/myapp
chmod 750 /var/log/myapp
8.3 定期权限审计
#!/bin/bash
# script: scheduled_permission_audit.sh
# 用途:定期权限审计(建议加入cron定时任务)
AUDIT_DIR="/var/audit/permissions"
DATE=$(date +%Y%m%d)
PREVIOUS_FILE="${AUDIT_DIR}/baseline.txt"
CURRENT_FILE="${AUDIT_DIR}/current_${DATE}.txt"
DIFF_FILE="${AUDIT_DIR}/diff_${DATE}.txt"
mkdir -p "${AUDIT_DIR}"
# 收集当前SUID文件快照
echo "Generating current SUID file list..."
find / -type f -perm -4000 2>/dev/null | sort > "${CURRENT_FILE}"
if [ -f "${PREVIOUS_FILE}" ]; then
# 比对与上一次的变更
diff "${PREVIOUS_FILE}" "${CURRENT_FILE}" > "${DIFF_FILE}"
if [ -s "${DIFF_FILE}" ]; then
echo "WARNING: SUID file changes detected!"
cat "${DIFF_FILE}"
# 此处可以集成邮件、钉钉、Slack等告警
fi
# 备份旧的基线文件
mv "${PREVIOUS_FILE}" "${AUDIT_DIR}/baseline_$(date +%Y%m%d -d yesterday).txt"
fi
# 将当前快照创建为新的基线
cp "${CURRENT_FILE}" "${PREVIOUS_FILE}"
echo "Audit completed"
8.4 文件权限基线核查
#!/bin/bash
# script: permission_compliance_check.sh
# 用途:检查权限是否符合安全基线
echo "=== Permission Compliance Check ==="
echo ""
ISSUES=0
# 检查1:/etc/shadow应该是600(或更严格的000)
if [ -f /etc/shadow ]; then
PERMS=$(stat -c "%a" /etc/shadow)
if [ "$PERMS" != "0" ]; then # shadow文件权限常显示为0(即000)
echo "[FAIL] /etc/shadow permissions: $PERMS (expected 0)"
ISSUES=$((ISSUES+1))
else
echo "[PASS] /etc/shadow permissions: $PERMS"
fi
fi
# 检查2:/etc/passwd应该是644或更低
if [ -f /etc/passwd ]; then
PERMS=$(stat -c "%a" /etc/passwd)
if [ "$PERMS" -gt "644" ]; then
echo "[FAIL] /etc/passwd permissions: $PERMS (expected <=644)"
ISSUES=$((ISSUES+1))
else
echo "[PASS] /etc/passwd permissions: $PERMS"
fi
fi
# 检查3:SSH私钥应该是600
if [ -f /root/.ssh/id_rsa ]; then
PERMS=$(stat -c "%a" /root/.ssh/id_rsa)
if [ "$PERMS" != "600" ]; then
echo "[FAIL] SSH private key permissions: $PERMS (expected 600)"
ISSUES=$((ISSUES+1))
else
echo "[PASS] SSH private key permissions: $PERMS"
fi
fi
# 检查4:.ssh目录应该是700
if [ -d /root/.ssh ]; then
PERMS=$(stat -c "%a" /root/.ssh)
if [ "$PERMS" != "700" ]; then
echo "[FAIL] .ssh directory permissions: $PERMS (expected 700)"
ISSUES=$((ISSUES+1))
else
echo "[PASS] .ssh directory permissions: $PERMS"
fi
fi
# 检查5:普通用户home目录应该是700
for user in /home/*; do
if [ -d "$user" ]; then
PERMS=$(stat -c "%a" "$user")
if [ "$PERMS" != "700" ]; then
echo "[FAIL] $user permissions: $PERMS (expected 700)"
ISSUES=$((ISSUES+1))
else
echo "[PASS] $user permissions: $PERMS"
fi
fi
done
# 检查6:/tmp目录应该是1777(带sticky bit)
PERMS=$(stat -c "%a" /tmp)
if [ "$PERMS" != "1777" ]; then
echo "[FAIL] /tmp permissions: $PERMS (expected 1777)"
ISSUES=$((ISSUES+1))
else
echo "[PASS] /tmp permissions: $PERMS"
fi
echo ""
if [ $ISSUES -eq 0 ]; then
echo "All checks passed!"
exit 0
else
echo "Found $ISSUES issue(s)"
exit 1
fi
9. 总结与检查清单
9.1 核心知识点回顾
- 基本权限模型:UGO三元组,
rwx对应4/2/1,umask决定默认权限。
- 特殊权限:SUID(
4)、SGID(2)、Sticky Bit(1),分别用于提升执行权限、继承组和目录文件保护。
- ACL扩展:
getfacl/setfacl实现用户和组级别的精细控制,支持权限继承,由mask限制最大权限。
- 文件属性:
chattr/lsattr管理底层属性,+i防篡改,+a只追加,是重要的计算机基础安全加固手段。
- 排障思路:确认用户身份 -> 检查文件属主权限 -> 检查父目录链权限 -> 检查ACL/属性 -> 考虑SELinux。
9.2 日常操作检查清单
部署新服务时:
[ ] 创建专用服务用户(useradd -r -s /sbin/nologin)
[ ] 设置服务目录所有权(chown -R serviceuser:serviceuser)
[ ] 目录权限设为755,文件权限设为644
[ ] 日志目录权限设为750或755
[ ] 需要服务写入的目录(如缓存、上传)单独确认并设置适当权限
[ ] 关键配置文件考虑使用 chattr +i 加固
备份和恢复时:
[ ] 使用 tar -p 或 --acls --xattrs 选项保留完整权限和属性
[ ] 备份前后使用 getfacl -R 记录权限快照
[ ] 恢复后验证文件权限是否正确
[ ] 验证服务运行用户是否能正常读写其所需文件
9.3 常用命令速查表
| 操作 |
命令 |
| 查看文件权限 |
ls -la file |
| 修改权限(数字) |
chmod 755 file |
| 修改权限(符号) |
chmod u+x file |
| 修改所有者 |
chown user file |
| 修改所属组 |
chgrp group file |
| 同时修改所有者和组 |
chown user:group file |
| 设置SUID |
chmod u+s file 或 chmod 4xxx file |
| 设置SGID |
chmod g+s dir 或 chmod 2xxx dir |
| 设置Sticky Bit |
chmod +t dir 或 chmod 1xxx dir |
| 查看ACL |
getfacl file |
| 设置ACL |
setfacl -m u:user:rw file |
| 删除ACL |
setfacl -x u:user file |
| 查看文件属性 |
lsattr file |
| 设置不可修改 |
chattr +i file |
| 取消不可修改 |
chattr -i file |
| 设置追加属性 |
chattr +a file |
| 查找SUID文件 |
find / -perm -4000 -type f |
| 查找SGID文件 |
find / -perm -2000 -type f |
| 查找全局可写文件/目录 |
find / -perm -2 |
9.4 排障流程图
权限问题发生
|
v
确认问题现象(读失败?写失败?)
|
v
定位相关文件路径
|
v
检查文件所有权(ls -la)
|
v
检查路径上所有父目录权限
|
v
检查ACL(getfacl)
|
v
检查文件属性(lsattr)
|
v
如果是服务,检查服务运行用户(ps aux)
|
v
如果是服务,检查SELinux/AppArmor状态
|
v
修复问题
|
v
验证修复(测试操作是否成功)
参考信息
环境版本:
- 操作系统:Rocky Linux 9.4
- 内核版本:6.8.5
- GNU Coreutils:9.1
- bash版本:5.2.15
掌握Linux权限体系是每一位系统管理员和开发者的必备技能。它不仅关乎系统的稳定运行,更是安全保障的第一道防线。希望这份指南能帮助你构建起清晰的知识脉络,并在实践中游刃有余。如果你在权限管理方面有更多心得或疑问,欢迎在云栈社区与广大技术同仁交流探讨。