如何使用Gin实现动态子目录文件服务且不暴露目录列表
实现方案
实现思路
- 不要使用Gin内置的
Static/StaticFS方法,这类方法默认会开启目录列表浏览,不符合需求 - 手动捕获所有
/media前缀的请求,自行校验路径合法性、判断目标是否为文件,仅合法文件请求才返回内容 - 额外增加路径穿越校验,避免恶意请求访问到
rooms目录外的敏感文件
完整代码示例
package main import ( "net/http" "os" "path/filepath" "strings" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() // 捕获所有/media前缀的请求 r.GET("/media/*filepath", func(c *gin.Context) { // 1. 处理请求路径,去掉开头的斜杠 reqPath := strings.TrimPrefix(c.Param("filepath"), "/") // 2. 拼接本地文件的根目录,建议替换为实际的绝对路径 baseDir := "./uploads/rooms" fullPath := filepath.Join(baseDir, reqPath) // 3. 路径穿越校验,防止恶意请求访问目录外的文件 absBaseDir, err := filepath.Abs(baseDir) if err != nil { c.AbortWithStatus(http.StatusNotFound) return } absFullPath, err := filepath.Abs(fullPath) if err != nil || !strings.HasPrefix(absFullPath, absBaseDir) { c.AbortWithStatus(http.StatusNotFound) return } // 4. 校验目标是否为存在的普通文件 fileInfo, err := os.Stat(absFullPath) if err != nil || fileInfo.IsDir() { c.AbortWithStatus(http.StatusNotFound) return } // 5. 校验通过,返回文件 c.File(absFullPath) }) r.Run(":8080") }
效果验证
- 请求
http://localhost:8080/media/1/a.jpg:正常返回对应图片 - 请求
http://localhost:8080/media/1:识别为目录,返回404 - 请求
http://localhost:8080/media/../../etc/passwd:路径穿越校验不通过,返回404 - 新增
rooms/3/d.jpg后不需要修改代码,直接请求http://localhost:8080/media/3/d.jpg即可正常返回
内容的提问来源于stack exchange,提问作者Anup Kumar Panwar
相关产品推荐
相关产品推荐

