在Ubuntu系统中,/tmp目录是所有用户和进程都能读写的临时文件存放区,这也让它成为攻击者最喜欢利用的突破口。要加固这个目录,核心操作就是在/etc/fstab中给/tmp挂载点加上noexec和nosuid两个选项。具体做法是:打开fstab文件,找到/tmp对应的行,将挂载选项改为"defaults,noexec,nosuid,nodev",然后重新挂载生效。这两个选项分别禁止在/tmp下执行任何程序、禁止在/tmp下使用SUID位提权,能有效阻断绝大多数基于临时目录的攻击链。
很多运维人员知道要做这件事,但不清楚为什么要做、怎么做才规范、做了之后会不会影响正常业务。这篇文章把这些问题全部讲透,从原理到实操到验证,一步不落。
为什么/tmp目录是高危区域
/tmp目录的权限默认是1777,也就是所有人都能读、写、执行,并且带有sticky位(只有文件所有者能删除自己的文件)。这个设计是为了方便多用户共享临时空间,但在安全层面就是一个巨大的隐患。攻击者只要能往/tmp写入文件,就有可能在里面放一个恶意脚本,然后尝试执行它。如果/tmp允许执行,攻击者就能直接运行恶意代码,获取当前用户权限甚至提权到root。
现实中的攻击场景非常典型:比如Web应用存在文件上传漏洞,攻击者上传了一个PHP webshell到/tmp目录,如果/tmp有执行权限,直接访问就能拿到服务器控制权。再比如,攻击者通过SSH登录了一个低权限用户,在/tmp里编译一个提权工具并运行,如果noexec没开,提权就成功了。所以/tmp的加固是服务器安全基线的基本操作,几乎所有安全合规标准都会要求这一项。
noexec和nosuid到底是什么意思
noexec是一个挂载选项,它的作用是禁止在该文件系统上执行任何二进制程序。注意,它不是删除执行权限,而是从内核层面直接拒绝execve系统调用。也就是说,即使你把一个文件chmod +x了,放到挂载了noexec的目录下,系统也不会让你运行它。这比单纯改文件权限要强得多,因为攻击者没法通过chmod绕过。
nosuid的作用是禁止在该文件系统上使用SUID和SGID位。SUID是一种特殊权限,当一个可执行文件设置了SUID位,任何用户运行它时都会以文件所有者的身份运行。比如passwd命令就是SUID root的,普通用户运行它就能修改/etc/shadow。如果攻击者在/tmp放一个SUID root的恶意程序,就能直接提权。nosuid就是从根源上堵死这条路。
还有一个常一起使用的选项是nodev,它禁止在该文件系统上创建设备文件。虽然/tmp一般不需要创建设备节点,但加上nodev是更严格的做法,属于纵深防御的一部分。实际生产环境中,建议三个选项一起上:noexec,nosuid,nodev。
具体操作步骤:修改/etc/fstab
第一步,备份fstab文件。这个文件一旦改错,系统可能无法正常启动,所以先备份:
sudo cp /etc/fstab /etc/fstab.bak
第二步,用编辑器打开fstab:
sudo nano /etc/fstab
第三步,找到/tmp对应的挂载行。Ubuntu系统中,/tmp通常有两种情况:一种是独立分区,fstab里会有一行类似这样的内容:
UUID=xxxx-xxxx /tmp ext4 defaults 0 0
另一种情况是/tmp是根分区的一部分,没有独立挂载行,而是通过tmpfs(内存文件系统)挂载的。这种情况下,你需要在fstab里添加一行,或者修改现有的tmpfs挂载行。Ubuntu 18.04及以后版本,/tmp默认就是tmpfs,挂载行通常是:
tmpfs /tmp tmpfs defaults,noatime,nosuid,nodev 0 0
如果你的系统已经有nosuid和nodev但没有noexec,那就在defaults后面加上noexec:
tmpfs /tmp tmpfs defaults,noatime,nosuid,nodev,noexec 0 0
如果是独立分区的ext4格式,就把defaults改成defaults,noexec,nosuid,nodev:
UUID=xxxx-xxxx /tmp ext4 defaults,noexec,nosuid,nodev 0 0
第四步,保存退出后,重新挂载使配置生效,不需要重启:
sudo mount -o remount /tmp
如果你是新添加的挂载行,可以直接用:
sudo mount -a
验证配置是否生效
修改完之后必须验证,不验证等于没做。用mount命令查看/tmp的挂载选项:
mount | grep /tmp
输出结果中应该能看到noexec、nosuid、nodev这几个关键词。如果看到了,说明配置正确。如果没看到,检查fstab语法有没有写错,可以用以下命令检查fstab是否有语法错误:
sudo findmnt --verify
还可以做一个实际测试:在/tmp下创建一个简单的脚本并尝试执行:
echo '#!/bin/bash' > /tmp/test.sh echo 'echo hello' >> /tmp/test.sh chmod +x /tmp/test.sh /tmp/test.sh
如果noexec生效,系统会报"Permission denied"或者"cannot execute binary file"之类的错误。这就证明noexec在正常工作。
对业务的影响和应对方案
很多人担心加了noexec会影响正常程序运行。确实,有些程序会在/tmp下生成临时可执行文件然后运行,比如某些编译工具、Java的JIT编译器、部分数据库的临时操作等。但在绝大多数服务器场景下,/tmp只是用来存放临时数据文件,不需要执行程序。如果确实有程序需要在/tmp执行,有几种处理方式。
第一种,为特定程序创建独立的临时目录,比如/var/tmp/myapp,这个目录不加noexec。第二种,如果程序必须用/tmp,可以在程序启动脚本里把需要执行的文件放到其他允许执行的目录。第三种,使用systemd的PrivateTmp功能,为特定服务创建独立的、受限制的/tmp空间,既隔离又可控。对于大多数Web服务器、数据库服务器来说,加noexec完全不会有问题。
需要特别注意的是,如果你的系统上跑着某些老旧的应用或者自研程序,建议先在测试环境验证,确认不受影响再上生产。安全加固不能一刀切导致业务中断,那就本末倒置了。
Ubuntu不同版本的差异处理
Ubuntu 16.04及更早版本,/tmp通常是根分区的一个目录,没有独立挂载,默认权限1777。这种情况下,你需要在fstab里添加tmpfs的挂载行来覆盖默认行为,或者直接修改根分区的挂载选项(不推荐,影响面太大)。
Ubuntu 18.04、20.04、22.04、24.04这些较新版本,/tmp默认已经是tmpfs挂载,而且通常已经带了nosuid和nodev,但不一定有noexec。你只需要检查并补上noexec即可。可以用以下命令快速查看当前状态:
mount | grep tmp
如果输出中tmpfs /tmp那行没有noexec,就按前面的步骤加上。如果你的系统用了systemd的tmp.mount单元来管理/tmp,也可以直接修改那个单元文件:
sudo systemctl cat tmp.mount
查看具体配置,然后通过override机制修改:
sudo systemctl edit tmp.mount
在编辑器里添加或修改Options行,加入noexec。这种方式比直接改fstab更符合systemd的管理逻辑,也更不容易被系统更新覆盖。
安全加固的整体视角
/tmp加固只是服务器安全基线的一个环节,不能指望只做这一件事就高枕无忧。完整的安全基线还应该包括:禁用不必要的服务、配置防火墙规则、定期更新系统补丁、使用SSH密钥登录、配置fail2ban防暴力破解、限制root远程登录等等。/tmp的noexec和nosuid属于"减少攻击面"这一类措施,它的价值在于即使其他防线被突破,攻击者在/tmp这个常用跳板上也很难进一步扩大战果。
从纵深防御的角度看,noexec阻断了执行路径,nosuid阻断了提权路径,nodev阻断了设备节点利用路径。三层叠加之后,/tmp从一个"什么都能干"的开放区域变成了一个"只能存数据"的受限区域。这种最小权限原则是Linux安全加固的核心思想,不仅仅适用于/tmp,也适用于/var/tmp、/dev/shm等其他共享目录。
最后提醒一点,修改fstab之前一定要备份,修改之后一定要验证。如果你是远程操作服务器,建议先在本地开一个备用会话,万一fstab写错导致无法挂载,还有另一个会话可以修复。安全加固是好事,但操作失误导致的故障比安全漏洞更直接、更致命。稳扎稳打,先验证再推广,这才是专业运维该有的态度。
总结
Ubuntu系统加固/tmp目录,核心就是在fstab中添加noexec和nosuid选项。操作简单,风险可控,效果显著。独立分区就改对应行的挂载选项,tmpfs就在现有行里追加noexec。改完用mount命令验证,用实际执行测试确认。注意业务兼容性,老旧程序需要单独处理。结合其他安全措施形成完整基线,才能真正提升服务器的整体安全水位。
