fiber 默认日志不脱敏,因logger中间件直接调用req.uri().string()和req.header.string()生成明文日志,敏感字段(如token、authorization)需在日志前通过visitall遍历queryargs/headers主动脱敏,不可依赖后置字符串替换。

为什么 Fiber 默认日志不脱敏,且不能靠中间件后置处理
Fiber 的 Logger 中间件(如 fiber.Logger)默认把 req.URL.String()、req.Header、req.Body 原样转成字符串写入日志,一旦含 ?token=abc 或 Authorization: Bearer xyz,就直接明文落地。这不是配置开关能关掉的——它在 ctx.Request().URI() 和 ctx.Request().Header.String() 调用时就已经生成了完整字符串,后续中间件无法安全剥离字段语义。
对 HTTP 请求参数和 Header 做前置脱敏(非字符串替换)
必须在日志中间件执行前,把敏感字段从原始结构中“摘出来”再重写,而不是等它变成字符串再正则扫。关键点:
-
ctx.Query("token")、ctx.Get("Authorization")这类显式取值方式可直接判断并替换,但仅覆盖单层; - 要处理
ctx.Request().URI().QueryArgs()返回的args对象,遍历所有 key,对匹配"token"、"auth"、"key"的 value 调用args.Set(key, "[REDACTED]"); - Header 同理:用
ctx.Request().Header.VisitAll()遍历,对strings.Contains(strings.ToLower(k), "auth")的项跳过或覆写为"[REDACTED]"; - 别动
ctx.Request().URI().SetQueryString()后直接丢给日志——Fiber 日志中间件仍会读原始URI缓存,需配合自定义Logger实现;
自定义 Fiber Logger 替换默认行为
用 fiber.New() 创建 app 时传入自定义 fiber.Config{Logger: &customLogger},或更常用的是用 app.Use(customLogMiddleware) 替代默认 fiber.Logger。核心是重写日志字段构造逻辑:
- 不要调用
ctx.Request().String()或ctx.Request().Header.String(); - 手动拼接日志行:用
ctx.Method()+redactedURI(ctx)+redactedIP(ctx)+redactedUserAgent(ctx); -
redactedURI函数里先调用ctx.Request().URI().QueryArgs().VisitAll()清洗 query,再用ctx.Request().URI().String()获取已脱敏 URI; - Body 脱敏要谨慎:只对
Content-Type: application/json且长度合理(如 json.Unmarshal +SanitizeMap递归清洗,其他类型留空或记为"[BINARY]";
结构化日志场景下如何让业务数据自动脱敏
如果你用 fiber.Map 或结构体返回 JSON(如 c.JSON(200, user)),而 user 含 Password 字段,Fiber 底层走 json.Marshal,此时脱敏必须发生在序列化入口:
- 让结构体实现
json.Marshaler接口,MarshalJSON()内显式控制字段输出,例如跳过Password或替换成"[REDACTED]"; - 字段名必须导出(首字母大写),否则
json包无法访问; - 避免在
MarshalJSON里调用可能 panic 的方法(如未判空解引用u.Credentials.Token); - 若用第三方 JSON 库(如
easyjson),需确认其是否尊重json.Marshaler—— 大多数支持,但部分生成代码会绕过;
真正难缠的是嵌套 map 或 interface{} 类型字段,它们不会触发 MarshalJSON,得靠中间件在 c.JSON 调用前手动调用 SanitizeMap 扫描 key 白名单。











