默认路由匹配不防注入,因Echo的GET/POST等方法仅做路径字符串匹配,不校验参数内容;如/user/:id会将../../etc/passwd原样传入c.Param("id"),校验须由开发者在handler或中间件中显式实现。

为什么默认路由匹配不防注入
Echo 的 GET、POST 等注册方法本身不校验路径参数内容,只做字符串匹配。比如你写 r.GET("/user/:id", handler),框架会把 /user/../../etc/passwd 里的 ../../etc/passwd 当作 id 原样塞进 c.Param("id")——它不会自动拒绝含 ..、/ 或空字节的值,更不会过滤 SQL 片段或 JS 标签。这不等于漏洞,而是设计使然:路由层只负责分发,校验必须由你显式加在 handler 或中间件里。
路径参数注入拦截:用正则预匹配 + 提前终止
别等进 handler 再 parse,直接在路由定义时用正则约束参数格式。Echo 支持 :paramname=regexp 语法,匹配失败自动返回 404(不进 handler):
-
r.GET("/post/:slug=[a-z0-9]+(?:-[a-z0-9]+)*", postHandler)—— 强制 slug 只能是小写字母、数字和短横线组合 -
r.GET("/user/:id=[0-9]{1,10}", userHandler)—— id 必须是 1~10 位纯数字,直接拦住1'; DROP TABLE users-- - 避免用
:id这种裸参数,尤其当它会拼进 SQL 或文件路径时
注意:正则只作用于单个参数段,/../ 这类跨段路径遍历仍需靠中间件统一处理。
全局路径遍历与危险字符拦截中间件
所有请求都经过的兜底防护,重点拦截 URL 中的 ..、%00、// 和控制字符:
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 在
e.Use()中注册中间件,用c.Request().URL.Path检查原始路径 - 用
strings.Contains()或bytes.IndexByte()快速扫描..和\x00,比正则更快也更可控 - 发现可疑字符立即
c.String(400, "Invalid path")并 return,不调用next(c) - 别依赖
filepath.Clean()后再比对——攻击者可绕过,比如/a/./b/../c清理后是/a/c,但原始路径已含危险模式
示例判断逻辑:if strings.Contains(c.Request().URL.Path, "..") || bytes.Contains(c.Request().URL.RawPath, []byte{0}) { ... }
动态路由与控制器调用场景的特殊风险
如果你用 r.Any("/*path", fallbackHandler) 或类似通配路由,风险陡增——这时 path 可能是任意字符串,甚至带查询参数伪造。必须:
- 禁止在 fallbackHandler 中直接
include或evalpath对应的文件名 - 若需映射到控制器,坚持白名单机制:
map[string]func(){ "dashboard": dashboard, "profile": profile },不在 map 中就 404 - 警惕
c.QueryParam("action")这类从 query 拿行为名的做法,它和 ThinkPHP 的s=参数一样容易触发 RCE,必须严格限制可选值
真正难防的是“合法路径+非法语义”,比如 /api/export?format=csv&table=users; DROP TABLE logs--——这种得靠后续业务层的 SQL 参数化,路由层只能拦明面上的畸形路径。


















