我被黑了,今天早上服务器开始挖门罗币了

原来从12月7日起,我竟在为他人挖矿整整十天。真是妙极了。

 💬 372 条评论 |  漏洞/黑客/挖矿 | 

编辑:这件事引发的关注远超预期。我原本让claude根据我惊慌失措的聊天记录草拟文案,反馈很明确——没人喜欢AI生成的粗糙内容。因此我今早重新润色了文案,修正了部分不准确之处并使其更具人性化。——杰克

或:我如何领悟到“我不使用Next.js”并不意味着你的依赖项不使用Next.js

上午8:25:邮件§

清晨醒来收到赫兹纳这封“佳作”:

元素周期表

尊敬的杰克·桑德斯先生:

我们发现您的服务器存在攻击迹象。请采取必要措施避免此类事件重演并解决问题。

同时请向我们提交简要说明,内容应包含事件发生原因及后续处理方案。若未能在2025-12-17 12:46:15 +0100前完成后续步骤,您的服务器可能随时被封禁。

附件包含从我方服务器向泰国某IP范围进行网络扫描的证据。太棒了。没有什么比收到滥用报告和四小时内基础设施被关闭的威胁更能表达“早安”了。

背景:我使用Hetzner服务器托管Coolify平台,运行着所有个人项目,包括我的网络小天地:

  • 物联网副业
  • 本博客
  • 数据分析系统
  • 我父亲的网站(他是电工)

上午8:30:糟了§

我第一时间通过SSH登录检查负载平均值:

$ w
 08:25:17 up 55 days, 17:23,  5 users,  load average: 15.35, 15.44, 15.60

该服务器运行着多个Go后端服务和SvelteKit前端应用。我每日总访问量峰值仅20人,显然出了大问题。

执行ps aux查看CPU消耗情况:

USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
1001      714822  819  3.6 2464788 2423424 ?     Sl   Dec16 9385:36 /tmp/.XIN-unix/javae
1001       35035  760  0.0      0     0 ?        Z    Dec14 31638:25 [javae] 
1001     3687838  586  0.0      0     0 ?        Z    Dec07 82103:58 [runnv] 
1001     4011270  125  0.0      0     0 ?        Z    Dec11 10151:54 [xmrig] 
1001       35652 62.3  0.0      0     0 ?        Z    Dec12 4405:17 [xmrig] 

CPU占用率高达819%。罪魁祸首是/tmp/.XIN-unix/目录下的javae进程,以及多个xmrig进程——这分明是加密货币挖矿软件(具体是门罗币)。

原来从12月7日起,我竟在为他人挖矿整整十天。真是妙极了。

调查始末§

我的第一反应是“彻底完蛋了”。主机运行加密货币挖矿程序已有一周,整台机器彻底报废。只能直接重置系统重建。

所幸我事先做了些侦探工作,至少要查明入侵途径以防后患。在克劳德的协助下(这并非我的专长)展开调查。

首先发现一个有趣现象:所有进程都以用户1001身份运行。既非root用户,也非系统用户——而是UID 1001。

让我检查实际运行的进程:

$ docker ps
CONTAINER ID   IMAGE                                                               CREATED       STATUS                 PORTS            NAMES
c604f579efd5   dsw80g4w8g0kgog8oskc0sks:63e3be6167b43de47663445dd72f92f97887b843   2 days ago    Up 2 days (healthy)     [DELETED]       dsw80g4w8g0kgog8oskc0sks-075301203997
00aec82c2650   o4wk8gsckwgkcgcgkcw8gcsc:40497e7208602d31d7b5e58af4f2e86611b9850c   2 days ago    Up 2 days               [DELETED]       o4wk8gsckwgkcgcgkcw8gcsc-072326337252
a42f72cb1bc5   ghcr.io/umami-software/umami:postgresql-latest                      9 days ago    Up 9 days (healthy)     [DELETED]       umami-bkc4kkss848cc4kw4gkw8s44
7c365a792902   postgres:16-alpine                                                  9 days ago    Up 9 days (healthy)     [DELETED]       postgresql-bkc4kkss848cc4kw4gkw8s44
af077d142471   ghcr.io/coollabsio/coolify:4.0.0-beta.452                           10 days ago   Up 10 days (healthy)    [DELETED]       coolify
fdc3cc9b926b   ghcr.io/coollabsio/coolify-realtime:1.0.10                          10 days ago   Up 10 days (healthy)    [DELETED]       coolify-realtime
d3dc2af3ff4d   postgres:15-alpine                                                  10 days ago   Up 10 days (healthy)    [DELETED]       coolify-db
dc77adba40bb   redis:7-alpine                                                      10 days ago   Up 10 days (healthy)    [DELETED]       coolify-redis
4962dd18bed7   ghcr.io/coollabsio/sentinel:0.0.18                                  3 weeks ago   Up 7 hours (healthy)    [DELETED]       coolify-sentinel
5ec997e35140   nginx:stable-alpine                                                 6 weeks ago   Up 6 weeks (healthy)    [DELETED]       kcwsosksw084swoog04g0w0k-proxy
5da5e2f2052b   prom/prometheus:latest                                              6 weeks ago   Up 6 weeks              [DELETED]       yg400wo4wok8k0cgo8844gcg-155648790718
32815a5e2e52   twakedrive/tdrive-frontend                                          7 weeks ago   Up 7 weeks              [DELETED]       frontend-ssowscwgccgk8k0k8oos8w40-120609116307
5d6bc828fe7f   twakedrive/tdrive-node                                              7 weeks ago   Up 7 weeks              [DELETED]       tdrive_node-ssowscwgccgk8k0k8oos8w40-120609108796
3e727b84415d   mongo                                                               7 weeks ago   Up 7 weeks              [DELETED]       mongo-ssowscwgccgk8k0k8oos8w40-120609102533
3506728b808b   a4c00g0ggkk4cww4scsw8scw:682dfd679845535f873d3c5b4599295f4d855ba5   7 weeks ago   Up 7 weeks              [DELETED]       a4c00g0ggkk4cww4scsw8scw-113711308615
736d9f03d152   rccwscgosk48gs0844sogsgw:51d68c7e7665371569aacc5f044c82ec1f06fa4c   7 weeks ago   Up 7 weeks              [DELETED]       rccwscgosk48gs0844sogsgw-111702410410
8f79e6f4c981   grafana/grafana-oss                                                 7 weeks ago   Up 7 weeks (healthy)    [DELETED]       grafana-ik8wokwgowow8gksok8k40sc
09d013497f9f   24a90047f2d2                                                        7 weeks ago   Up 7 weeks (healthy)    [DELETED]       postgresql-ik8wokwgowow8gksok8k40sc
bf8b6a969b19   gcr.io/cadvisor/cadvisor:latest                                     7 weeks ago   Up 7 weeks (healthy)    [DELETED]       k0gkw4koc8swo4wkg44w408g-211926055160
30e4d6edf675   prom/node-exporter:latest                                           7 weeks ago   Up 7 weeks              [DELETED]       yc4c4ckg80ogggc4ck8gwgww-211604215046
b227504e8787   rabbitmq:3-management                                               7 weeks ago   Up 7 weeks (healthy)    [DELETED]       rabbitmq-xscowck8kgc0wssokoggcskc
b260ad24c434   d741b3768746                                                        7 weeks ago   Up 7 weeks (healthy)    [DELETED]       kcwsosksw084swoog04g0w0k
6d038254e9ef   grafana/loki:latest                                                 7 weeks ago   Up 7 weeks              [DELETED]       b88cwo8ckwo0gw840oo444kk-193205274080
fe2aad5d9704   traefik:v3.1                                                        7 weeks ago   Up 7 weeks (healthy)    [DELETED]       coolify-proxy

注:为避免泄露内部机制,此处删除了端口信息。

关键在于,我正在运行Umami——这是我9天前重新部署的隐私导向型分析工具,用于追踪博客流量。当时因其运行异常且原因不明才重新部署,这个时间点让我感到可疑。

现在检查哪个容器使用用户1001:

$ docker ps -q | while read container; do
  echo "=== $container ==="
  docker exec $container ls -la /app/node_modules/next/dist/server/lib/ 2>/dev/null | grep xmrig
done

输出:

=== a42f72cb1bc5 ===
drwxr-xr-x    2 nextjs   nogroup       4096 Dec 17 05:11 xmrig-6.24.0

**就是它。**容器a42f72cb1bc5正是我的Umami分析容器。而在本应存放Next.js服务器内部文件的位置,竟存在完整的xmrig-6.24.0目录。

进程列表中的挖矿命令证实了这一点:

/app/node_modules/next/dist/server/lib/xmrig-6.24.0/xmrig 
  --url auto.c3pool.org:443 
  --user 8Bt9BEG98SbBPNTp1svQtDQs7PMztqzGoNQHo58eaUYdf8apDkbzp8HbLJH89fMzzciFQ7fb4ZiqUbymDZR6S9asKHZR6wn 
  --pass WUZHRkYOHh1GW1RZWBxaWENRX0ZBWVtdSRxQWkBWHg== 
  --donate-level 0

有人利用我的分析容器,正用我的CPU挖矿门罗币。真棒。

等等,我根本没用Next.js§

其实我早就在Hacker News看到过这篇Reddit帖子,提到Next.js存在严重漏洞(CVE-2025-66478)。我的第一反应是“笑死,谁在乎啊,我又不用Next.js”。

噢,我天真的孩子啊。

然而…Umami 正是用Next.js构建的。我对此毫不知情,也懒得去查证。哎呀。

该漏洞(CVE-2025-66478)存在于Next.js的React服务器组件反序列化机制中。RSC用于客户端与服务器间数据序列化/反序列化的“Flight”协议存在反序列化安全漏洞。攻击者可向任意App Router端点发送包含恶意载荷的特殊HTTP请求,当该请求被反序列化时,即可在服务器端执行任意代码。

  1. 攻击者向Umami的Next.js端点发送构造HTTP请求
  2. RSC对恶意有效负载进行反序列化
  3. 通过不安全的反序列化实现远程代码执行
  4. 下载并安装加密货币挖矿程序
  5. 攻击者获利

“我不使用Next.js”这种说法看来不攻自破。

恐慌时刻:它是否逃离了容器?§

此刻我才真正开始恐慌。看着进程列表:

1001      714822  819  3.6 2464788 2423424 ?     Sl   Dec16 9385:36 /tmp/.XIN-unix/javae

这条路径——/tmp/.XIN-unix/javae——似乎位于主机文件系统而非容器内部。这意味着它能访问我的数据库、所有环境变量,所有东西。克劳德告诉我需要:

  1. 假设所有数据均已泄露
  2. 检查后门程序、持久化机制
  3. 可能需要从头重建系统
  4. 耗费整天时间修复这个烂摊子

我检查了持久化机制:

$ crontab -l
no crontab for root

$ systemctl list-unit-files | grep enabled
# ... all legitimate system services, nothing suspicious

没有恶意cron任务。没有伪装成nginxsapaches的假系统服务。这……还算好?

但我仍需确认:恶意软件是否真的逃离了容器?

真相时刻§

测试标准是:若主机上存在/tmp/.XIN-unix/javae文件,则大势已去。若不存在,则说明我所见只是Docker默认行为——容器进程在主机ps输出中可见,但实际处于隔离状态。

$ ls -la /tmp/.XIN-unix/javae
ls: cannot access '/tmp/.XIN-unix/javae': No such file or directory

它从未逃逸。

至少表面如此。我们可将事件警戒级别从DEFCON1降级为“持枪警戒并加强检查,暂不执行断头台”。

恶意软件完全被限制在Umami容器内。显然,当在Docker主机上运行ps aux时,会显示所有容器进程——因为它们共享同一内核。但这些进程处于独立挂载命名空间中——它们无法访问或修改主机文件系统。

我已确认该容器实际运行的用户身份:

$ docker inspect umami-bkc4kkss848cc4kw4gkw8s44 | grep '"User"'
"User": "nextjs",

$ docker inspect umami-bkc4kkss848cc4kw4gkw8s44 | grep '"Privileged"'
"Privileged": false,

$ docker inspect umami-bkc4kkss848cc4kw4gkw8s44 | grep -A 30 "Mounts"
"Mounts": [],

目前掌握的情况及未彻底失控的原因:

  • 容器以用户nextjs(UID 1001)运行,非root权限。
  • 容器未获得特权。
  • 容器未挂载任何卷。

这意味着:

  • 恶意程序可在容器内运行进程
  • 进行加密货币挖矿
  • 扫描网络(故触发Hetzner滥用报告)
  • 占用100% CPU

但恶意程序无法:

  • 访问主机文件系统
  • 安装cron任务
  • 创建systemd服务
  • 在容器重启后存续
  • 逃逸至其他容器
  • 安装rootkit

容器隔离机制确实有效。不错。

Dockerfile与自动生成镜像§

相较于我链接的Reddit帖子,以下几点在我看来是关键救星:

  • 我为所有应用程序手动编写Dockerfile。这本身并非万能解,但相比自动生成的镜像,能更清晰掌握内部组件。
  • Coolify和Docker在容器化方面的整体理念。虽然后来我了解到不能完全依赖容器隔离来保障安全,但老实说这总比在主机上运行所有程序要好得多。

之前看到的Reddit帖子?那家伙彻底完蛋了,因为他的容器是以root权限运行的。恶意软件可以:

  • 安装cron任务实现持久化
  • 创建systemd服务
  • 在文件系统任意位置写入数据
  • 经受重启考验

可见容器隔离机制在此场景下确实奏效!

我的疏漏在于:未追踪所用工具及其依赖项。事实上,我直接通过Coolify的服务界面安装了Umami,甚至未作任何配置。

当然这绝非Umami的过错。他们一周前就为开源版发布了修复补丁。只是我当时根本没考虑过要处理这件事。

修复方案§

# Stop and remove the compromised container
$ docker stop umami-bkc4kkss848cc4kw4gkw8s44
$ docker rm umami-bkc4kkss848cc4kw4gkw8s44

# Check CPU usage
$ uptime
 08:45:17 up 55 days, 17:43,  1 user,  load average: 0.52, 1.24, 4.83

CPU负载恢复正常。两天过去了,CPU使用率始终稳定在5%左右。

我还启用了UFW防火墙(早该这么做了):

$ sudo ufw default deny incoming
$ sudo ufw default allow outgoing
$ sudo ufw allow ssh
$ sudo ufw allow 80/tcp
$ sudo ufw allow 443/tcp
$ sudo ufw enable

该设置仅允许SSH、HTTP和HTTPS连接,彻底封堵了所有入站通道。PostgreSQL端口不再暴露,RabbitMQ端口也不再对互联网开放。我认为这问题不大,因为5432端口本就未从Docker容器向主机开放。但做起来总归稳妥。

我向Hetzner提交了简要说明:

调查已完成。扫描源自被入侵的Umami分析容器(CVE-2025-66478)。

该容器以非root用户运行,无特权访问权限且未挂载主机文件系统,因此入侵完全被隔离。容器已清除,防火墙已强化。

他们在一小时内关闭了工单。

经验教训§

1. “我不使用X”并不意味着依赖项不会使用X§

我不编写Next.js应用程序。但我运行的是用Next.js构建的第三方工具。当CVE-2025-66478漏洞披露时,我以为“这不关我的事”。大错特错。

务必了解你的依赖项实际采用何种技术栈构建。那款“简单的分析工具”实则是拥有复杂技术栈的完整Web应用程序。

2. 容器隔离机制有效(前提是配置得当)§

情况本可能糟糕得多。若该容器以root权限运行,或挂载了敏感目录的卷,或能访问Docker套接字,我此刻写下的博客就会是关于重建整个基础设施的惨痛教训。

而实际情况是:我删除了一个容器,继续处理日常事务。

**编写专属Dockerfile。**务必明确进程运行用户身份。除非有充分理由,否则避免使用USER root。不要挂载不需要的卷。不要授予容器--privileged权限。

3. 技术成熟度的差距§

这种恶意软件不像那些每次我修改DNS就自动扫描/wpadmin的路人甲。它很厉害。

  • 伪装成合法路径(/app/node_modules/next/dist/server/lib/)
  • 使用混入环境的进程名(javaerunnv)
  • 试图建立持久化机制
  • 据其他报告显示,甚至配备了“杀手脚本”来清除竞争挖矿程序

但它终究受限于容器隔离机制。良好的安全实践终能战胜高明恶意软件。

4. 多层次防御至关重要§

尽管容器隔离机制有效,我仍应做到:

  • 从第一天就启用防火墙(而非拖延至“以后再说”)
  • 运行fail2ban阻止SSH暴力破解攻击
  • 建立完善的监控/警报系统(我仅因Hetzner邮件才察觉异常)
  • 在CVE漏洞披露时立即更新Umami

这次纯属侥幸。容器隔离机制挽救了我因自身懈怠造成的危机。

当前改进措施§

  1. 不再使用Umami。 – 唉,我又改主意了。这并非Umami的过错,他们的开源软件非常出色。我已重新部署了新版Umami。
  2. 全面审核第三方容器。 逐一检查运行中的所有容器:
    • 以何种用户身份运行?
    • 关联哪些存储卷?
    • 最近更新时间?
    • 是否真正需要?
  3. 强化SSH安全。 仅启用密钥认证,禁用密码认证,并配置fail2ban。
  4. 完善监控机制。 设置CPU使用率、负载平均值及可疑网络活动的告警。我绝不该从托管服务商处得知系统遭入侵。虽然已部署Grafana和Node导出器,但若不主动查看数据毫无意义!
  5. 定期安全更新。 彻底告别“稍后更新”的拖延症。若存在CVE漏洞,立即打补丁或停用服务。

阴云中的银色内衬§

这次经历其实收获颇丰:

  • 首次实践真实入侵事件响应
  • 验证容器隔离机制确实有效
  • 深入理解Docker命名空间、用户映射及权限边界
  • 在无实际数据损失压力的情况下强化基础设施

最终仅损失了上班前约两小时的晨间时间,情况本可能糟糕得多。

不过我确实好奇:那混蛋究竟挖了多少门罗币?根据CPU占用率和运行时长推算…大概够他们吃顿丰盛的午餐了。不客气,神秘攻击者。希望你玩得尽兴。

快速浏览§

  • Umami分析工具(基于Next.js构建)存在远程代码执行漏洞
  • 遭恶意利用,植入加密货币挖矿程序
  • 以1000%+ CPU占用率持续挖矿门罗币10天
  • 容器隔离机制救了我——因其以非root权限运行且未挂载任何文件系统
  • 修复方案:执行docker rm umami并启用防火墙
  • 教训:务必了解依赖项的构建方式,并正确配置容器环境

本文文字及图片出自 I got hacked, my server started mining Monero this morning.

共有 372 条讨论

  1. > 我还启用了UFW(早该这么做了)

    我不推荐使用UFW。

    firewalld是当前更优的选择,不会像UFW规则那样变得难以维护。

        firewall-cmd --persistent --set-default-zone=block
        firewall-cmd --persistent --zone=block --add-service=ssh
        firewall-cmd --persistent --zone=block --add-service=https
        firewall-cmd --persistent --zone=block --add-port=80/tcp
        firewall-cmd --reload
    

    配置由/etc/firewalld和/usr/lib/firewalld目录下的xml文件支撑,而非脆弱的ufw规则文件堆栈。除非有特殊需求使用传统iptables,否则请采用nftables后端。

    针对Docker需特别注意:容器运行时常会绕过防火墙规则自行开启端口,这是常见陷阱。根据您的配置,原帖中的防火墙规则可能无法阻止 Docker 打开入站端口。

    新版 firewalld 通过 /etc/firewalld/firewalld.conf 中的 StrictForwardPorts=yes 选项提供了便捷配置方案。

    1. 请避免直接暴露端口组合如 8080:8080,而应采用 “192.168.0.1:8080:8080” 形式绑定到私有IP。随后使用任意传统方法仅对外暴露必要端口。

      我个人实践中,运行Docker的虚拟机使用10.0.10.11作为主机IP。该虚拟机甚至没有独立的公共IP,理论上我甚至可以将其暴露给0.0.0.0。但考虑到未来可能的变更,这只是预防措施。该IP仅通过WireGuard及同一子网内的其他机器可访问,因此在公共IP上使用Caddy进行反向代理非常简单。

      1. 这确实是个陷阱。惊讶于官方从未将默认值从0.0.0.0改为127.0.0.1。若需绑定所有接口,必须显式指定。

        1. 设计初衷是为便捷。若非本地开发场景都采用此方案,实际操作会增加大量阻力。

          Docker还存在更多隐蔽陷阱。例如它会悄然更改使用的私有IP地址段——我曾因与其他用途的私有地址段冲突而中招。配置文件虽可修复,但已创建的容器不受影响。

          顺便提一句。既然说到这里。温馨提示:您很可能不需要用户空间代理(userland-proxy),可将其禁用。

          /etc/docker/daemon.json

          { “userland-proxy”: false }

          1. 是否有类似指南列出Docker的常见选项/注意事项?

            简单搜索后发现的建议大多是泛泛而谈,比如保持更新或启用无root模式。

            1. 据我所知没有。抱歉。不过附上我的daemon.json配置文件供参考。它控制了日志文件大小并设置了格式,同时修复了IP块问题,使其不会像我之前提到的那样改变。

                {
                  “log-driver”: “json-file”,
                  “log-opts”: {
                    “labels”: “production_status”,
                    “tag”: “{{.ImageName}}|{{.Name}}|{{.ImageFullID}}|{{.FullID}}”,
                    “env”: “os,customer”,
                    “max-size”: “10m”
                  },
                  “bip”: “172.17.1.1/24”,
                  “default-address-pools”: [
                    {“base”: “172.17.0.0/16”, “size”: 24}
                  ]
                }
              
      2. 没错,常规的“8080:8080”绑定导致第一天数据库就收到勒索信息。现在只绑定到本地主机了。

        1. 我也遇到同样情况(默认端口的postgres/postgres)。花了几天才查明原因,因为受影响的数据库会定期从其他源重建。我注意到某些时段查询会失败,直到下次重建才恢复。

          1. 确实有大量机器人在网络中搜寻这类漏洞,算是宝贵的教训,不会再犯啦 😀

        2. 我总会忘记的一点是:127.0.0.0/8 其实是一个完整的网络,而非单一IP。

          因此可在/etc/hosts中静态映射多个独立“域名”地址,让多个应用程序监听“相同”端口而不冲突。

          1. 我从未想过这样使用localhost,居然真能行。通常要创建私有/8网络会用10.0.0.0/8,但标准的192.168.0.0/16也能提供大量地址空间(255^2减去2个IP地址,我记得是这样)。

            ..这实在太奇怪了。你是说无需为网卡添加虚拟IP就能绑定127.0.0.2:80?所以“localhost”的概念居然等同于整个A类网络?听起来像是网络堆栈的漏洞啊。

            编辑:没错,OSX的路由表证实了这点。非常诡异(至少对我而言)

    2. 我强烈反对,firewall-cmd实在过于复杂。如果你的主业是防火墙管理员或许还行,但对我们这些只需在防火墙上开个小口子——作为实现真正目标的必要前提——的人来说,这工具实在太臃肿了。

      在 ufw 系统上,我清楚该怎么做:如果需要开放的端口被阻塞,我就运行 ‘ufw allow’。操作极其简单,连我都记得住。如果忘记了,运行 ‘ufw –help’ 就会提示我执行 ‘ufw allow’。

      但防火墙管理命令呢?每次在Fedora系统上需要在防火墙开洞时,我都得花大量时间阅读’firewall-cmd –help’极其复杂的输出结果和庞大的手册页,最终只能放弃改用’sudo systemctl disable –now firewalld’。这种情况已经发生过多次

      如果firewalld/firewall-cmd能满足你的需求,那当然很好。但对于“默认拒绝所有入站流量,仅在本机开放特定端口”这类需求而言,我认为这是极其糟糕的解决方案。更荒谬的是它竟是Fedora Workstation的默认防火墙。

    3.   > 特别针对Docker而言,容器运行时会绕过防火墙规则自行开放端口,这是非常常见的陷阱。
      

      正如我在其他评论所言:弃用Docker,安装podman。

      1. 我总看到podman拥趸呼吁弃用Docker,可每次尝试podman都惨遭失败。依我之见,podman不该定位为Docker的替代品,而应作为独立工具存在。

        1. 这太糟糕了,我在podman中运行Dockerfile从未遇到问题。虽然不清楚操作差异何在,但原则上我会过滤掉任何干扰“容器套容器”机制的容器。podman本就不需要这类花哨操作。

          此外,Docker Compose工具在兼容性方面是个众所周知的例外。(虽然存在非官方的podman compose工具,但功能不全,况且quadlets才是更好的选择。)

          我同意将podman视为独立工具的观点。没错,你可以构建Dockerfile,但buildah能让你从零开始高效构建OCI镜像,且无需root权限。感兴趣者可参阅本文档¹了解 buildah 与 podman、docker 的对比分析。

          1. https://github.com/containers/buildah/tree/main/docs/contain

          1. 无root权限和无守护进程运行的副作用是容器会在用户注销时停止,我实在难以相信这些细节对新手而言竟是理所当然的。因为我原以为生产环境中容器的核心价值,正是确保注销后仍能持续运行。

            当然,仔细想想,没人会期待某个命令在注销后依然存活,但从docker转来的用户仍会抱有这种期待。我不禁疑惑:难道要像从前那样在tmux里运行这些?不,你还得搞定一堆systemd/linger之类的配置。既然已身处systemd生态,继续搜索后便遇到了Quadlet——这个相对较新的方案(据我所知)文档糟糕,却取代了之前文档完善的旧方案。说到底,这些文档足以让人对K8s产生创伤后应激障碍。Quadlet、podlet和pods——混乱至极。

            当Podman偏离Docker时,似乎总以最反直觉的方式行事。或许是我被多年Docker使用习惯洗脑,或许是如今耐心已耗尽,但这就是我的真实体验。部署后五分钟就崩溃,当时我简直蠢到家了。明明本地测试通过,准备好要用podman了,结果生产环境就挂了。谢了,不。

              1. 没错,但我想只对podman生效,别影响其他运行任务。

                    systemctl --user enable podman.socket loginctl enable-linger <USER>?
                
                
                
                1. 我认为应该参照SSH机制。断开连接后会话立即终止。若想保留特定会话组件,该保留哪些?毕竟容器可能依赖主机的avahi、cups或其他服务?

                  只是随想:若能在主机创建仅启用容器必需的最小系统服务集的用户,可将此方案应用于该用户。

                  不过在服务器环境中,此方案意义不大——默认用户通常已是服务用户,其启用的服务本就极简。而在桌面环境,默认用户本就处于登录状态。所以坦白说,这并非真正的问题。

          2. 关于如何在本地开发环境中使用quadlets的教程实在太少,实际上我看到的多数指南都推荐使用podman/Docker compose。你是否在本地开发和测试中使用quadlets?

          3. 我本地运行时直接用Podman的Kubernetes YAML替代Compose,这样环境与生产环境高度一致。如今Docker Compose在我看来已相当小众。

      2. podman 并非 Docker 的直接替代品。虽然可以使用 podman 替代 Docker,但需做好遇到细微差异和重大区别的准备,尤其当您使用 Docker Compose 或希望在无根模式下运行 podman 时。这绝非简单地执行 alias docker=podman 就能解决的问题。

        实现Compose服务自动重启的唯一非弃用方案是使用Quadlet文件——这类systemd单元文件包含针对容器的特殊配置选项。您需要手动将docker-compose.yml转换为一个或多个Quadlet文件。相关文档同样存在诸多不足,仅提供一份冗长的项目化手册页。

      3. 文章完全没提及podman或podman与docker的对比。核心问题在于Umami的NexJS和React CVE漏洞。顺便说,我选择Docker是因为它运行极其稳定,而podman阵营的虚假宣传铺天盖地——除非性命攸关,否则这阵风浪平息前我绝不会碰它。

        1. 若在无特权模式下运行则不受影响——相较于Docker,该模式在Podman中才是更核心的功能。

            1. Docker确实支持无root模式,但正如楼主所言,它并非原生功能。配置过程繁琐且故障频发。而在Podman中它能完美运行,且凭借quadlets等领先特性,使Docker服务与普通服务无异。

              1. 没人想要四重容器,也没人提过这个需求。

      4. 在 Docker 中只需明确定义接口(IP)和端口,例如 0.0.0.0:80。不会发生任何绕过。

      5. 不,我对 Docker 非常满意,它运行得很好。

    4. 若允许任何二进制程序建立出站连接,使用何种netfilter前端都无关紧要。

      要阻止此类攻击,需限制未知/未授权二进制程序的出站连接。

      此类恶意软件尤其需要连接挖矿池。其他类型则会从远程服务器下载脚本或二进制文件,或尝试与C2C服务器通信。

      另一方面,移除/tmp、/var/tmp和/dev/shm目录的可执行权限同样有效。

      1. > 另一方面,移除/tmp、/var/tmp和/dev/shm目录的可执行权限同样有效。

        遗憾的是这更像是临时补丁,因为任何恶意软件都会通过标准调用方式启动脚本(如’/bin/bash /path/to/dropped/payload’)。非可执行挂载仅对直接放置在路径中的二进制文件有效,因为使用较少人知的’/bin/ld.so /path/to/my/binary’调用方式启动的情况较为罕见。

        我曾建议Debian安装程序支持为/tmp配置只读挂载,但遭到了拒绝。太多打包脚本依赖于从/tmp(更准确地说,$TMPDIR)执行其各个步骤。

        1. 我同意。正因如此我才说它同样有用。虽然无法适用于所有场景,但在多数加密货币挖矿攻击中,植入/tmp的文件都是可执行程序。

      2. 很多服务默认需要写入配置文件权限以便通过网页界面调整设置,这确实很遗憾。

        若非如此,大量容器本可以实现完全只读的文件系统。

        1. 通过二进制程序限制出站连接:OpenSnitch。

          还可屏蔽加密货币挖矿池及恶意IP的出站连接,例如利用VirusTotal或urlhaus.bazaar.ch的IOC列表。

        2. 两种路径:

          – 配置管理(Ansible、Salt、Chef、Puppet)
          – 预配置镜像(NixOS、Packer、Guix、Atomic系统)

          一次性操作:pssh

      3. 之前不是有过npm恶意软件事件吗?如果无法回传数据就会破坏用户主目录?

    5. 个人觉得直接用nftables.conf就够直观了,实在看不出额外工具的必要性。iptables虽然折腾人,但它早就被弃用了。

      1. 我也是这么想的,我认识的大多数Linux用户都喜欢安装firewalld、UFW或其他覆盖式防火墙,而不是直接编辑nftables配置,这让我很惊讶。其实操作并不复杂,尽管我从未深入研究过iptables的细节。我猜很多过去用过iptables的人,会觉得nftables类似,出于习惯就避免直接操作它。

        1. 使用nftables前需要学习大量知识,才能对操作效果稍有把握。

          而ufw图形界面只需勾选一个复选框——阻止传入连接。

    6. 为何人们偏爱这些抽象工具而非nftables?直接使用nftables吧,它易学高效,掌握它就等于通晓防火墙的全部精髓。

    7. Hetzner提供独立于主机的免费防火墙服务,可作为第一道防线使用。

      1. 这是个好主意。在OCI环境中,我同时启用了VCN防火墙和VPS内部的ufw防火墙。

      2. Hetzner防火墙服务的弊端在于严重拖累网络性能,尤其在IPv6环境下。

        1. 它还破坏了我的Docker网络配置,导致Portainer无法运行。

      3. 我正在使用该服务。这样是否足够?还是需要在本地机器额外安装防火墙?

        1. 两者都用。使用服务商防火墙能增加额外防护层。但可能出现故障导致规则短暂消失(同步问题、升级、虚拟机迁移等),此时服务将暴露风险。我曾遭遇过这种情况,所幸未造成损失。

        2. 安全需分层防护,我建议双重部署。

    8. firewalld的问题在于它拥有我所知最糟糕的用户体验。选项完全不合逻辑,程序本身在配置错误时不提供任何有用提示,文档糟糕到必须查阅红帽手册——这些手册幸好是为每月支付数千美元支持费的公司编写的。

      iptables虽非完美,但至少直观得多——它直接操作IP地址和端口,而非依赖XML文件定义的区域/服务这类抽象概念。既然firewalld底层仍使用iptables/nftables,我实在不明白为何要在已知技术之上叠加更糟糕的抽象层。

      我真心厌恶firewalld。

      1. 作为FreeBSD和pf的用户,所有Linux防火墙在用户体验上都显得笨拙——至少在最佳状态下如此。

        我渴望看到用合理配置文件管理的Linux防火墙,而BSD确实做到了极致——即使面对多接口/多区域的高级网关配置,其配置文件依然易于配置且人类可读。

        我毫不怀疑Linux在功能上完全能实现同等效果,但天啊,这用户体验实在令人抓狂。

        1. 我完全赞同。

          数十年来我一直在各类计算机上同时使用Linux和FreeBSD。

          若要比较两者,Linux最令人抓狂的莫过于其网络配置工具。

          虽然我的笔记本、台式机及部分计算服务器运行Linux,但在承载网络服务的服务器上,我更青睐FreeBSD——其管理便捷性无可比拟。

        2. 你试过nftables吗?它比iptables好太多了。

          1. 是的,我已经在用nftables了。确实比iptables(或各种iptables前端工具)优秀,目前可能是最佳选择——但老实说,它离pf的用户体验还差得远,可惜啊 :/

      2. 我也讨厌它。为什么要费心学习区域概念,抽象化端口、地址、接口等概念?结果很快发现我的裸机服务器至少从firewalld角度看,始终需要精细化的规则。

    9. 我虽未使用过firewalld,但自2006年起就在桌面端和服务器上使用ufw,可以保证绝无更换计划。

    10. 这两者能处理容器间通信吗?

      假设容器A暴露紧密耦合的服务X和Y。容器B应仅能访问X,容器C应仅能访问Y。

      但不知为何,Docker或Podman始终缺乏便捷的实现方式。上次研究时发现,必须手动调整容器分配的IP地址,并强制服务显式绑定——这实在过于繁琐。防火墙能否解决此问题?

      1. 关于Docker或Podman的问题我无法回答,但在Kubernetes中存在专为此类场景设计的NetworkPolicy API。我确信其底层调用了Linux原生工具(如iptables、nftables等),因此至少在理论上完全可行将这些工具用于此目的。

      1. 关于“别用ufw改用firewalld”的评论?我不同意。自2006年起我一直在用ufw,且无意更换。它运行得很好。

    11. 在此提一下Foomuuri。它算是shorewall的精神续作,并具备firewalld模拟功能,可兼容firewalld相关工具

      1. 感谢!若能为alpine打包就太棒了,毕竟firewalld需要D-Bus支持。虽然有awall但仍基于iptables,个人觉得配置略显笨拙。

      2. Foomuuri 已经接近完工了。

        我的意思是,像 GRE VPE/VXLAN/VLAN 或 IPSec 这种嵌套负载需要用原始 nft 编写才能在 Foomuuri 上运行,但它确实能用!

        不过我更欣赏 Shorewall 的设计思路,你的配置方案优雅地封装了 Shorewall 的机制。

        免责声明:我在Github维护vim-syntax-nftables语法高亮库。

    12. > 针对Docker的常见陷阱在于:容器运行时可能绕过防火墙规则自行开启端口。根据配置情况,原帖中的防火墙规则可能无法阻止Docker开启入站端口。

      这真是个好消息。我曾追踪过GitHub上相关公开问题,但始终未获满意解决方案。此前关于“StrictForwardPorts”的讨论可参考:https://news.ycombinator.com/item?id=42603136

    13. 不过UFW和Firewall-CMD在此场景下都只是使用iptables。真正的升级在于转向nftables。我知道下一步还需学习eBpf,但目前nftables更易理解且便于掌握——尤其在移除iptables相关代码后。不过从技术层面讲,nftables仍基于netfilter。

      顺带一提,ufw支持nftables。真正的启示在于:编写自己的防火墙并采用非许可模式——然后用CaC模板化这些配置。

  2. 这属于“React2Shell”漏洞CVE-2025-55182的问题吗?有趣的是此事几乎无人关注,仿佛这类漏洞理所当然。受影响版本追溯至一年多前,这意味着过去12个月部署过Next.js应用的开发者,其网站很可能已沦为百万节点僵尸网络的一员。而所有建议无非是“用Docker”或“装防火墙”。

    此刻我甚至不知该如何评价、思考或感受前端生态。我正考虑放弃以“Web应用”生态为核心的职业发展,转而申请需要C技能的岗位。比起前端领域层出不穷的新潮技术,C似乎更容易理解。/吐槽结束

    1. 近几年前端技术迭代速度明显放缓。当前主流Web应用栈已固化五年之久:Next.js(9岁)、React(12岁)、Tailwind(8岁)、Postgres(36岁)。我并非推崇这个栈,只是它已成为行业常态。

      回溯2000年代末至2010年代初,我们经历了原型框架→MooTools→jQuery→Backbone→AngularJS→Ember→React的更迭,短短六年间每年都有新框架登场。若想抱怨潮流更迭,不妨看看AI开发领域——那才是真正的轮番上阵。

      1. 我记得那段日子。说实话真是筋疲力尽。虽然有趣,但确实令人疲惫。如今能找到一套“足够好”的栈来处理大多数事情,感觉很棒。

    2. 你完全可以不碰当周最火的JS框架就写出Web应用。我从来没碰过那些试图模糊前后端界限的框架。

      后端选个可靠的技术栈(.NET、Java、Go等),前端随心所欲。瞧,漏洞减少,人员流动也变少了!

    3. 我的Java网站仅使用HTML/CSS/JS(原生JavaScript),不依赖任何框架。

    4. 我最近频繁听到相关讨论,因为当时部署了约100个Next前端。不过我未使用服务器端组件,因此不受影响。

      1. 据我理解,即使不使用服务器端组件,系统仍存在漏洞风险。

        除非您运行的是静态HTML导出——例如:未使用Next.js服务器,而是通过Nginx等工具提供服务

        1. 没错,关键在于它明确指出:

          若您的应用 React 代码未使用服务器端组件,则不受此漏洞影响。若您的应用未使用支持 React 服务器端组件的框架、打包工具或插件,则不受此漏洞影响。

          https://react.dev/blog/2025/12/03/critical-security-vulnerab

          因此,若您的后端支持RSC(即使未实际使用),仍可能存在漏洞风险。

          GP声称仅发布了前端组件,但这可能意味着很多问题。

          编辑:链接

          1. 他们可能指的是Vercel的另一项漏洞——由于工程实践不佳,该漏洞允许任何人相对轻松地绕过其身份验证机制:

            https://nvd.nist.gov/vuln/detail/CVE-2025-29927

            加上最近这个React漏洞,可见其企业文化根本不在乎客户,只顾追逐潮流来满足贪婪的职业野心。

  3. 补充说明:若需极轻量级容器,可通过设置 –cpus=“0.5”(或在docker compose中使用cpus:0.5)严格限制容器CPU占用。这种隔离机制能有效防止单个失控容器影响系统其他部分——无论其是加密货币挖矿恶意软件、DDoS攻击尝试,还是异常运行的服务/软件。

    1. 另一种方案是在容器支持此配置的前提下启用只读模式运行容器…这将大幅缩减潜在攻击面。

      1. 从未研究过此方案。我预计多数镜像在此配置下会运行失败。还是说我过于悲观了?

        1. 若未作额外配置,多数镜像确实会失败。在Kubernetes中,通常可通过将emptyDir卷挂载到需要可写权限的特定目录(如常见的/tmp目录)来规避此问题。若目录既需可写权限,又需包含基础镜像中的内容,通常做法是:先将emptyDir挂载到/tmp,在initContainer中将内容复制进去,再将同一个emptyDir卷挂载到运行时容器的原始位置。

          遗憾的是,无法将这些emptyDir卷设置为noexec模式[1]。

          我认为Docker中对应emptyDir卷的实现方式是--tmpfs参数。

          1: https://github.com/kubernetes/kubernetes/issues/48912

        2. 效果时好时坏…有时需要将/tmp或其他数据目录设为可写…某些镜像因首次运行时的初始化步骤而无法正常工作。这取决于具体情况…但多数自建应用确实能通过限制写入权限或完全禁用写入来实现运行。

        3. 只读模式和无root权限是我对Docker容器的两大要求。多数镜像无法只读运行,因为它们会在启动脚本中创建用户。由于我需要唯一UID来隔离挂载目录,这种行为毫无意义。最终只能通过封装或复制Dockerfile来实现合理运行。

          拥有如此优秀的分层构建系统和挂载点机制,Docker竟将只读模式作为事后补丁,实在令人费解。

          1. 我倾向用docker-compose管理容器运行,特别是配合.env配置文件——既便于存储在仓库中,又易于定制且能设置合理的默认值。

            1. 确实如此。我也用docker-compose。但若Docker镜像试图更新/etc/passwd、强制使用硬编码UID,或在运行时而非构建时执行install.sh脚本,这些方案就失效了。

        4. 取决于具体应用场景。Nginx不支持此方案,但valkey可行。

    2. 确实如此,但更常见的情况是初始配置后,后期引入突发性高负载接口导致不必要的限流。熟悉应用性能特征固然重要,但实际操作中容易忽视这一点。

    3. 虽然这是个好主意,但我不禁思考:这样做是否会让入侵行为更难被察觉?毕竟相比所有CPU都满负荷运转的情况,CPU使用率的小幅上升能引起多少人/监控系统的注意?

    4. 无论采用何种容器方案,软硬内存限制都值得纳入考量。

    5. 这确实是个关键提醒!感谢指出!

    6. 需要注意的是,Docker 基本上是无状态的。因此,如果你在运行需要处理可疑用户输入(如图像、视频或更关键的 PDF 文件)的程序,建议将其部署在独立的虚拟机上,每小时轮换 Docker 容器,每 12 小时轮换虚拟机,即便如此,仍需警惕系统被入侵导致机密泄露的风险。

      1. 既然能入侵一次,一小时后就能再次得手。我倾向于认为这种简单的循环机制对持续性攻击者效果甚微。

      2. 多数风险可通过在LXC容器中运行Docker(如Proxmox方案)缓解——其隔离性远超原生Docker,本质更接近独立虚拟机运行模式。

        1. 可惜在PVE9中未经深度修改根本无法实现

          1. Illumos曾拥有在监狱区和区域内运行容器的出色架构…不知这些技术是否曾融入Linux世界。若突破容器限制,你仍会处于更严密的监狱区环境中。

  4. 居然不用防火墙!真够大胆的。Hetzner允许配置独立于主机的防火墙,建议你添加这个作为深度防御措施——这样就算ufw配置失误也能补救。我个人就是这样只允许SSH从家庭IP访问;外出需要远程操作时,直接登录Hetzner官网临时修改规则即可。

    1. 多数情况下防火墙收效甚微。诚然,当你操作失误甚至不清楚服务监听端口时,它能充当最后一道防线,但若未配置防火墙,其存在与否的差异微乎其微。

      真正关键的是:你是否意识到正在运行的软件存在广为人知的远程代码执行漏洞?这些软件甚至未采用成熟的沙箱机制自我隔离。

      作者将Docker奉为救世主的论述,恐怕只是侥幸之谈。

      1. 作者提及其他暴露在互联网的服务(Postgres、RabbitMQ)扩大了攻击面。这些服务本身可能存在漏洞或配置错误。

        完善的安全防护需要多层防护。

        1. 但若必须暴露这些服务,防火墙便无济于事;若无需暴露,则根本无需防火墙,只需配置服务不监听非本地接口即可。

          1. 这听起来简直是自掘坟墓的绝妙方案。

            直接用防火墙就行。

            1. 我不太明白你的意思,在我看来真正危险的是对服务器监听的服务置之不理。

              防火墙只是临时配置错误时的防护措施,它绝不该成为服务与互联网之间唯一的屏障。

              1. 防火墙就是防护措施,仅此而已。就像汽车里隔离驾驶员和引擎的防火墙。

            2. 若你已将服务暴露于互联网却毫无头绪,请立即停止操作。选择监听接口是几乎所有系统的首要配置选项,若你因某篇垃圾博客“教程”而设置0.0.0.0,那你根本不具备让机器暴露于互联网的资格。

              1. “非专家勿碰”是绝佳的门槛把控策略,所幸这里是黑客新闻站,我们可以无视这些守门人!

                我建议大家大胆尝试,但务必控制风险。搭建一台不存重要数据的VPS,尽情玩耍后删除即可。

                我们都曾是“不合格的互联网使用者”,却依然勇往直前。

                你的玩具项目被黑了损失5美元信用点,不会有人因此丧命,过程中你可能收获颇丰。

      2. 刺耳的错误蜂鸣声响起,接下来你该说什么?“堡垒服务器是骗局”?

    2. 但若他们提供公共网络服务或需与外部系统交互,防火墙也无济于事。

      或许可以让应用服务器完全受防火墙保护,另设堡垒主机充当HTTP代理,同时处理入站和出站连接。但这种配置绝非易事,尤其处理出站场景时。

      1. 不,你说得对,我并非指防火墙能拯救他们,只是作为一般性建议。确实,运行opnSense等软件的第二台VPS能充当经济实惠的代理,这样就能完全隔离主服务器。不过这同样无法拯救他们——他们仍需将HTTP/S转发至主设备。

        1. 若部署防火墙阻断出站连接(通过代理白名单的连接除外),本可阻止恶意软件下载(因其通常通过远程代码执行调用curl/wget命令实现,而非直接上传二进制文件)及/或其与挖矿服务器的连接。

          1. 但实际运行防火墙时,又有多少人会正确配置出站过滤呢?

          2. 实践中这基本无法实现。防火墙后端的用户通常期望能与任意远程主机建立连接。

            1. 通过策略过滤HTTPS代理完全可行。详见https://laurikari.github.io/exfilguard/

              该模型下主机无需直接互联网连接或公共DNS访问权限。所有出站流量强制经由代理传输,使管理员能完全控制每台主机的连接目标。

              但实施过程并非毫无痛感:您必须维护允许访问的URL和HTTP方法白名单,分发可信CA证书,并确保所有软件均配置为使用该代理。

    3. 三十年Linux运维生涯中,唯一遭遇系统被入侵的情况,是当我在互联网暴露设备上运行了知名端口的程序。

      我清楚端口扫描器确实存在,但使用非默认端口的做法似乎能有效防范大多数安全问题。

      1. 这是极其糟糕的建议。非标准端口根本算不上防御措施,连最基础的防护都谈不上。

        1. 说得对。据我所知,Shodan付费版多年来就提供“非标准端口监听服务X”的搜索功能。唯一合理的推测是:如今任何像样的网络普查[tm]工具都已将此列为标准功能。

      2. 在Linux系统执行npm install、pip install…、docker pull…/docker run…等操作时,系统极易遭受入侵。

        我曾根据某些看似合理的网络帖子执行过几次docker pull操作,随后发现容器内的应用/脚本立即或数日后便连接至某些.ru域名网站…

      3. 我也这么做,但这仅是深度防御策略的一部分,其他防护措施仍不可或缺。

    4. 启用密码认证本身就很冒险。个人认为fail2ban并非必需,但因其普及度总被提及。

    5. 我不再为SSH设置IP白名单,但始终让SSH守护进程运行在随机端口,以躲避端口扫描器的侦测。

      这个做法已坚持多年,至今仍不确定它究竟是真正有效,还是徒劳无功的遮羞布。

      1. 只要明白这是依靠模糊性而非加密技术实现的安全防护即可。

        我认为这并非错误做法,只是与使用YubiKey等方案效果不同。

      2. 此举无法完全隐藏身份,但能减少日志垃圾信息。

        我的sshd仅监听VPN接口

    6. 我完全屏蔽了SSH,改用WireGuard访问服务器。若出现问题,可随时通过控制面板为我的IP重新启用SSH。但你的方案安全性同样可靠,或许只是稍逊几分便利性。

    7. 需说明的是,此功能仅限于他们的VPS服务,不适用于独立服务器。若通过服务器拍卖租用独立服务器,仍需自行配置防火墙。

      1. 独立服务器同样可配置外部防火墙;服务器配置中有专属选项卡。功能虽基础但实用。

    8. 没错。我所有服务器都部署在Tailscale之后。唯一暴露的是负责路由TCP(邮件)和HTTP的负载均衡器。该均衡器运行在Docker容器中,并配备完整防火墙(含Docker旁路规则)。每台服务器除内部防火墙外,还额外通过herzner防火墙进行防护。

      应用服务器运行Docker容器,镜像仅执行单一程序(无操作系统,无shell),并严格限制CPU和内存。多数应用仅需极少量临时存储空间,通常无需挂载任何文件。因此想在其中执行任何操作都难如登天。

      早年我曾运行Wordpress站点,每月都会遭遇各种方式的入侵。这让我获益良多,尤其领悟到应用本身常是威胁源——Wordpress的每个插件都是攻击载体。更糟的是某些脚本语言(包括JS)能轻易跳转实例重写运行代码。这促使我转向Go语言:编译后的代码即为运行代码,绝无例外。

    9. 说真的,fail2ban太牛了。或许该写篇日志记录服务器遭受的无数次攻击尝试。

      1. 我曾设想fail2ban唯一可能发挥作用的方式,是将某台服务器的IP地址收集后应用于整个服务器集群——我确实这样运行过一段时间。但最终我意识到它本质上只是让日志文件更干净,因为按定义它只处理未成功的攻击/尝试记录。我们不该纠结日志里的攻击尝试,而应让软件自行处理。

  5. > 之前看到的Reddit帖子?那家伙彻底被攻陷了,因为他的容器以root权限运行。恶意软件能:[…]

    但事实真是如此吗?我理解的是:即便以root权限运行Docker容器且容器被100%攻破,攻击者仍需利用Docker本身的漏洞才能“攻击”宿主机,还是说我漏掉了什么关键点?

    1. 虽然这点没错,但普遍的安全立场是:Docker并非安全边界。切勿将其视为安全边界。它仅提供_进程级_隔离。若需更强的安全保障,可采用完整虚拟机(KVM/QEMU)、gVisor[1]等工具限制容器化进程的攻击面,或使用专为多租户设计的Firecracker[2]等方案。

      问题的核心在于:进程隔离无法抵御特定类别的攻击向量,也无法防范因配置错误导致的意外风险。Docker固然优秀,但切勿将其视为运行不可信代码的沙箱。

      1. https://gvisor.dev/

      2. https://firecracker-microvm.github.io/

      1. 我常听到“Docker并非安全边界”的警句,据我所知这曾是Docker项目早期的官方立场,但事实果真如此吗?

        当然,若存在内核漏洞便能突破边界(gvisor在一定程度上缓解了此类风险),而针对行锤攻击/内存时序攻击似乎尚无有效防护手段(不过这类攻击似乎并不常见)。除此之外,主要的安全配置失误似乎在于过宽的卷绑定(例如允许容器内部访问Docker控制套接字,或是将根目录挂载到容器内部这类明显愚蠢的操作)。

        我是否遗漏了什么?

      2. 这确实是个关键点……但我想99%的Docker用户都将其视为沙箱环境并如此使用。

        1. 这种认知并非毫无依据。十多年来我们始终将Docker作为安全改进方案进行推广。它确实提升了安全性,只是实际效果远不及许多布道者宣称的那般显著。

          1. 这得看你接触的是哪类人群。在我所处的圈子里,Docker从未被当作安全方案来推广。

        2. 绝非99%。许多人专门为Docker运行着虚拟机管理程序加虚拟机。

          攻击者现在需要先攻破Docker漏洞,再攻破虚拟机漏洞才能触及虚拟机管理程序(且请注意:攻破虚拟机不等于攻破虚拟机管理程序)。

          1. 赞同——这在Proxmox这类主机服务商中相当普遍。我用LXC对容器节点进行分区,特定场景下也会使用虚拟机。

            这种方案不仅能按工作负载划分主机资源,还能建立安全边界。虽然性能可能略有损失,但这种分区方式更符合我对工作负载的逻辑认知。最后,模板化和脚本化操作极其简单,维护成本极低——若需重大变更,只需终止LXC实例并重新配置即可。在此架构下,数据迁移几乎无需进行(或极其罕见)。

        3. 它能抵御意外攻击和操作失误(如sudo rm -rf /),

          但无法阻止恶意软件的深度渗透

      3. 虚拟机被视为安全边界,尽管通过足够研发其实并非如此。在虚拟机中托管Minecraft服务器尚可,但若与存储价值数十亿美元加密货币或军事机密的服务器共存则风险极高。

        Docker原理类似但据称更脆弱。

        两者都存在不易察觉的配置漏洞,可能导致安全边界被突破。

        1. 尽管通过充分研发可以突破虚拟机边界,但它们仍被视为安全边界。在虚拟机中托管Minecraft服务器尚可接受,但若与存储数十亿美元加密货币或军事机密的服务器共用同一物理机则风险极高。

          虽然我基本认同技术层面的论点,但未能理解此处的威胁模型。难道是某些外部威胁事先知晓重要目标紧邻防护较弱的目标?在我看来,国家行为体投入高昂研发成本去破坏业余爱好者级别的服务,只为期许能在主机虚拟机管理程序上发现更有价值的数据,这种做法似乎并不现实。

          一旦部署此类昂贵恶意软件,存在巨大风险——所有研发资金可能仅用于侦察阶段。

        2. 但为何有人会将军事机密或数十亿美元资产托管在同一平台?这推论有些牵强。

          1. 你忽略了关键点:当高价值目标与软目标毗邻时,逃逸行为就具有合理性;但在低价值场景下,虚拟机逃逸的研发投入并不划算

            1. 但若能大规模实施仍可能值得,比如控制数千台机器

    2. 首先,攻击者只需用CPU挖门罗币,这在容器内完全可行。

      其次,即便Docker容器配置完善,攻击者仍能以root身份调用内核。这固然是安全边界,但其实战可靠性远不及非root隔离机制或虚拟机间的隔离。

      第三,默认配置下容器内的进程可能占用大量内存(导致随机进程被换出磁盘或因内存不足终止)、消耗过多CPU资源,甚至填满磁盘空间。若将拒绝服务视为攻击手段,这正是其表现形式。

      第四,存在大量可禁用安全边界的配置选项,且许多在线指南会建议使用这些选项。在Docker中需要访问热插拔摄像头?嗯,除非设置–privileged参数否则无法实现——哎呀,安全边界就此失效。开发时尝试附加调试器并设置CAP_SYS_PTRACE权限?同样绕过了安全边界。诸如此类的情况比比皆是。

    3. 要实现这种安全防护,必须使用用户命名空间——在未启用用户命名空间的容器中以root身份运行是不安全的。没错,突破容器通常需要其他漏洞或配置错误,但容错空间几乎为零(例如若在容器中添加CAP_SYS_PTRACE权限,突破容器便轻而易举,且容器运行时对此毫无防御能力)。过去十年间几乎所有容器突破事件都因用户命名空间而受阻。

      遗憾的是,用户命名空间至今仍非 Docker 的默认配置(尽管导致其使用体验糟糕的核心问题早已解决)。

    4. 若容器以特权模式运行,只需通过 Docker 套接字与宿主机守护进程通信,即可创建直接访问根文件系统的新容器,随后便能以 root 身份修改任意内容。

      1. 需特别注意:若运行 docker-in-docker,Docker 可能无法构成安全边界。可在任意 dind 容器(尤其是 devcontainers)中尝试以下命令:docker run -it –rm –pid=host –privileged -v /:/mnt alpine sh

        我不同意其他评论者关于Docker不构成安全边界的观点。只要不主动禁用边界(例如通过--privileged参数启动容器),它就是有效的防护机制。我在此处撰文探讨了开发容器的安全替代方案:https://cgamesplay.com/recipes/devcontainers/#docker-in-devc

        1. 容器永远不是安全边界。即便你正确配置了所有参数,规避了所有陷阱,还祈祷不会出现影响“正确配置”容器的逃逸漏洞,它们也只能算是安全边界的粗略近似——或许能满足某些使用场景,但绝不能替代硬件级虚拟化。

          据我所知,唯一尚未认清此事实的知名企业是微软——其屡次因容器隔离机制引发的多租户系统漏洞而颜面尽失,正是明证。

          1. 虚拟机永远无法构成安全边界。即便你完美配置、规避所有陷阱,还祈祷不存在影响“正确配置”虚拟机的逃逸漏洞,它们也只能粗略模拟安全边界——或许满足某些场景需求,但绝非独立硬件的合格替代品。

            层层嵌套,永无止境。

            1. 确实,在某些(罕见)场景下物理隔离能提供更合适的安全级别。若需折中方案,可采用配备单租户NUMA节点的虚拟机。

              但对于典型场景而言,虚拟机(VM)是实现真正安全隔离边界的最低要求,因为其攻击面要小得多。

    5. 容器逃逸确实存在。关键在于攻击者是否已利用该漏洞,以及风险程度如何。

      你是否存储着价值数百万美元的加密货币/敏感数据?最好假设机器和数据已被入侵,并据此制定应对方案。

      若这只是处理低价值事务的玩具服务器,即使遭遇容器逃逸零日攻击也仅会造成些许尴尬?那你大概率无需担忧。

      此类攻击本质是为挖矿设计的大规模自动化攻击,极少有人会实际登录你的服务器。因此清理容器即可。

    6. 认为根容器能与Docker守护进程通信并启动额外容器…还能挂载文件系统的其他部分等。不过对此不太确定

      1. 撇开Docker和内核的无意漏洞不谈,它必须具备访问Docker API的权限(通常通过绑定挂载Unix套接字实现)。而获取Docker API访问权限等同于在主机上拥有root权限。

        1. 糟了。我一直在用Docker为测试中的交互项目安装NPM模块。我原以为Docker会阻断对底层主机(我的电脑)的访问。

          感谢提醒——但现在…该如何应对?

          1. 若未挂载docker.sock或其上级目录(默认为/或/run),也未以–privileged模式运行容器,从这个角度看应该没问题。为更稳妥起见,我仍建议使用非特权用户运行的无特权容器或虚拟机。Qubes(https://www.qubes-os.org/)是个不错的选择,尽管操作体验稍显笨拙。

            * 但若习惯绑定挂载,这些方案会带来麻烦

            编辑:这绝非全面指南,但出于某种原因我必须特别强调:切记不要将.git目录设为可写!对.git的写入权限等同于任意代码执行权限——因为执行git命令的用户拥有该权限。

          2. 正如兄弟提到的,除非你或运行时显式挂载了docker套接字,否则这种特殊场景不应影响你。

            你仍需加强防护措施。除了启用“rootless”模式(即在宿主机以非特权用户而非root运行容器运行时)外,还应确保在容器内以非特权用户运行npm/node。我仍看到许多人默认在容器内以root运行,因为这是多数镜像的默认设置。原帖作者也提及了这一点。

            对于无特权的 Podman,可通过以下命令以当前用户 UID 运行并映射挂载点/卷的所有权:

                podman run -u$(id -u) --userns=keep-id
            
          3. Podman 默认机制能更安全地实现此操作,建议尝试使用。

    7. 确实存在漏洞,但许多Docker容器配置不当或拥有过高权限,导致逃逸风险。

      此外,若系统已遭入侵,可能存在隐藏于文件系统的rootkit,此时仅靠lsstat命令无法确认文件是否存在。

      1. > 但许多Docker容器存在配置错误或不必要的权限赋予,导致逃逸风险

        坦白说,此论断需要佐证。除非你直接授予容器写入/usr/bin等主机运行二进制文件的权限、重构整个/etc目录、访问Docker等套接字,或是采取其他极端操作——即便最不专业的Docker用户也不可能这么做——否则这种情况极其罕见。

        当然容器本应合理限定作用域,但人们总幻想某种神秘的容器逃逸0day漏洞会攻击到他们那些配置正常的Minecraft服务器或个人博客——明明已采用合理挂载、非管理员权限等措施。你没那么特别。

        1. 作为runc(Docker使用的运行时)维护者,若您未使用用户命名空间(绝大多数用户正是如此),我认为您的配置存在安全隐患。

          更令人震惊的是,大量教程竟毫无警示地推荐将docker.sock绑定挂载到容器中(某些教程甚至建议以“只读”模式挂载——这更可笑,因为该操作毫无作用)。我大约八年前在Reddit上就对此发表过批评。

        2. 我接触的半数厂商软件都要求挂载主机设备、添加权限或以特权模式运行容器,只因外包给最低价供应商的开发者连容器是什么都搞不清楚。我怀疑连极少数客户都不会对此提出异议——显然只有我所在的公司会率先对此提出质疑。

        3. 我见过许多文章直接写-v /var/run/docker.sock:/var/run/docker.sock却毫无警示

          1. 这种配置的预期使用场景是什么?

    8. >这仍需Docker存在漏洞才能“攻击”宿主机,还是我漏了什么?

      并非必须存在漏洞本身。例如桥接适配器就能实现很多操作——几年前就发生过类似事件:有人在容器中获取root权限,由于容器使用桥接适配器,他成功拦截了GCP账户信息更新的流量。

    9. 拥有root权限的Docker容器在主机上也具有root级权限,因为两者的用户ID都是0。因此若存在管理松散的绑定挂载点,Docker用户便能在容器外部创建0777权限文件,此时攻击链已基本成型。更糟的是,若有人为“确保运行”而使用–privileged参数启动容器,再因操作失误将容器暴露至互联网,后果将不堪设想。

      1. 能否进一步说明?Docker外部的0777文件不仍会在容器内执行而非主机上吗?

        1. 我认为其意指可创建容器外部可访问的可执行文件(甚至可能是setuid root权限的),根据路径设置,可能诱使用户在主机上运行该文件。

          试想将该可执行文件命名为“ls”或“echo”,当用户路径中包含“.”(这就是为何不该设置此路径的原因):只要在此目录执行“ls”命令,你就运行了被篡改的代码。

          当然还有其他方式让该可执行文件在主机上运行,这只是简单示例。

          1. 另一种手段是枚举目录查找常用脚本名称,然后覆盖你的脚本。更隐蔽的做法是将恶意代码追加到文件系统中现有脚本末尾——从此每次运行该脚本时,恶意代码都会搭便车执行。

            不过若我在Linux系统编写此类脚本,会优先抓取$(hist) $(env) $(cat /etc/{group,passwd})…的内容,再遍历/usr/bin/ /usr/local/bin/及XDG_{CACHE,CONFIG}目录——这些位置通常存有明文凭证。

            $HOME/.{aws,docker,claude,ssh}

            本质上攻击者只需熟悉操作系统结构。正是通过枚举这些目录的脚本,他们才得以在root权限容器内写入0777权限的恶意脚本。

            1. 若开发环境支持,建议采用无发行版容器或空基底容器,并尽可能启用只读模式运行。

              Go和Rust语言在这种受限环境下的适应性通常优于其他选项。

    10. 攻击途径可能是Docker漏洞或内核级漏洞。非虚拟机容器会共享内核资源。

  6. 约二十年前,PHP网站曾遍地遭黑。

    如今JS网站正遍地沦陷。

    JS已沦为它曾试图取代的存在。

    开发者本色依旧,倒也令人欣慰。;)

    1. 简直像在说…问题根本不在工具本身 😛

  7. 未经人工校对。多次声称漏洞与Puppeteer相关。幻觉!

    “CVE-2025-66478 – Next.js/Puppeteer RCE)”

    1. 首段就明确说明本文主要转录了Claude对话记录。

      1. 那是后期添加的说明。但未能修正原文错误。更合理的表述应是:“本文由大型语言模型生成,可能存在诸多未被发现或修正的错误。”

  8. 哈哈哈,原帖作者可能深陷麻烦——取决于容器里存放了何种凭证/数据。我本回复了子评论,但觉得还是直接回复原帖更妥当。

    从根容器出发,根据卷挂载情况及容器获得的权限,攻击者会遍历主机目录查找常用脚本名称,进而覆盖其中某个脚本。更隐蔽的做法是将恶意代码追加到主机文件系统中现有脚本的末尾。从此每次运行该脚本时,攻击者的代码便会搭便车执行。

    另一方面,若我在Linux系统编写此类脚本,会优先抓取$(hist) $(env) $(cat /etc/{group,passwd})…等内容,再遍历/usr/bin/ /usr/local/bin/及XDG_{CACHE,CONFIG}目录——这些位置通常存放明文凭证。$HOME/.{aws,docker,claude,ssh} 目录同样关键。本质上攻击者只需熟悉操作系统结构。而能被植入的0777权限脚本,正是攻击者利用root权限容器写入的。

    1. 幸运的是,Docker 中的 umami 采用高度隔离设计。所有数据存储在卷中,数据库运行于独立容器。最大风险在于数据库凭证。默认配置无需挂载卷,因此无需担忧。该容器以无特权模式运行,无额外权限。据我所知,该容器甚至未安装 bash,部分尝试运行的漏洞利用脚本因缺少 bash 环境而失败。

      删除并重建容器会清除所有关联状态,因此操作后基本无需担忧。

      1. 可尝试串联其他漏洞利用——即便默认非root运行,仍可能造成重大影响。

    2. 幸运的是该容器内仅存放Umami运行所需文件,完全不涉及凭证。不过感谢提供情报!

  9. 过去数月我与某GPU安全公司合作…可以明确指出:云服务商(普遍而言)并不将安全视为优先事项——甚至常认为这不属于其职责范围。多数服务商甚至缺乏检测GPU是否遭入侵的能力,还指望客户自行承担风险。

    而企业却以为云服务商在把关…总之这是个现实问题。

    1. 我可以明确告诉你,新型云服务商(普遍而言)并不将安全视为首要任务——甚至常常不认为这是他们的责任。

      AWS在其《共享责任模型》页面[0]中明确阐述了这一点:

      若您运行过时且存在漏洞的软件,云服务商无义务为您提供保护。他们无需阻止加密货币挖矿程序在您的实例上运行。即便防火墙服务也非其责任范畴——尽管主流供应商至少提供某种形式的防火墙(如AWS安全组和访问控制列表)。

      所有这些都属于客户的责任。供应商应保障云平台本身的安全性,而客户则需负责云平台内部的安全防护。

      [0] https://aws.amazon.com/compliance/shared-responsibility-mode

  10. 最近那些门罗币挖矿程序正趁React 19存在漏洞之际四处安装。我遇到了完全相同的问题。

    1. 超爱挖矿类恶意软件——它们相当显眼却几乎不造成损害。本质上就像无需管理的漏洞赏金计划:既省去繁琐的报告流程,又只需在漏洞被发现时支付几美元电费。

      只要部署了完善的网络或进程监控,这类恶意软件往往能被及时发现——而那些存在漏洞的软件本身,或是更隐蔽危险的恶意程序,反而可能被忽视。

    2. 我不得不彻底重置运行Umami服务器的Oracle云实例。它遭到了攻击。正好借此机会升级版本并更新所有备份系统等。在返回500错误期间丢失了几小时的数据。

  11. 我不会再信任那个启动镜像或存储设备,为了安心我会彻底清除它。

    话说回来,你有这台机器的镜像或容器镜像吗?我挺好奇的。

    1. 确实考虑过直接干掉它,不过我打算先用枪指着它观察几天,以防万一。

      幸运的是数据库备份正常,所有持久化数据都备份到了S3。我估计一小时内就能重建新实例。

      可惜没留镜像。当时差点没先调查就直接把整台机器扔进太阳里!

      1. 启用连接跟踪(若未开启)并持续监控连接记录。这是发现异常行为的好方法。

  12. 当前运行容器化自托管工作负载的最佳安全实践是什么?是采用无守护进程、无特权的Podman容器吗?

    或许还能借鉴Renovate的机制更新容器镜像,比如设置“minimumReleaseTime=7days”之类的参数?

    1. 无论是否采用容器化部署,检查运行项的依赖关系都是成功的基础。使用Snyk等工具扫描容器和仓库中的已知漏洞,及时发现异常。

      其次需以最小权限运行程序。遗憾的是,Docker及各类容器技术在此处实属反模式——它们优先考虑便利性,安全性能则退居次位。因此原帖作者本应以只读模式运行容器,严格限制资源配额,若非公共服务更应实施IP访问限制。

      另一种方案是采用Tailscale等工具,构建零信任加密访问模型。当然这不适用于公共服务。

      此外还有诸多其他措施。

    2. 永恒法则:

      • 绝不以root权限运行容器
      • 非必要绝不向互联网开放端口
      • 禁止容器外联互联网
      • 仅运行可信且理解的容器,拒绝网络上附带陈年漏洞和全套工具的垃圾软件
      • 定期审计容器、扫描漏洞、彻底清除

      我知道说起来容易做起来难。

      Podman比Docker默认更安全,OpenShift也是如此——不过对于简单自托管应用而言,这可能有些过度了。

  13. 加密货币问世后,犯罪分子牟利似乎成了主要结果。

    1. 我认为挖矿恶意软件对社会是净收益。与其让漏洞服务器闲置,我宁愿它被挖矿恶意软件利用。若遭挖矿恶意软件入侵,这几乎不费我一分钱,反而能让我在真正恶意攻击发生前发现漏洞,同时为漏洞发现者提供微薄回报。

    2. 犯罪分子和色情产业几乎总是新技术的早期采用者。无论好坏,他们的应用案例都是概念验证,若取得成功,便会被更正规的行业扩展和发扬光大。

      例如:互联网。
      例如:点对点技术。
      例如:视频流媒体。
      例如:人工智能。

      1. 新技术从色情犯罪领域转向实际应用的平均周期有多长?超过15年吗?

        1. 这取决于监管措施对该技术的介入速度。

      2. 犯罪分子如何成为互联网、视频流媒体和人工智能的早期采用者?

        1. 并非如此,但某些人这么说能自我安慰。

    3. 电子邮件问世后,犯罪分子牟利确实成了主要结果。

          1. 这些邮件几乎全被归入垃圾箱。加密货币产生的收益和人们从中获取的价值,没有半数涉及犯罪。我认识的人里,没有一个用门罗币做过合法生意。

    4. 还有快速的恶意软件检测。

    5. 因为加密货币自诞生起就是非法的。我所有获得加密项目融资的朋友,在奥巴马-拜登执政期间都遭遇了银行账户冻结、罚款、监禁等处罚。直到特朗普政府时期,尽管缺乏法律框架,风险投资、ETF、稳定币结算和跨境监管才开始被“接受”。

      所以… 加密货币本身非法,使用即构成事实上的犯罪。

      此外,就具体案例而言,这是我见过最优秀的漏洞赏金计划。运行门罗币节点触发每日预算上限本不算糟糕…相比窃取数据库凭证转卖给最高出价者要好得多…所以加密货币反而改善了现状。

      1. 对那些在该欺诈案中没有经济利益的人来说,当然不意外。

  14. 有趣的是今天看到这个帖子,我也在Hetzner租用服务器(虽然觉得无关紧要),昨天发现有人安装了门罗币挖矿程序。

    幸运的是,我安装的软件[1]运行在Incus环境下的LXC容器中,入侵从未突破应用环境。容器本身还设置了低CPU优先级,因此直到尝试访问页面时才发现异常——页面根本无法加载。

    我简单检查了一下,发现似乎在root用户下添加了SSH密钥,还安装了某种远程管理代理。这个容器运行的是Alpine系统,因此在关闭实际Web应用程序后,通过简单的ps命令输出剩余进程,就能轻松识别出不属于该环境的进程。

    最终我直接清空了容器,但仍保留了备份以备日后(大概率不会)深入排查。这次经历让我学到几个实用技巧:

    – 务必假设系统可能被攻陷,确保环境隔离且资源受限(按量付费云用户请注意)。

    – 务必建立快照和备份机制。我采用Incus每日ZFS快照方案,使入侵前的系统回滚变得轻而易举。

    – 虽然理想状态下应销毁所有受感染设备,但根据威胁程度,回滚系统、锁定设备并升级也可能是可行方案。

    关于挖矿程序本身:

    – 从其配置文件可见,该程序实际并未正确配置。这表明攻击者可能执行某种基准测试,若系统“不值得”投入资源,便会悄然保持入侵状态——他们仍可利用该系统达成其他目的。

    – 攻击者未尝试文件系统混淆,这或许是我能发现它的唯一原因。/root目录下竟散落着多个包含“monero”字样的文件夹,这种痕迹本可轻易隐藏。

    – 若攻击者未安装挖矿程序,仅悄然入侵系统并放任原有进程运行(或更合理地设置CPU优先级),我可能永远不会察觉此事。

    [1]: https://github.com/umami-software/umami

  15. 我的配置类似,但额外采取了以下安全措施:

    – 使用Hetzner防火墙(因ufw与Docker兼容性差)仅开放443端口公共访问。

    – 自建OpenVPN访问所有私有端口,另部署Wireguard实例作为备用VPN。

    – Cloudflare Access默认保护*.coolifydomain.com。这本可保护楼主的Umami配置,因仅楼主能访问Umami控制面板。可在Cloudflare Access中创建绕过规则,通过IP或域名允许其他系统访问。

    – Cloudflare Access规则仅允许通过VPN IP(或向指定邮箱发送一次性密码)访问内部管理路径(如 /wp-admin/)。

    – 在Coolify的docker-compose文件中添加Traefik标签,为无法置于Cloudflare Access后端的内部服务(如自建Prefect)启用基本认证。此举还将在攻击者看到Umami应用前增加登录验证界面。

    – 前端仅部署在Vercel或Cloudflare Workers,后端API部署在Coolify服务器。由于应用路由解耦,两者均确认从未受影响。

    – 最后,服务器每5分钟运行一次Bash定时脚本,监控资源使用情况。当消耗量超过设定阈值时,通过Pushover向我发送警报。仅靠安全措施远远不够,监控与预警同样不可或缺。

    即便采取所有这些措施,仍会存在特殊情况。这是自主托管的局限性,但同时也是极大的自由。

  16.   $ sudo ufw default deny incoming
      $ sudo ufw default allow outgoing
      $ sudo ufw allow ssh
      $ sudo ufw allow 80/tcp
      $ sudo ufw allow 443/tcp
      $ sudo ufw enable
    

    作为iptables用户,这个命令顺序让我感到不安。过去我常因先封锁再添加例外而把自己锁在服务器外。不过这里不同,最后一条命令会立即生效…

    1. 我也遇到过这种情况:先拒绝所有入站请求,正准备允许SSH时,SSH连接突然断开 🙂 幸好能通过服务商的虚拟机控制台恢复实例。

  17. 抛开防火墙和最佳实践不谈,我建议直接把所有管理相关操作都放在Tailscale(或类似工具)后端,包括SSH。Hetzner允许你在公共IP关闭SSH后,仍可通过控制台终端访问——即使Tailscale上的SSH失败也能接入。网站相关操作也该采用类似策略。博客和公共网站部署在公共地址,管理操作则通过Tailscale进行。若配合Let’s Encrypt妥善配置,甚至能为私有资源设置美观的主机名。

  18. 干得漂亮。

    正是这类案例让我拒绝使用VPS。

    我当然能搞定(过去也做过),但顶多算个平庸的管理员。

    我宁愿付费请专业人士打理我的主机。

  19. 有趣的是,近期转向自建解决方案的趋势正引发人们重新审视自建系统带来的安全隐患。再这样循环下去,又将陷入恶性循环!

    1. 什么趋势?我看到的只是进一步的集中化:

      搜索引擎试图通过牺牲小型甚至个人网站来改善低质量搜索结果。餐厅乐于只出现在一个平台上:谷歌地图。既然能在上面展示,还有人上传菜单图片,谁还需要昂贵的网站?(最好是旧版本,这样价格看起来更便宜,还能避免虚假宣传的指控。)开源社区使用Github,有时也用Gitlab或Codeberg,而不是搭建Forgejo(我自己托管了大量项目,但注意到社区效应确实存在,也逐渐远离了自建代码仓库)。最妙的是项目将Discord聊天群作为文档和bug报告“表单”。注重隐私者集体使用Signal,而Matrix至今仍像我初闻时那样小众。那些仅因可下载就被冠以开源之名的二进制文件,都能在Hugging Face找到——据我所知,连大公司也只用这个平台。部分小型项目可能托管在Github,但我尚未见过自建托管的案例。静态网站托管在GitHub Pages等平台,后端则部署在Firebase。个人及小型企业放弃NAS设备,转而使用OneDrive或iCloud等云存储服务。部分高级用户会将文件存放于Backblaze B2。而初涉自主托管的新手们,越来越多地借助中继服务器访问自有网络——并非出于必要,而是为规避端口转发或配置内部服务私有访问的麻烦。安防摄像头正是典型例证:过去需安装设备、设置密码并转发端口才能远程监控。如今人们期待设备插上电源后“自动运行”,无论身处何地。这种依赖谷歌/亚马逊服务(且允许其监控所有数据流)的便利性被广泛接受。更不用说网络形态的消亡:人们不再按传统方式(超链接页面)使用网站,而是将大型语言模型作为一站式服务终端。

      并非说存储、私密聊天等服务的便利性提升、易用性增强及由此带来的普惠性必然是坏事,但这种趋势在我看来与你所认为的截然不同。

      过去1年、5年乃至10年间,我实在想不出任何自建服务比例持续上升而非下降的案例。

      若你看到分布式互联网的曙光,请务必分享——我感觉自己正成为朋友圈里最后一个坚持自建服务的人

      1. 虽然进展缓慢,但确实有人正逐步转向更去耦合的互联网。问题在于你仍然必须使用Cloudflare(或任何HTTP代理),这是任何希望离线运行的服务都无法规避的基本需求。

        我曾遭受过据称超过10Tbps的攻击,若没有第三方防护服务,根本无法想象如何应对——仅传输协议每年就需耗费数百万美元。

        虽然越来越多软件试图扭转这种局面,但正如https://thingino.com/所言:开源项目充斥着饿死的开发者(没人愿意为开源项目捐款)。

  20. > “不再暴露PostgreSQL端口,不再向互联网开放RabbitMQ端口。”

    天啊。我依然建议重建服务器。这种配置在2025年绝对_不_安全。该系统极可能已被精心设计的持久性感染程序彻底掌控。

    1. 此外,他们显然在同一主机上为其他用户运行物联网平台,该平台不仅能可视化传感器数据,还能触发(市电供电)设备。

      正确做法是部署新服务器(你有声明式配置吧?),迁移纯数据(或更优方案是从最新备份获取数据),将受攻击机器断网进行全面审计。此举既能为未来防范漏洞提供经验,又能告知物联网平台用户其数据是否遭泄露。某些国家甚至有法律强制要求报告数据泄露事件。当然,本人并非法律专业人士。

  21. 这很奇怪。我在Chrome浏览器查看这篇博客时加载正常,但将链接发给同事后,他在MacOS的Microsoft Edge浏览器中尝试访问时,浏览器却显示红色页面并提示“该网站已被报告为不安全”(Microsoft Defender SmartScreen警告)。

    地址栏中的域名’jakesaunders.dev’被标记为红色文字。

  22. 同样的情况也让我吃了一惊——我之前完全没意识到自己运行的某个工具竟在使用Next.js。

    我注意到这件事,是因为赫兹纳转发给我一封来自德国联邦信息安全局(BSI)的邮件——他们显然扫描了所有德国境内的IP地址,排查这个Next.js漏洞。邮件里附着一张表格,列出了IP地址及其对应的CVE编号。

    他们提供的服务相当到位,在此特别感谢德国纳税人资助了我免费的漏洞扫描服务 😉

  23. 我虽非应急响应专家,但认为安全做法是:备份受感染机器镜像后关机,在干净机器上启动虚拟机,挂载受感染镜像为只读模式,再用干净操作系统镜像进行调查?

    假设恶意软件已篡改系统命令,可能利用内核漏洞欺骗用户隐藏行踪,因此切勿直接操作受感染系统?

    1. 除非IT安全是你的爱好,否则若公司基础设施受影响但你用“coolify”托管个人项目的服务器未受波及,或许还算幸运。

  24. 我对文章这段内容存疑,因其中存在多处错误信息,推测源自克劳德的妄想:

    > 测试方法如下:若主机存在/tmp/.XIN-unix/javae文件,则系统已遭入侵。若该文件不存在,则所见现象仅是Docker默认行为——容器进程虽显示在主机ps输出中,实则处于隔离状态。

    1. 运行程序的文件可在程序运行时被删除。若程序试图隐藏自身,它会在启动后立即删除/tmp/.XIN-unix/javae。该文件不存在并不能可靠地证明容器未被逃逸。

    2. ps命令显示的是程序控制的命令行。任何程序都能修改此处的显示内容,包括程序名称和参数。若程序试图隐藏自身,会将其改为显示login -fp ubuntu。这同样不是诊断问题的可靠依据。

    验证systemd单元和crontab是必要的。鉴于该恶意软件如此明显,它可能并未采用这两种隐藏手段,但仅靠这些方法可能无法检测到窃取信息的恶意软件。

    文章后文提出“编写自定义Dockerfile”的建议,其中包含一条无效建议(使用USER root不会影响容器安全状态)和两条与编写Dockerfile无关的有效建议。“编写自定义Dockerfile”并非有用的安全建议。

    1. > “编写自定义Dockerfile”并非有效的安全建议。

      我认为恰恰相反。此举能加深对应用程序运行机制的理解,并可缓解特定供应链安全漏洞。

      虽然认同其逻辑存在混淆,但我认为该建议本身仍有价值。

  25. 我认为SSH启用密钥认证和Fail2ban并非必要。Fail2ban仅在保留密码认证时才有效——不过我可能错了。

    1. 我该检查SSH日志了。

      我的直觉是:既然SSH服务器会报告可用认证方式,一旦机器人检测到密码认证已禁用,就会断开连接不再尝试。

      但我也知道机器人有时很蠢。

  26. 感谢这篇文章。它促使我检查服务器,还发现Docker容器里有异常活动。好眼光!

  27. 你可以免费在某个仓库运行Docker Scout,它会提醒你是否有项目使用Next.js且存在该CVE漏洞。AWS ECR的扫描服务也很实惠:9美分/镜像,1美分/复扫。即使是个人项目,持续扫描也值得考虑。

    [*] https://aws.amazon.com/inspector/pricing/

  28. > 测试如下:若主机存在/tmp/.XIN-unix/javae文件,则系统已遭入侵。若不存在,则当前现象仅是Docker默认行为——容器进程虽显示在主机ps输出中,实则处于隔离状态。

      /tmp/.XIN-unix/javae &
      rm /tmp/.XIN-unix/javae
    

    本文的LLM写作风格令人痛苦,且充斥着错误信息(Puppeteer真的与漏洞有关吗?)。

    1. 确实有道理,我请Claude帮忙是因为坦白说这超出我的写作能力范围。不过我是真实存在的。抱歉,会修改。

      1. 赞同其他人的观点:宁可读糟糕的人类写作。我并非针对你——这只是个微不足道的例子引发的普遍性提醒——但请不要发布超出你事实核查能力范围的文章。只写你真正了解的内容,当你需要推测或调查后仍有未解之谜时,请坦诚说明。(人总会犯错,但当今时代,那些充满自信且细节丰富的错误尤其容易传播。)

      2. 仅供参考——我宁愿读糟糕的人类写作也不愿看大型语言模型生成的内容

      3. 嗨杰克!文章很棒,等我近期改造自建服务器时会参考这些建议。不过我同意楼上评论——LLM的写作风格削弱了这篇本应精彩的系统管理员侦探故事,反而让我没兴趣继续探索你的网站。

        不过很高兴看到你开始更多亲自撰写文章!我完全理解写作的艰辛,自己网站上也有不少类似主题的文章存在冗长散漫的问题,但这没关系——只要持续练习,水平终会提升。

        期待尽快读到你的新作!

          1. > 我尝试手写https://blog.jakesaunders.dev/schemaless-search-in-postgres/部分,但觉得显得语无伦次。

            这篇文章本身并无问题。请继续保持你的写作风格,这正是读者所期待的。

            大型语言模型自有其价值。我发现让它们修正错别字和明显错误很有用,同时要明确指示它们不要改变文本的风格或语气——它们在这方面表现得极其出色。

          2. 这样读起来舒服多了,更能让人窥见你真实的思考过程。感谢分享,写得真棒。

    2. 已修正,抱歉之前信息有误。

      1. 原文仍写着:

        > 它从未逃逸。

        你并未证实这一点(至少从文章内容看)。你做了些合理的抽查,并确认/修正了对环境的理解。我同意它很可能没有逃逸或在主机上获得持久性,但你并未真正验证这一点。换作是我,我仍会彻底擦除主机并重新部署所有环境[0]。

        另外关于容器用户非root的论述仍存在误导性。容器内部用户、容器运行时用户以及容器是否具有特权,这三者是完全不同的概念,却被混为一谈。

        另请参阅我对防火墙的评论:https://news.ycombinator.com/item?id=46306974

        [0]:不必紧急中断所有工作处理此事,但下次有空闲时务必从容完成。这种恢复操作本身就是有益的演练,确保未来遇到真正紧急情况时能从容应对。相比实际验证主机是否受污染,此举反而能节省时间和精力。

        1. 我看到了你关于防火墙的评论,关于转义符的提醒确实正确。目前看来应该足够安全。经历黑客攻击又意外登上HN首页,今天真是漫长的一天。

          明天我会坐下来重写文章,并进一步检查容器。

          1. 重写文章前请部署新服务器。说真的,你似乎尚未掌握全面审计的技能。部署全新服务器才是上策。若工作量太大,这正是学习声明式系统配置的好时机。

            无论如何,这种事发生在你身上真糟糕!作为同为HN用户的拥抱,我深知这类问题会吞噬大量时间精力。敢于公开这类事件需要勇气,这对许多人都有帮助,值得称赞!

          2. 嘿,感谢你抽空分享经验并参与讨论。相信不少HN读者会和你一样从中受益!

            (听说下次写作你会避开LLM技术,这点很棒<3)

      2. 我注意到文中多次提及Puppeteer,但不明白它与Umami、Next.js及CVE-2025-66478有何关联。

  29. > 我还启用了UFW(早该这么做了):

    当你开放端口时,Docker会覆盖你的规则。

    切勿通过Docker开放端口。切勿在公开可访问系统上运行内部服务。

  30. 作者遗漏关键要点:为缩小攻击面,非必要公开的服务绝不应暴露在公共网络中。分析软件等系统可通过WireGuard轻松访问,甚至更简便地使用SSH作为SOCKS代理。

  31. 阅读部分评论后:这或许不言自明,但必须谨慎控制向互联网暴露的内容。听起来这个分析服务或许本应仅通过VPN(或类似mTLS等机制)访问。

    对于基础网站而言,不依赖后端架构才是更优选择。

    每个暴露的服务都会增加风险,需要额外投入精力维护。这意味着更多工作量。

  32. 这个Next.js漏洞将被广泛利用,因为攻击门槛极低。这只是开始。

    1. 本以为自己对Next.js的厌恶已达极限,没想到还能更深。它简直是JS生态圈里的SharePoint。

  33. 这种情况下,“窃取”你付费挖矿获得的加密货币会有多难?不过我猜这些黑客足够聪明,会将所有数据即时转发至C&C服务器来防范此类行为。

    1. 执行挖矿计算的节点无需访问支付钱包的私钥。

    2. 除非掌握钱包助记词,否则无法获取挖矿收益。顶多能替换目标钱包地址自行挖矿。

  34. 这恰恰说明蜜罐、反恶意软件组织和黑名单对安全防护至关重要。

    即便身为OWASP成员每日研读漏洞报告,人们仍容易误以为自己不受影响。

  35. 去年我也遭遇类似事件,肇因是某个被遗忘的SSH密码认证账户(如admin:admin)缺乏安全防护。

    至少我认为是这样,因为始终没查明确切入侵途径。

    挖矿程序以root权限运行,甚至当我执行ls命令时文件都被隐藏!当时完全摸不着头脑,直到用救援镜像重启VPS并挂载根文件系统后,才发现进程列表里显示的文件确实存在。

  36. 建议进一步强化出站防火墙规则。Umami容器是否需要主动建立连接?若非必要,可通过限制出站扫描能力来防范风险。

    此举还能防止敏感数据外泄。

  37. 类似的门罗币挖矿事件也发生在我位于interserv.net的某台VPS上——当时我忘记从基于网页的终端控制台退出某台VPS的root会话,直接关闭了浏览器标签页。

    现已修复:教训深刻。

    1. > 当我忘记从某台VPS的网页终端控制台退出root会话,却直接关闭了浏览器标签页时。

      这种操作本身不应导致会话被入侵,即要么存在其他漏洞(未注销延长了可利用窗口期),要么攻击事件完全无关。无论哪种情况,都应查明真实原因。

  38. 很遗憾您遭遇此事。

    但我想探讨其中的门罗币相关性。

    是否可将此视为门罗币安全性迄今表现稳健的佐证?

    1. > 是否可将此视为门罗币安全性迄今表现稳健的佐证?

      不。攻击者选择挖门罗币而非其他加密货币的原因并非匿名性。多数加密货币无法通过CPU进行(有效)挖矿,而门罗币(显然)可以。可能存在其他选择,但我推测它们要么每CPU秒收益更低(因价值不足),要么因知名度不足和/或设置过程繁琐,导致攻击者直接选择已知的默认方案。

      直接挖比特币毫无意义,你根本赚不到钱——因为要和ASIC矿机竞争。有些币种设计时就具备抗ASIC特性,这类币主要靠GPU挖矿。而门罗币(及部分其他币种)的设计目标是同时具备抗GPU特性(我认为)。你可以将其视为该特性(足够)有效的证明,仅此而已。

    2. 选择门罗币进行此类操作的核心原因在于其挖矿算法。开发团队投入大量精力多次迭代算法,确保其同时具备GPU和ASIC抗性。

      若用该服务器挖比特币,即使有人承担服务器费用,收益也近乎为零。

      但确实,门罗币在技术层面表现非常出色。

      1. Qubic团队不是成功攻击过门罗币吗?

        1. 他们试图发动51%攻击,最坏情况可能导致双花问题。但实际控制率从未超过35%。

          该攻击既未也无法破坏或削弱门罗币的隐私与匿名特性。

  39. 很遗憾听到你遭遇黑客攻击。

    我知道我们不该把容器当作安全边界,但听到这类黑客攻击无法突破容器的故事确实令人欣慰。障碍越多越好,我猜。

    1. 黑客终究是人。至少在接下来的十分钟里。

      若操作者无法提升权限,攻击便无从展开。

  40. 我的首要措施是改用Podman替代Docker,防止容器逃逸。Podman能实现真正的无特权运行且不干扰防火墙。其次我会尽可能禁用大写锁定。

    1. 运行Podman和无root模式下运行Docker有何区别?(除了Docker会干扰防火墙——显然楼主尚未意识到这点)。我明白Podman无需守护进程,但仅此而已吗?还是我遗漏了什么?

      1. 该运行时从底层设计就支持无守护进程和无root权限运行。他们还提供K8s运行时,其接口极其精简,仅满足K8s兼容性要求。

        但Podman与systemd的集成也相当出色。借助socket激活的systemd单元,可将套接字置于容器内部,完全无需为容器配置网络。即使需要容器网络功能,Podman团队也开发了用户空间网络方案slirp4netns,如今更有进阶方案passt/pasta。

      2. 我发现无根Docker比Podman兼容性更高。使用Podman时,我在mssql等场景遭遇过崩溃转储,而无根Docker未出现此问题。

        此外无根Docker不会像有根Docker那样绕过ufw防火墙。

  41. 若我没记错,Hetzner虚拟机默认未启用防火墙。若您来自默认设置不同的服务商,这可能带来隐患——您以为未对互联网开放的容器其实始终处于开放状态。双重防火墙失效:既绕过了ufw,外部防火墙也未配置。

    必须定义防火墙策略并绑定至虚拟机。

  42. 有人知道如何在容器内部直接列出该容器运行的进程吗?

    若容器内部能查看所有进程,这难道不是设计缺陷?此类信息可能为逃逸提供便利。

  43. 若未启用–privileged参数且未进行过度挂载,“user root”权限是否足以实现容器逃逸?抑或仅增加了攻击面,使攻击者在存在其他漏洞时可能逃逸?

    1. 逃逸沙箱需利用containerd或内核漏洞,而沙箱中的root权限将为漏洞利用提供更大操作空间。

      但若攻击者确实利用漏洞成功逃逸,则将在主机上获得root权限。

      在容器内以无特权用户运行进程可降低逃逸沙箱的风险;而直接以无特权用户运行容器(如rootless podman或docker)则能在逃逸成功时缩小攻击面。

  44. 我遇到过类似情况,但幸运的是自己及时发现了。多年来使用SSH,却从未意识到它默认也支持密码登录。或许是我太粗心了,但事实就是如此…

  45. 那么我的理解正确吗?这个人的服务器上居然运行着完全不安全的指标接口?这种设计初衷究竟是什么?

  46. 顺便提一句,若你用Hetzner VPS运行Umami,配置可能过剩。有人提醒我后,我把Umami迁移到Oracle免费云VPS,每月省下4美元。具体取决于这是业余项目还是正式部署,但这个选项确实存在。

    1. 我宁愿多付4美元/月也要离Oracle越远越好

    2. 听起来不错,但Oracle会威胁在免费主机上强制关闭CPU使用率低于合理平均值的实例,最终还会突然执行关停。

      这麻烦到让我彻底放弃使用他们的服务。

      1. 你是指闲置状态还是满负荷运行?我曾有几台Oracle免费层虚拟机处于相对闲置状态,过去三年运行期间从未收到过关闭威胁。

      2. 我原以为也是如此,但只要绑定信用卡,他们似乎允许虚拟机保持空闲状态。我还是设置了每月1美元的预算上限并开启了预警,以防万一。

    3. 我租用了整台Hetzner EX41裸机服务器,而非VPS。上面运行着20个左右的服务。

      不过确实配置严重过剩。但每秒8000次请求的后端负载测试让我感觉超酷!

    4. 我选择Hetzner是因为它是欧盟本土企业,经营理念合理,没有贪婪的CEO。

    5. 在这种规模下,所有东西都放在一台主机上确实挺方便管理的,不过确实可以叠加不同供应商的免费层级来降低成本。

  47. 没看到有人提到,但使用只读根文件系统并挂载可写目录为noexec模式难道不够吗?

  48. 黑客用CPU挖矿真的值得吗?我以为ASIC矿机已经统治挖矿领域了

    1. ASIC确实主导着比特币挖矿,但门罗币的POW算法本就设计为抗ASIC。再说,用别人的服务器挖矿,效率高低有什么关系?

    2. 门罗币的工作量证明(RandomX)具有很强的抗ASIC特性。虽然单次收益微薄,但若利用此类漏洞部署数千甚至数万个节点,收益可累积(8核现代处理器全天候挖矿,单节点日收益约10-20美分)。楼主那台VPS估计给这些脚本小子赚了1美元左右。

      1. 攻击1000台服务器收益就会显著累积。尤其在生活成本低廉的地区。

      2. 所以年收益40美元?这是否意味着所有门罗币都靠这种方式开采?因为正规挖矿显然完全不划算?

        1. 我认为是这样,但很难断言。可能存在大量利用闲置电力(或盗用电力)但使用自有设备的矿工。我自己就用废弃太阳能发电挖矿

          1. 另一种可能性:

            故意产生热量。

            若环境寒冷且本需使用取暖设备,当热源采用电阻式加热时,运行加密货币矿机同样高效且能返还几美元收益。相对于取暖成本,这相当于“免费”获取热能。

            若使用热泵或依赖燃烧物(天然气、木材等)供热,则成本计算方式不同。

    3. 这是门罗币当前采用的工作量证明机制:

      > RandomX 采用虚拟机执行特殊指令集程序,包含整数运算、浮点运算及分支指令。> 这些程序可实时转换为CPU原生机器码(示例:program.asm)。> 最终通过加密哈希函数(Blake2b)将执行程序的输出整合为256位结果。

      我怀疑任何人都不可能制造出比基础CPU更高效、更经济的专用矿机。因此,很可能没有人使用ASIC矿机挖掘门罗币。

    4. 没错,对门罗币而言这是唯一切实可行的方案。我推测楼主提到的案例只是众多受害者之一,这些矿机的总算力可能累积形成了相当可观的加密货币。

    5. 这绝对划算——他们既不用支付算力费用也不耗电。

      若能操控数百甚至数千台机器为其挖XMR,撇开合法性不谈,简直是坐收渔利。

    6. 对他们而言完全免费,不划算才奇怪。这种自动化漏洞利用程序正席卷整个互联网。

    7. 优质硬件需要成本。而易受攻击的机器既免费又数量近乎无限。

    8. 当单台主机成本为零时,即使每月每台被入侵主机仅盈利5美元,也能构成可观的业务。

    9. 若将挖矿效益定义为利润除以基础设施运行成本,那么只要利润不为零,利用他人付费的CPU进行挖矿就是划算的。

  49. 当所有加密货币彻底消失时,世界会变得更美好

    1. 对受害者而言,遭遇勒索软件(索要苹果礼品卡)和被恶意软件悄然窃取数据直至发现有价值信息,哪种情况更糟?

  50. 我家用容器时不用Docker,但听说它没采用用户命名空间隔离机制?

    1. 若你在命名空间内拥有root权限并成功逃逸,便能在外部获得root特权。

      1. 你指的是用户命名空间吗?如果是,这种突破机制如何实现逃逸到主机root权限?我以为用户命名空间的核心机制是:容器内部的UID 0在外部视角下对应UID 100000之类的值。在这种架构下,逃逸容器本身不应赋予你修改主机主命名空间中实际UID的能力——不过我不确定Docker是否真正启用了用户命名空间。

        例如,在我的 systemd-nspawn 配置中启用 –private-users=pick 参数(启用用户命名空间)后,我创建了一个容器并为其设置了绑定挂载。从容器内部看,由容器命名空间的 UID 0 创建的绑定挂载文件似乎归属 UID 0 所有;但从容器外部观察,同一文件却显示归属 UID 100000 所有。反之,主机上“真实”UID 0拥有的文件,在主机视角显示为UID 0所有,但在容器视角则显示为UID 65534(即“nobody”)所有。脱离容器本身不应改变进程的“实际”用户从100000变为0,正如最初以非0 UID身份脱离容器时不会改变——这与脱离其他命名空间时,容器内的“UID 0”用户不会变成主机上的“UID 0”原理相同。

        1. 用户命名空间中的用户被授予了root级权限,命名空间本身需要被严格限制以防止这种情况发生。但若拥有root权限的用户逃逸出命名空间,则其在主机上同样拥有这些权限。

          命名空间还会暴露内核接口,若被利用同样可能导致相同后果。

          归根结底,命名空间仅用于资源隔离,将其用作沙箱虽可行,但本质上并非真正的沙箱。

  51. 本文开篇颇具吸引力,但读到“为何重要”、“关键时刻”等明显AI痕迹后再度失望,整篇文章充斥着此类标记。

    1. 确实,我宁愿读一篇结构拙劣但内容有趣的文章,也不愿看同样内容被套进千篇一律的AI腔调里。

      1. 文章已编辑:

        >编辑说明:几位HN用户指出本文读起来像大型语言模型生成。实情是这基本是我惊慌失措与Claude对话的记录。若行文生硬还请见谅,但事件确有其事!

        尽管如此,这绝非借口,我依然无法接受被喂食未公开的垃圾内容。我甚至懒得读下去。

  52. a) 容器无法真正隔离

    b) 若想将运行环境严格限制在预期语言/程序内,应采用强制隔离的unikernel方案

    1. > a) 容器无法真正隔离

      但这次似乎成功隔离了?

  53. 我还是搞不懂该怎么做才能避免这些问题。

    1. 全面掌握操作系统管理技能,并保持适度的偏执心态,是不错的起点。

      1. 接下来15年就靠自己编写所有软件来满足这份偏执吧。

        明年是我个人项目的第五年。还剩十年。

    2. 把个人博客托管在wordpress.com这类平台

  54. 父亲收到安全漏洞通知了吗?若未收到,他或许该考虑更换主机服务商。父亲值得获得一份不含法律术语的正式事后分析。

    1. 哈哈哈,我今天下午确实告知过他。但这家伙明明买了1Password,却仍用同一密码登录所有银行应用。远程代码执行漏洞的迫在眉睫威胁根本没打动他。

      1. 仅购买1Password之类工具就自以为万事大吉远远不够。用密码管理器的人常忘了:得逐个访问常用网站创建记录,再把密码改成安全版本,然后退出登录用新密码测试有效性——这过程耗时惊人。对多数人而言,别人买密码管理器给他们用,搞完第二个网站就放弃了。想想他们本可以刷多少条TikTok视频啊

        1. 是的,有天下午我和妈妈坐下来,把她所有密码都改成了1Password生成的长而安全的密码。那真是段美好的时光!这还帮她记住了需要访问的各种服务,现在它们都配着强密码安全存储着。而且这也是增进感情、共度时光的好方式。:)

      2. 小心,HN可不是普通的IRC频道。

  55. 简而言之:他遭遇黑客攻击,但损害仅限于运行Umami(基于NextJS构建)的Docker容器。幸运的是,该容器以非特权非root用户身份运行,这极大降低了风险——攻击面仅局限于容器内部,无法访问整个主机/文件系统。

    是否存在必须以root身份运行Docker容器的场景?

    1. 若需通过容器管理主机资源,通常需要以root权限运行的进程。最常见的场景是Docker-in-Docker架构——即容器通过Docker套接字直接调度其他容器。

  56. 写得很好的博客文章。干得漂亮,我学到了新知识。

  57. 我也运行着Umami,但在CVE补丁发布后立即进行了修补。此外,我仅通过Caddy公开暴露了跟踪JS端点和/api/send接口(尽管仅/api/send就可能足以利用该漏洞)。实际交互Umami界面时,我使用Twingate(类似Tailscale)在本地隧道连接至VPC。

  58. 你很幸运赫兹纳没有删除你的服务器并终止账户。

      1. 加密货币软件的使用。这完全违反他们的政策。据我所知,他们的政策并不区分主动使用与被动使用。

        他们对其他人也这么做过。

    1. 若他们这么做,下个月就收不到服务费了。

  59. 唯一的教训似乎是使用ufw!(或同类工具)

    1. 正如其他人提到的,防火墙或许能通过限制出站连接,在入侵后削弱黑客对机器的利用价值。

      入站防火墙仅能保护那些不应暴露在公共互联网上的服务。该服务是故意暴露在网上的,因此防火墙无法避免此次入侵。

      我从中得到的教训是:及时更新安全补丁能有效防止公开服务遭入侵。

  60. 至今仍难以置信竟有这么多人在搞破解,结果只是用硬件解毒药数独。现在的黑客手段真够寒酸的。

  61. 那容器在这里有什么意义?似乎只会让管理变得更不透明、更复杂。

    容器内运行的框架上运行的js脚本

    PS:看来主机最终没有被攻破

  62. 加密货币赋予原始CPU时间明确的货币价值,并极大刺激了僵尸网络的创建——这种现象让我莫名愤怒。

    1. 几年前有人在我服务器上挖门罗币。当时我正在运行Jenkins。

  63. 直接用Hetzner托管服务器?配置超高,全权代管,还能安装多种语言和应用。

  64. > ls -la /tmp/.XIN-unix/javae

    除非以root权限运行,否则可能因权限不足导致文件查找失败,而不仅仅是文件不存在,对吧?

    > “我不使用X”并不意味着你的依赖项不使用X

    这再明显不过了,我不明白当服务器上运行着数十个容器时,有人看到广泛使用的技术存在CVE漏洞还能感到安全。我用Docker容器,读完文章立刻去检查了——毕竟根本不知道多数容器是用什么技术构建的。

    > 不再用Umami了。我心有不甘。虽然CVE已披露且修复,但我再也不用Next.js框架的分析工具了。

    荒谬的反应。

    1. 没错,我的Umami容器确实中招了,但从漏洞披露到实机受攻击的时间间隔极其短暂。Umami团队修复速度极快,甚至在第二个漏洞紧随其后曝光时又进行了二次补丁更新。

      没有绝对的安全。你打算用什么分析工具?自建系统也难免留下漏洞。

    2. > 不再用Umami了。我被坑惨了。

      不过文字游戏玩得妙!

  65. 切勿将服务器IP直接暴露在互联网上,无论是VPS还是裸机。

    1. 除非需要互联网访问,否则必须确保其可被互联网访问。

      1. 面向公众的服务必须始终通过防火墙或WAF(如Cloudflare)路由。

        后端访问可通过Tailscale等工具轻松实现。

        1. 可能是个蠢问题:怎么可能不通过防火墙?家用服务器不都连在路由器后面吗?路由器本身就有防火墙功能,只需转发暴露给服务器的单一端口即可?

          Cloudflare还能提供更多保护(如抵御DoS攻击,若服务器在家中还能隐藏个人IP)。

    2. 隐藏服务器IP只是众多方案中的一种实践(混淆技术)。

      但仅靠此无法解决HTTP远程代码执行漏洞,因此Cloudflare[0]和Fastfy[1]等边缘代理服务商在其WAF产品中主动添加了防护机制。

      即便Cloudflare在保护客户过程中也曾遭遇服务中断[3]。

      – [0] https://blog.cloudflare.com/waf-rules-react-vulnerability/ – [1] https://www.fastly.com/blog/fastlys-proactive-protection-cri… – [2] https://blog.cloudflare.com/5-december-2025-outage/

    3. 任何服务器?如何运行公共网站?即使置于负载均衡器之后,该均衡器仍是“暴露于互联网的服务器”

      1. 面向公众的服务必须始终通过防火墙或WAF(如Cloudflare)路由。

        后端访问可通过Tailscale等工具轻松实现。

        公共IP完全无需使用。若真有需要,保留内部IP即可。

      1. 我运营生产服务器多年。

        DNS根本不成问题。外部DNS可由Cloudflare及其WAF处理。其DNS服务能隐藏你的公共IP,或者更理想的是直接在服务器上安装Cloudflare隧道,完全无需使用公共IP。这项服务是免费的。

        后端访问通过Tailscale等工具轻而易举。

        公共IP并非必须使用。如果你真的想,可以直接保留内部IP。

      1. Cloudflare隧道确实能实现,但此场景下并非必需。

        我将其用于自建服务。

        1. 该服务器仍通过公共IP暴露在互联网上,只是经由第三方城堡转发访问。

          1. 隧道无需使用公共IP接收流量,Cloudflare隧道仅呼出流量且可完全封锁。

            若使用Cloudflare的DNS服务,其可在DNS记录中隐藏IP地址,但仍需严格管控。不过部分用户会进一步强化防护措施。

            若使用裸金属服务器,可进行拆分部署。

            这确实是第三方堡垒。但当你尚未掌握服务器运维与安全防护技能时,借助这类服务并非坏主意。

            部分用户会在经济型VPS上部署Pangolin或Nginx代理管理器,根据实际需求安全连接服务器。

            值得庆幸的是,许多安全方案早已被先行者探索完善。

            即便我曾将裸机服务器直接接入互联网,也会在中间部署pfsense等防火墙。

            1. 除了DoS防护和隐藏IP,隧道还能带来什么?暴露IP有何安全隐患?比如我访问网站时,网站知道我的IP,我并不认为这是安全风险。

              如果运行存在漏洞的软件,通过Cloudflare隧道依然会暴露漏洞,对吧?

              真心好奇,我总是害怕将东西暴露在互联网上:-)。

      2. 方法很多。使用“堡垒主机”是选项之一,搭配WireGuard或Tinc等工具。Tailscale等服务是另一种方案。Tor则是另一种选择。

        1. 但堡垒主机本身是台服务器,仍会暴露在互联网上。

        2. >切勿直接将服务器IP(无论是VPS还是裸机)暴露在互联网上。

      3. 当然可以。

        免费方案——注册Cloudflare账户。使用Cloudflare的DNS服务,他们会在你的www域名前添加公共IP。

        第二层方案:在服务器安装Cloudflare隧道软件,从此无需使用公共IP。

        后端安全访问?安装Tailscale或Headscale。

        此方案可覆盖多数网站托管场景。若涉及额外端口或服务,可借助nginx代理管理器(网页端)等工具。部分用户会将其部署在专用VPS作为跳板机。

        如此便可将公共IP使用权限设为可选项,必要时随时锁定。以上方案均在防火墙运行前即可实现。

      4. 没错,就是CloudFlare ZeroTrust。完全免费,我已在多台主机上为大量容器部署,运行完美。

        1. 确实很方便。虽然不喜欢它只能绑定单个服务,但作为临时方案足够可靠。

    4. 你是指“必须运行网络防火墙”还是“隐藏IP地址”?因为有人同时建议这两点,其中一项显然不合理。

      1. 网络防火墙是强制要求的。

        所谓“隐藏IP”其实名不副实。

        通常可完全锁定公共IP,仅允许内部发起的连接(如Cloudflare隧道或其他外联方式)。

        具体方案:一端部署Cloudflare+隧道,另一端用Tailscale等工具接入。

        其他博主撰写的教程相当实用,值得参考。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

你也许感兴趣的: