Skip to content

feat(server): trust configured Unix socket requests - #2853

Open
qbisi wants to merge 1 commit into
OpenListTeam:mainfrom
qbisi:unix_file_trusted
Open

feat(server): trust configured Unix socket requests#2853
qbisi wants to merge 1 commit into
OpenListTeam:mainfrom
qbisi:unix_file_trusted

Conversation

@qbisi

@qbisi qbisi commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

增加scheme.unix_file_trusted,使得对于来自 unix_socket 的请求免认证。一个主要的用途是供服务器内部程序使用 unix_sock 挂载 webdav 以避免使用/泄漏 API_KEY 或 PASSWORD,unix_socket 的权限组相当于已经做了身份认证,nginx proxy pass可以使用http 端口以要求身份认证

Summary / 摘要

  • Add scheme.unix_file_trusted and OPENLIST_UNIX_FILE_TRUSTED; the zero-value default remains false.

  • Treat requests received through the configured Unix socket as an administrator without requiring account credentials, passwords, or an API key, including WebDAV requests.

  • Skip protected-download signature validation only for trusted Unix socket requests.

  • Keep existing HTTP and HTTPS authentication behavior unchanged.

  • This PR has breaking changes.
    / 此 PR 包含破坏性变更。

  • This PR changes public API, config, storage format, or migration behavior.
    / 此 PR 修改了公开 API、配置、存储格式或迁移行为。

  • This PR requires corresponding changes in related repositories.
    / 此 PR 需要关联仓库同步修改。

Testing / 测试

  • go test ./...
  • go test ./internal/conf ./server/middlewares ./server ./internal/bootstrap
  • gofmt -d internal/bootstrap/run.go internal/conf/config.go server/middlewares/auth.go server/middlewares/down.go server/webdav.go (no output)
  • Manual test / 手动测试: Not run.

Checklist / 检查清单

  • I have read CONTRIBUTING.
    / 我已阅读 CONTRIBUTING
  • I confirm this contribution follows the repository license, contribution policy, and code of conduct.
    / 我确认此贡献符合仓库许可证、贡献规范和行为准则。
  • I have formatted the changed code with gofmt, go fmt, or prettier where applicable.
    / 我已按适用情况使用 gofmtgo fmtprettier 格式化变更代码。
  • I have requested review from relevant maintainers or code owners where applicable.
    / 我已在适用情况下请求相关维护者或代码所有者审查。

AI Disclosure / AI 使用声明

  • This PR includes AI-assisted content.
    / 此 PR 包含 AI 辅助内容。

Tools used / 使用工具:

  • Codex

Usage scope / 使用范围:

  • Code generation / 代码生成

  • Tests / 测试

  • Review assistance / 审查辅助

  • I have reviewed and validated all AI-assisted content included in this PR.
    / 我已审核并验证此 PR 中的所有 AI 辅助内容。

  • I have ensured that all AI-assisted commits include Co-Authored-By attribution.
    / 我已确保所有 AI 辅助提交都包含 Co-Authored-By 归属信息。

  • I can reproduce all AI-assisted content included in this PR without any AI tools.
    / 我可以在没有任何 AI 工具的情况下重现此 PR 中包含的所有 AI 辅助内容。

- add unix_file_trusted configuration with a disabled zero-value default
- grant trusted Unix socket requests an admin identity without credentials
- bypass WebDAV authentication and download signatures only on the trusted socket

Co-authored-by: Codex <267193182+codex@users.noreply.github.com>
@qbisi
qbisi force-pushed the unix_file_trusted branch from 74cfd07 to 1ef5dcd Compare July 27, 2026 09:18
@qbisi
qbisi marked this pull request as ready for review July 29, 2026 21:40
@xrgzs xrgzs added enhancement Module: Server API and protocol changes labels Jul 31, 2026

@PIKACHUIM PIKACHUIM left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙏 感谢贡献

感谢 @qbisi 提交此PR!我已完成代码评审,以下是评审结果。


📖 PR背景与需求

PR标题:feat(server): trust configured Unix socket requests

需求说明:增加 scheme.unix_file_trusted 配置选项,使得通过 Unix socket 接收的请求可以免认证,直接以管理员身份访问系统。主要用途是供服务器内部程序通过 unix socket 挂载 WebDAV,避免使用/泄漏 API_KEY 或 PASSWORD。

设计理念:Unix socket 的文件系统权限机制本身已经提供了身份认证(只有有权限访问 socket 文件的进程才能连接),因此可以将其视为可信通道。对于需要对外暴露的场景,可以通过 nginx proxy_pass 使用 HTTP 端口来要求身份认证。

预期目标

  • 新增配置项 unix_file_trusted(默认 false,向后兼容)
  • 通过 Unix socket 接收的请求在开启此配置后,自动以管理员身份通过认证
  • 包括 WebDAV 请求在内的所有请求都适用
  • 跳过受保护下载的签名验证(仅针对可信 Unix socket 请求)
  • 不影响 HTTP/HTTPS 的现有认证行为

📋 问题摘要

  • ⚠️ 安全性:存在重大安全风险,需要慎重考虑
  • 代码质量:代码结构清晰,实现方式合理
  • ⚠️ 改进建议:有3处需要讨论的关键点

📂 逐文件分析

internal/conf/config.go

改动意图:在 Scheme 结构体中新增 UnixFileTrusted 配置字段。

代码修改逻辑

  • 添加字段:UnixFileTrusted bool,支持 JSON 配置和环境变量 UNIX_FILE_TRUSTED
  • 默认值为 false(零值),保持向后兼容

合理性评估

  • 优点

    • 字段命名清晰,直观表达语义
    • 默认值安全(false),用户需要显式开启
    • 支持环境变量配置,方便容器化部署
  • ⚠️ 疑问

    1. 缺少配置文档和警告:这是一个安全敏感配置,应该在注释中添加警告说明使用场景和风险,例如:
      UnixFileTrusted bool `json:"unix_file_trusted" env:"UNIX_FILE_TRUSTED" help:"SECURITY: Trust Unix socket requests as admin. Only enable if the socket is protected by OS permissions. DO NOT enable if the socket is accessible to untrusted users."`

internal/bootstrap/run.go

改动意图:在 Unix socket 服务器启动时,根据配置决定是否包装请求处理器。

代码修改逻辑

  • 如果 conf.Conf.Scheme.UnixFileTrustedtrue,使用 middlewares.UnixFileTrusted() 中间件包装原始处理器
  • 这个中间件会在请求的 context 中注入一个标记(unixFileTrustedKey{}),表示这是一个可信的 Unix socket 请求

合理性评估

  • 优点

    • 在启动时决定是否信任,避免每次请求都检查配置
    • 使用 context 传递信任标记,避免全局状态污染
  • ⚠️ 疑问

    1. 缺少日志记录:启用此功能时应该记录警告日志,提醒管理员这是一个安全敏感配置:
      if conf.Conf.Scheme.UnixFileTrusted {
          utils.Log.Warnf("Unix socket %s is configured as TRUSTED - all requests will be authenticated as admin", conf.Conf.Scheme.UnixFile)
          unixHandler = middlewares.UnixFileTrusted(unixHandler)
      }

server/middlewares/auth.go

改动意图:在现有的认证中间件中,优先检查是否为可信 Unix socket 请求,如果是则直接以管理员身份通过认证。

代码修改逻辑

  • Auth()Authn() 中间件的开头调用 authenticateUnixFileTrusted(c)
  • 如果该函数返回 true(表示已处理认证),则直接返回,跳过后续的 token/session 认证逻辑
  • authenticateUnixFileTrusted() 函数:
    1. 检查 IsUnixFileTrusted(c)(验证请求是否来自可信 Unix socket)
    2. 如果是,获取管理员用户,注入到 context,调用 c.Next(),返回 true
  • UnixFileTrusted() HTTP 中间件:在请求的 context 中注入 unixFileTrustedKey{} 标记
  • IsUnixFileTrusted() 函数:检查配置 conf.Conf.Scheme.UnixFileTrusted 且 context 中存在标记

