Help us shape the future of Go! Take the 2026 Go Developer Survey

security

package
v0.32.41 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 31, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Overview

Package security 提供独立的安全原语:

  • DownloadToken: 取件下载令牌(时间窗 HMAC + 恒时比较)
  • SSRF: 存储端点 URL 校验(scheme 白名单 + 私网地址策略)

Index

Constants

This section is empty.

Variables

View Source
var ErrEndpointURL = fmt.Errorf("存储端点 URL 不合法")

ErrEndpointURL 存储端点 URL 不合法

Functions

func ContentDispositionAttachment added in v0.18.0

func ContentDispositionAttachment(name string) string

ContentDispositionAttachment 构造下载 Content-Disposition(RFC 6266 + 5987):

  • 引号/反斜杠/控制字符消毒防头断义;
  • 纯 ASCII 名只给 filename=;
  • 非 ASCII 名(中文等)补 filename*=UTF-8”<pct-encoded>,且 filename= 改用 纯 ASCII 兜底名——老客户端(Android 9 下载器等)不认 filename*,遇到裸 UTF-8 字节会把整个头丢弃变成 download.bin,兜底名至少保住扩展名与可辨识度。

pct-encoded 按 RFC 5987 attr-char 白名单逐字节编码(PathEscape 会放行 `;`/`,` 等非 attr-char,ext-value 里裸分号会截断头参数,故不复用它)。

func DownloadSessionKey added in v0.32.0

func DownloadSessionKey(code, clientIP string) string

DownloadSessionKey 无令牌部署时的兜底「取件会话」键(按分享码 + 取件人 IP)。

场景:`security.download_token.enabled=false` ⇒ 没有令牌 ⇒ 没有天然的 「一次取件」凭证 ⇒ 若每次交付都算一次取件,多文件分享逐个下载会逐个扣次 (「取件次数=1 只能下载第一个文件」的老问题在关闭令牌时重现)。 ⇒ 用 (分享码, 取件人 IP) 兜底:同一收件人的一次取件(多文件/续传/重下) 只扣 1 次;不同分享互不干扰。

单向(HMAC)⇒ 落库的不是明文 IP。域不同("ip|" vs "fp|")⇒ 不会与令牌指纹撞键。

func DownloadTokenFingerprint added in v0.32.0

func DownloadTokenFingerprint(token string) string

DownloadTokenFingerprint 令牌的计次指纹(**不校验有效性**)。

签发方用它在签发的同一刻算计次键(文本分享在 select 交付正文时计次); 校验方用 VerifyDownloadTokenFingerprint(校验 + 指纹一体)。

func DownloadTokenTTL added in v0.32.0

func DownloadTokenTTL() time.Duration

DownloadTokenTTL 当前令牌有效期。

func GenerateDownloadToken

func GenerateDownloadToken(code string) string

GenerateDownloadToken 生成下载令牌 "exp.nonce.sig"。

令牌 = **一次取件的凭证**:下载时按令牌计次(同一令牌至多扣 1 次), 见 repo/db/model.PickupCharge。空密钥(未注入)时返回空串——调用方按 「功能未启用」处理。

⚠️ 形态变更(2026-10-24,破坏性):此前是 "exp.sig"(载荷 `code.exp`), 现在是 "exp.nonce.sig"(载荷 `code.exp.nonce`)。旧令牌在升级后校验失败 (窗口 ≤ TTL,取件页重新取一次即可)。

func SetDownloadTokenSecret

func SetDownloadTokenSecret(secret string)

SetDownloadTokenSecret 注入下载令牌签名密钥(应与 jwt_secret 等强的独立随机值)。

func SetDownloadTokenTTL added in v0.32.0

func SetDownloadTokenTTL(seconds int)

SetDownloadTokenTTL 设置令牌有效期(秒);<=0 时回落到默认值。

func TextViewKey added in v0.32.2

func TextViewKey(code, clientIP string) string

TextViewKey **文本交付面**的计次键:按 (分享码, 取件人 IP) 派生。

为什么文本面不用令牌指纹(2026-10-24 回归修复):select 每次都会签发**新**令牌 ⇒ 令牌指纹每次都不同 ⇒ 收件人**刷新一次页面就扣一次**取件次数 ⇒ 额度很快耗尽, 第三次 select 直接 403「超过取件次数」——**正文都看不了**(改动前 select 从不 扣次,文本分享可以随便刷新查看 ⇒ 这是引入的功能性回归)。

文本的交付动作是「打开页面」而非「下载」⇒ 判重粒度应当是**取件者**而不是 一次请求:同一 IP 重复打开/刷新 = 同一次取件(只扣 1 次,能一直看); 不同的人(不同 IP)= 各自的取件(各扣 1 次 ⇒ owner 的「N 次」= N 个取件者)。

单向(HMAC)⇒ 落库的不是明文 IP。与 DownloadSessionKey 的域不同("text|" vs "ip|")⇒ 两类键不会互相撞。

func ValidateEndpointHost

func ValidateEndpointHost(hostPort string) error

ValidateEndpointHost 校验裸主机端点(FTP/SFTP 的 host 字段:host[:port], 无 scheme 不适用 URL 解析)。策略与 ValidateEndpointURL 一致:IP 字面量直接 判私网;域名解析后逐 IP 复判;allow_private_networks 开启时全放行。

func ValidateEndpointURL

func ValidateEndpointURL(rawURL string) error

ValidateEndpointURL 校验 s3/webdav 存储端点 URL:

  • 仅允许 http/https scheme
  • 必须携带 host
  • DNS 解析后逐 IP 复判私网策略(防重绑定攻击:解析结果非配置期望网段时拒绝)

allowPrivate 未配置(默认 false)时拒绝环回/私网/链路本地地址。 局域网 MinIO/WebDAV(飞牛 NAS)部署需显式 security.ssrf.allow_private_networks=true。

func VerifyDownloadToken

func VerifyDownloadToken(code, token string) bool

VerifyDownloadToken 恒时比较校验令牌(exp 窗口 + HMAC 签名)。

func VerifyDownloadTokenFingerprint added in v0.32.0

func VerifyDownloadTokenFingerprint(code, token string) string

VerifyDownloadTokenFingerprint 校验令牌并返回其**计次指纹**(空串 = 无效)。

令牌串 = "exp.nonce.sig",签名载荷 = "code.exp.nonce" ⇒ 签名覆盖分享码 (令牌不可跨分享使用),nonce 落在令牌串里(可重建载荷,无需服务端记账)。

指纹 = HMAC(secret, "fp|" + 令牌):单向,**不是令牌本身** —— 计次记录要落库, 若直接存签名段,DB 泄漏即等于泄漏可直接下载的凭证。

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL