Golang HTTP服务器持续占用服务器资源问题排查
Golang HTTP服务器持续占用服务器资源问题排查 大家好。这是我的第一个帖子。
我有一个Go HTTP应用程序,它不断填满我的硬盘。
我知道这可能是某种攻击,因为它是一个循环,向一个名为 /tmp/#45 的文件写入数据……我的代码中没有任何会做这种事情的逻辑。
我认为我已经对我的基本文件服务器路由进行了处理。
if r.URL.Path == "/" {
f, err := os.Open("static" + Slash + "index.html")
checkErr(err)
http.ServeContent(w, r, "index.html", time.Now(), f)
return
}
if strings.HasSuffix(r.URL.Path, "/") || strings.Contains(r.URL.Path, "..") || r.URL.Path == "." {
http.NotFound(w, r)
return
}
FileServerHandler.ServeHTTP(w, r)
我认为我的WebSocket配置是合理的。
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
EnableCompression: true,
CheckOrigin: func(r *http.Request) bool { return true },
}
我猜测有人向服务器发送了一个请求,以某种方式欺骗它不断地向硬盘写入数据。我只是想不通是如何做到的。
只有80和443端口是开放的。其他所有端口都被服务器的防火墙以及其前面的防火墙拒绝了。
我能想到的另一件事是,该应用程序以root身份运行,以便可以访问80/443端口。我已经在更新它,使其由普通用户在不同的端口上运行,并使用NGINX进行代理。
有什么想法吗?
谢谢!
更多关于Golang HTTP服务器持续占用服务器资源问题排查的实战教程也可以访问 https://www.itying.com/category-94-b0.html
这段代码不足以弄清楚发生了什么。
更多关于Golang HTTP服务器持续占用服务器资源问题排查的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
crontab 并非设计用于在系统重启时启动应用程序,根据您的操作系统,有更好的方法来实现此目的。
文件里有什么内容?如果是纯文本,文件内容能帮助识别它们是什么吗?如果是二进制文件,可以尝试检查文件开头的几个字节,看看是否有“魔数”能提示是什么程序创建了它们。
在Ubuntu 20.04中,您建议采用哪种方式?我之所以这样做,是因为在谷歌搜索后,除了将应用程序重新开发为服务之外,这似乎是大多数推荐的方式。
我已经缩小了问题的范围。这真是最奇怪的事情!
出于某种原因,当我在重启时通过 crontab 启动这个 Web 应用时,正是这个操作导致应用填满了硬盘! 如果我自己运行这个应用,它工作得很好。但如果让 crontab 运行它,我观察 iotop 发现它只是在不断地填满硬盘!
有人遇到过这种情况吗?
我唯一能想到的是,这个应用捕获了 Control-C 信号,所以如果我按 Control-C 退出,它会先做一些清理工作。
老实说,我毫无头绪。
我已经在两台机器上复现了这个问题。
“烦人”的部分是,我不记得查看临时文件的命令了。因为如果我仅仅执行 ls 或 find du,这些文件是不可见的……那是我在某个地方找到的一个特殊命令,能让我找到它们。
太奇怪了!
你应该配置一个新的 systemd 服务,它将负责启动你的应用程序。

如何在 Linux 上实现程序开机自动启动
目录 如何实现 Linux 程序开机自动启动 创建我们希望在开机时自动启动的示例脚本或程序 创建一个系统单元(也称为服务) 配置你的服务以实现自动…
这是一个典型的目录遍历漏洞,攻击者通过构造特殊路径绕过了你的安全检查。问题出在你的路径验证逻辑不完整。
// 当前有缺陷的检查
if strings.HasSuffix(r.URL.Path, "/") || strings.Contains(r.URL.Path, "..") || r.URL.Path == "." {
http.NotFound(w, r)
return
}
这个检查只阻止了包含..的路径,但攻击者可以使用URL编码绕过。例如/tmp/%2345会被解码为/tmp/#45。你的检查没有处理URL解码后的路径。
修复方案:
import (
"net/http"
"net/url"
"path/filepath"
"strings"
)
func safePathHandler(next http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// 解码URL路径
path, err := url.PathUnescape(r.URL.Path)
if err != nil {
http.Error(w, "Invalid path", http.StatusBadRequest)
return
}
// 清理路径,移除相对路径组件
cleanPath := filepath.Clean(path)
// 检查路径是否试图逃逸根目录
if !strings.HasPrefix(cleanPath, "/") || strings.Contains(cleanPath, "../") {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
// 检查特殊目录和文件
if strings.Contains(cleanPath, "/tmp/") ||
strings.Contains(cleanPath, "/etc/") ||
strings.Contains(cleanPath, "/proc/") ||
strings.Contains(cleanPath, "/dev/") {
http.Error(w, "Forbidden", http.StatusForbidden)
return
}
// 更新请求路径为清理后的路径
r.URL.Path = cleanPath
next.ServeHTTP(w, r)
}
}
// 使用中间件包装FileServer
http.Handle("/", safePathHandler(FileServerHandler))
同时,立即停止以root身份运行服务。使用setcap赋予二进制文件权限:
sudo setcap 'cap_net_bind_service=+ep' /path/to/your/binary
然后以非root用户运行。或者使用nginx反向代理:
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Go服务监听8080端口,由普通用户运行。