合理性评估

  • 优点

    • 逻辑清晰,通过 context key 实现请求来源的可靠传递
    • 在认证链的最前端检查,避免不必要的认证开销
    • 代码复用好,统一了 AuthAuthn 的处理逻辑
  • ⚠️ 疑问

    1. 安全边界不清晰:当前实现假设只有 Unix socket 监听器才会调用 UnixFileTrusted 中间件。但如果配置错误(如在 HTTP 服务器上也使用了这个中间件),会导致所有 HTTP 请求都被信任。建议增加双重验证:

      func IsUnixFileTrusted(c *gin.Context) bool {
          if !conf.Conf.Scheme.UnixFileTrusted {
              return false
          }
          trusted, _ := c.Request.Context().Value(unixFileTrustedKey{}).(bool)
          if !trusted {
              return false
          }
          // 验证请求确实来自 Unix socket(通过检查 RemoteAddr 格式)
          // Unix socket 的 RemoteAddr 格式通常为 "@" 或不包含端口号
          remoteAddr := c.Request.RemoteAddr
          if remoteAddr == "" || strings.Contains(remoteAddr, ":") {
              log.Warnf("unix_file_trusted is enabled but request appears to be from TCP socket: %s", remoteAddr)
              return false
          }
          return true
      }
    2. 日志不足:建议在 authenticateUnixFileTrusted 中记录更详细的日志,包括请求路径和 RemoteAddr,便于审计:

      log.Infof("Trusted Unix socket request authenticated as admin: %s %s (remote: %s)", 
          c.Request.Method, c.Request.URL.Path, c.Request.RemoteAddr)

server/middlewares/down.go

改动意图:对于可信 Unix socket 请求,跳过受保护下载的签名验证。

代码修改逻辑

  • 修改签名验证条件:if !IsUnixFileTrusted(c) && needSign(meta, rawPath)
  • 只有在不是可信 Unix socket 请求需要签名时,才进行签名验证

合理性评估

  • 优点

    • 逻辑简洁,一行代码实现功能
    • 对于内部程序通过 Unix socket 访问,确实不需要签名验证
  • ⚠️ 疑问

    1. 安全考虑:跳过签名验证意味着可以下载任何文件(包括受保护的文件),这与"以管理员身份"的语义一致。但建议在 PR 描述或代码注释中明确说明这一行为。

server/webdav.go

改动意图:为 WebDAV 请求添加可信 Unix socket 的认证支持。

代码修改逻辑

  • WebDAVAuth() 中间件的开头检查 IsUnixFileTrusted(c)
  • 如果是可信请求,获取管理员用户,注入到 context,调用 c.Next(),直接返回
  • 否则继续执行原有的 WebDAV 认证逻辑(检查登录次数、Basic Auth 等)

合理性评估

  • 优点

    • 与 HTTP API 认证逻辑保持一致
    • WebDAV 作为主要使用场景,确实需要此功能
  • 💡 可选优化

    • 日志记录:记录 WebDAV 通过 Unix socket 免认证访问的事件

🎯 总体评价

功能性:⭐⭐⭐⭐ - 功能设计合理,解决了实际需求,但使用场景需要明确限定
安全性:⭐⭐⭐ - 存在安全风险,需要加强边界验证和文档说明
代码质量:⭐⭐⭐⭐ - 代码结构清晰,实现方式合理,但日志和注释不足
实现方案:⭐⭐⭐⭐ - 实现方案合理,使用 context 传递信任标记是正确的方法

建议操作

  • ✅ Approve(建议合并)
  • 🔄 Request Changes(需要修改)
  • ❌ Close(建议关闭)

理由:此 PR 的功能设计是合理的,代码实现也基本正确。但由于涉及安全敏感的认证绕过,需要加强以下几点:

  1. 增强安全边界验证:在 IsUnixFileTrusted 中增加对请求来源的验证,避免配置错误导致所有 HTTP 请求都被信任
  2. 增加安全警告日志:在启用此功能时记录警告日志,在每次免认证访问时记录审计日志
  3. 补充配置文档:在配置字段中添加 help 标签,明确说明使用场景和安全风险
  4. 补充测试用例:验证在不同配置下的行为(特别是安全边界测试)

🔧 推荐修改方案

1. 增强 IsUnixFileTrusted 的安全验证

func IsUnixFileTrusted(c *gin.Context) bool {
	if !conf.Conf.Scheme.UnixFileTrusted {
		return false
	}
	trusted, _ := c.Request.Context().Value(unixFileTrustedKey{}).(bool)
	if !trusted {
		return false
	}
	// 双重验证:确认请求确实来自 Unix socket
	// Unix socket 的 RemoteAddr 通常为 "@" 或不包含 ":" 端口分隔符
	remoteAddr := c.Request.RemoteAddr
	if remoteAddr != "" && strings.Contains(remoteAddr, ":") {
		// 看起来像 TCP 连接 (ip:port),不应该被信任
		log.Warnf("unix_file_trusted enabled but request appears to be from TCP: %s %s (remote: %s)", 
			c.Request.Method, c.Request.URL.Path, remoteAddr)
		return false
	}
	return true
}

2. 增加安全日志

// 在 internal/bootstrap/run.go 中
if conf.Conf.Scheme.UnixFileTrusted {
	utils.Log.Warnf("SECURITY: Unix socket %s is configured as TRUSTED - all requests will authenticate as admin without credentials", conf.Conf.Scheme.UnixFile)
	unixHandler = middlewares.UnixFileTrusted(unixHandler)
}

// 在 authenticateUnixFileTrusted 中
func authenticateUnixFileTrusted(c *gin.Context) bool {
	if !IsUnixFileTrusted(c) {
		return false
	}
	admin, err := op.GetAdmin()
	if err != nil {
		common.ErrorResp(c, err, 500)
		c.Abort()
		return true
	}
	common.GinAppendValues(c, conf.UserKey, admin)
	log.Infof("Trusted Unix socket: authenticated as admin for %s %s (remote: %s)", 
		c.Request.Method, c.Request.URL.Path, c.Request.RemoteAddr)
	c.Next()
	return true
}

3. 补充配置文档

type Scheme struct {
	// ...
	UnixFile        string `json:"unix_file" env:"UNIX_FILE"`
	UnixFileTrusted bool   `json:"unix_file_trusted" env:"UNIX_FILE_TRUSTED" help:"SECURITY: Trust Unix socket requests as admin without credentials. Only enable if the socket file is protected by OS permissions and not accessible to untrusted users. DO NOT expose this socket to the internet or untrusted networks."`
	UnixFilePerm    string `json:"unix_file_perm" env:"UNIX_FILE_PERM"`
	// ...
}

4. 补充测试用例

建议添加测试用例验证:

  • 配置开启时,Unix socket 请求应该以管理员身份通过认证
  • 配置关闭时,Unix socket 请求应该正常执行认证流程
  • 边界情况:如果 UnixFileTrusted 中间件错误地被应用到 HTTP 服务器,应该被 IsUnixFileTrusted 的 RemoteAddr 检查拦截

Next Steps / 后续建议

  1. 在文档中明确说明此功能的适用场景和安全考虑
  2. 提供配置示例,说明如何正确设置 Unix socket 文件权限(如 chmod 600chmod 660
  3. 如果可能,考虑提供更细粒度的控制(如只信任特定路径前缀的请求)

再次感谢你的贡献!这是一个实用的功能,但需要在安全性上做进一步加固。👏

@pikachuren pikachuren left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙏 感谢 @qbisi 提交!
🤖 AI 自动审核声明:本评审报告由 AI 自动生成,当前使用 Claude Opus 5 模型进行分析。
⚠️ AI 分析结果仅供参考,可能存在误判或遗漏。如您发现任何问题或有不同意见,欢迎随时提出讨论和纠正。
⚠️ 重要提醒:即使 AI 评审认为代码质量良好且建议合并,最终是否合并仍需由项目维护者进行人工判定。项目维护者会综合考虑代码质量、项目规划、技术方向、团队资源等多方面因素做出决策。

🎯 结论

🔄 Request Changes — 功能有合理场景,但这是一条完整绕过鉴权的路径,几处细节需要收紧后再合并

📖 概要

feat(server): trust configured Unix socket requests · 新增 unix_file_trusted 配置,开启后经 Unix socket 进入的请求直接以 admin 身份放行。
核心改动:新增 UnixFileTrusted 中间件在 request context 打标记,Auth / Authn / WebDAVAuth 命中标记即注入 admin 用户,同时 Down 中间件跳过签名校验。

🧭 整体方案

技术路线是「以 Unix socket 的文件系统权限替代应用层鉴权」——本机反代或同机客户端通过 socket 访问时免去 token。这在 Unix 生态里是常见做法(socket 的 chmod/chown 本身就是访问控制),思路成立。实现上用 context key 传递标记、且 IsUnixFileTrusted 同时校验配置开关与 context 标记(双重判断,标记由服务端包装写入而非解析请求头,无法被外部伪造),这个细节考虑得不错。但既然是「完全绕过鉴权」,几处边界仍需加固。

📊 变更统计

5 个文件(+66 / -12 行) | 功能 ⭐⭐⭐⭐ | 最小改动 ⭐⭐⭐⭐ | 前向兼容 ⭐⭐⭐⭐ | 方案设计 ⭐⭐⭐

🚨 关键问题

P0(阻塞合并)

  • ⚠️ internal/bootstrap/run.go + internal/conf/config.go — 开启 unix_file_trusted 后,任何能读写该 socket 文件的本机进程都获得完整 admin 权限(含 WebDAV 与免签名下载)。此时 socket 的文件权限就是唯一防线,但代码并未强制校验 UnixFilePerm:若用户配置了 0666,同机任意低权限用户即可完全接管实例。请问是否考虑在启用 trusted 时强制校验权限位、发现宽松配置就拒绝启动呢?例如:
if conf.Conf.Scheme.UnixFileTrusted && perm&0o007 != 0 {
    utils.Log.Fatalf("unix_file_trusted requires a non-world-accessible unix_file_perm, got %#o", perm)
}

P1(建议修复)

  • ⚠️ server/middlewares/down.go!IsUnixFileTrusted(c) && needSign(...) 让 trusted 请求跳过签名校验。签名除鉴权外还承担防路径篡改作用,完全跳过后,反代若把用户可控路径透传进来,可能被用于访问任意文件。是否考虑此处保留签名校验,仅豁免登录态呢?
  • ⚠️ 启用该功能显著降低安全边界,但目前只是一个静默配置项。是否考虑启动时打一条醒目 Warn 日志,让运维明确知晓当前处于免鉴权模式?
  • ⚠️ authenticateUnixFileTrusted 内部调用 c.Next() 后返回 true,外层 Auth 随即 return。这种「中间件里嵌套推进链路」能工作,但容易被后续维护者误读为普通短路返回,是否考虑改为更直观的控制流?

P2(可选)

  • 💡 WebDAVAuth 中的 admin 注入与 authenticateUnixFileTrusted 几乎重复,可抽成共用函数~
  • 💡 建议文档中补充适用场景与风险,强调「不要在多用户主机上开启」~

📂 逐文件分析

server/middlewares/auth.go

改动意图:让 trusted socket 请求以 admin 身份通过鉴权。
代码逻辑UnixFileTrusted 包装 handler 写入 context 标记;IsUnixFileTrusted 同时要求配置开关与标记为真;Auth / Authn 开头调用并在命中时注入 admin。
问题分析:双重校验设计正确,标记无法被外部 HTTP 头伪造。主要风险来自 socket 权限缺乏强制约束(P0)与控制流可读性(P1)。

server/middlewares/down.go

问题分析:跳过签名校验的范围过大,建议收窄(P1)。

internal/bootstrap/run.go / internal/conf/config.go

问题分析:仅在 trusted 时包装 handler、默认关闭,前向兼容良好;缺少权限强校验(P0)。

✅ 待处理清单

  • [P0] 启用 trusted 时强制校验 unix_file_perm,拒绝 world-accessible 的 socket
  • [P1] 评估 Down 中间件是否应保留签名校验
  • [P1] 启动时输出安全模式警告日志
  • [P1] 调整 authenticateUnixFileTrusted 的控制流写法
  • [P2] 抽取重复的 admin 注入逻辑并补充文档

🎯 结论:🔄 Request Changes — 方案合理且已有防伪造考虑,但作为免鉴权通道必须先补上 socket 权限强校验。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement Module: Server API and protocol changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants