当前位置:首页 > 文章列表 > Golang > Go教程 > 为可信子域配置 CrossOriginProtection 放行规则

为可信子域配置 CrossOriginProtection 放行规则

来源:17golang原创 2026-10-09 07:59:06 0浏览 收藏

当控制台部署在 https://console.example.com,API 部署在 https://api.example.com 时,两者虽然属于同一站点,却不是同源。给 API 接入 http.CrossOriginProtection 后,控制台发出的 POST、PUT、PATCH、DELETE 请求需要用 AddTrustedOrigin 精确放行;最稳妥的规则是逐个登记完整的 scheme://host[:port],不要把整个 *.example.com 想当然地视为可信。

结论先说:为每个真实前端 Origin 建立精确白名单,在进程启动时完成格式校验,运行时只让通过来源检查的请求进入业务 Handler。新增子域必须显式变更配置并补测试。

官方文档:https://pkg.go.dev/net/http#CrossOriginProtection

场景:同站点子域不等于同源

一个常见拆分是官网、运营控制台和 API 各占一个子域。浏览器从控制台向 API 发起写请求时,Sec-Fetch-Site 可能是 same-site,但 CrossOriginProtection 的默认直接放行条件是 same-origin 或 none。这正是许多团队接入后遇到 403 的原因:域名看起来属于同一家公司,浏览器安全模型看到的却是两个 Origin。

这里不应该关闭保护,也不应该把所有子域一次性放开。子域可能由不同团队、不同应用甚至第三方平台承载,一处子域失陷不应自动获得向 API 提交写操作的能力。把控制台的完整 Origin 加入可信清单,才能把边界收敛到真正需要调用 API 的前端。

请求输入:先看保护器实际使用哪些信号

CrossOriginProtection 保护的是非安全方法的浏览器请求。官方文档说明,GET、HEAD、OPTIONS 始终允许,因此这些方法不能承担状态修改。对于其他方法,保护器主要读取 Sec-Fetch-Site,必要时再比较 Origin 主机与请求 Host;如果两个头都没有,当前实现将请求视为同源或非浏览器请求并允许。

可信子域规则只作用于带有 Origin 的请求,并要求 Origin 头与登记值完全一致。这意味着下面三项都属于规则的一部分:

  • scheme:http 与 https 是不同 Origin;
  • host:console.example.com 与 admin.example.com 必须分别登记;
  • port:显式端口不同,也应按不同 Origin 管理。
请求方法 Sec-Fetch-Site Origin Host 可信 Origin 清单经过 CrossOriginProtection 到业务处理器或拒绝处理器的关系图
图1:可信子域写请求的判断输入与处理结果。白名单匹配的是完整 Origin,不是域名后缀。

配置校验:在启动阶段逐条登记可信 Origin

可信来源适合放在部署配置中,但不要在每次请求里解析字符串。下面的代码从逗号分隔配置读取 Origin,启动时逐条调用 AddTrustedOrigin;任何一条格式错误都直接终止启动,避免服务带着残缺白名单上线。

package main

import (
    "fmt"
    "log"
    "net/http"
    "os"
    "strings"
    "time"
)

func newCrossOriginProtection(raw string) (*http.CrossOriginProtection, error) {
    protection := http.NewCrossOriginProtection()

    for _, item := range strings.Split(raw, ",") {
        origin := strings.TrimSpace(item)
        if origin == "" { // 跳过空配置项,避免把空字符串登记为规则
            continue
        }
        if err := protection.AddTrustedOrigin(origin); err != nil {
            return nil, fmt.Errorf("可信 Origin %q 无效: %w", origin, err)
        }
    }

    protection.SetDenyHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // 只记录判断所需的低敏感度字段,不记录 Cookie、令牌或请求体。
        log.Printf("cross-origin denied method=%s path=%s origin=%q fetch_site=%q",
            r.Method, r.URL.Path, r.Header.Get("Origin"), r.Header.Get("Sec-Fetch-Site"))
        http.Error(w, "禁止跨源写入", http.StatusForbidden)
    }))
    return protection, nil
}

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("POST /api/orders", func(w http.ResponseWriter, r *http.Request) {
        // 生产代码仍要在这里完成身份认证、权限校验、输入校验和持久化。
        w.WriteHeader(http.StatusNoContent)
    })

    protection, err := newCrossOriginProtection(os.Getenv("TRUSTED_ORIGINS"))
    if err != nil {
        log.Fatal(err) // 配置错误时失败退出,避免静默缺少可信来源
    }

    server := &http.Server{
        Addr:              ":8080",
        Handler:           protection.Handler(mux), // 在业务路由之前统一执行来源检查
        ReadHeaderTimeout: 5 * time.Second,
    }
    log.Fatal(server.ListenAndServe())
}

生产环境可以设置 TRUSTED_ORIGINS=https://console.example.com,https://admin.example.com。本地开发若使用 http://localhost:5173,应放在开发环境自己的配置里,不能混入生产白名单。AddTrustedOrigin 接受的是 Origin,而不是 URL 页面地址,因此不能包含路径、查询参数或片段。

存储模型:精确清单比通配符更容易审计

官方 API 的语义是 Origin 头与登记值精确匹配,并没有“可信主域名后缀”的配置含义。即使组织拥有 example.com,也不要尝试用 https://*.example.com 表达放行;需要访问 API 的控制台有几个,就登记几个完整 Origin。

这种写法看似多了几行配置,却带来三个好处:代码审查能看见新增信任关系;下线旧控制台时可以单独删除规则;端口或 scheme 变更不会在不知情的情况下继承权限。对于动态租户子域,如果数量很大,不应简单扩大 CSRF 白名单,而应重新评估调用方式、身份边界和令牌模型。

可信 Origin 从部署配置经启动校验进入保护器再到路由包装拒绝日志回归测试和规则清理的生命周期图
图2:可信 Origin 配置生命周期。规则从变更、校验、应用到审计和清理都应留下明确边界。

查询路径:一条写请求如何得到最终结果

把请求决策按顺序梳理后,排查 403 会简单很多:

  1. 如果方法是 GET、HEAD、OPTIONS,直接允许;
  2. 如果浏览器信号表明请求同源,允许进入业务 Handler;
  3. 如果 Origin 与某条可信 Origin 完全一致,允许进入;
  4. 如果请求直接命中显式绕过模式,则绕过检查;
  5. 其他非安全跨源浏览器请求进入拒绝 Handler,默认状态码为 403。

Handler 适合统一包装整个 mux。若必须把检查结果嵌入已有中间件,也可以调用 Check,但要注意它只返回错误,不会自动执行 SetDenyHandler。两种接法不要同时重复检查,以免日志和拒绝响应出现两次。

异常处理:可信 Origin、CORS 和路由绕过不要混用

能力解决的问题使用原则
AddTrustedOrigin允许明确的跨子域浏览器写请求逐个登记完整 Origin
CORS 响应头决定浏览器脚本能否读取跨源响应按前端读取需求单独配置,不能替代 CSRF 防护
AddInsecureBypassPattern让直接命中特定 ServeMux 模式的请求全部跳过检查仅用于有独立签名认证的机器接口等少数场景
SetDenyHandler统一 403 格式、指标和低敏感度日志不回显内部规则,不记录 Cookie 或令牌

遇到合法请求被拒绝时,先确认浏览器发出的 Origin 是否与配置逐字一致,再检查 scheme、端口和环境配置。不要为了快速恢复而给整个 API 添加绕过模式。官方文档明确指出,AddInsecureBypassPattern 会允许所有直接匹配该 ServeMux 模式的请求,并且无效或冲突模式会触发 panic。

清理策略:用测试固定边界,用审计删除旧规则

白名单是会随部署变化的安全数据。每次新增 Origin 都应附上用途、负责人和下线条件;旧控制台迁移完成后及时删除对应规则。拒绝指标可以按路由、Origin 和 Sec-Fetch-Site 聚合,但要限制标签基数,并避免收集敏感字段。

至少应覆盖四组回归:同源写请求通过;登记的控制台 Origin 通过;未登记的兄弟子域得到 403;安全方法通过但不产生状态变化。另外再测一个无浏览器来源头的服务调用,确认它仍然依靠令牌或签名完成认证,而不是误把 CrossOriginProtection 当作 API 鉴权。

当可信子域数量开始快速增长时,先停下来检查架构。精确 Origin 清单的价值就在于让信任扩张可见;如果每个新租户都必须成为高权限浏览器来源,真正需要调整的往往是认证和调用模型,而不是继续堆白名单。

相关问题

能否写成 https://*.example.com? 不建议,也不符合 AddTrustedOrigin 的精确匹配语义。应登记每个完整 Origin。

同站点子域为什么还会被拦截? same-site 与 same-origin 不是同一个概念。跨子域浏览器写请求需要显式建立信任。

配置了可信 Origin 后还要配置 CORS 吗? 如果前端脚本需要读取跨源响应,仍要配置合适的 CORS;两者职责不同。

默认拒绝响应是什么? Handler 默认返回 403,也可以通过 SetDenyHandler 自定义响应和日志。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Linux pidfd 如何避免按 PID 操作进程的竞态Linux pidfd 如何避免按 PID 操作进程的竞态
上一篇
Linux pidfd 如何避免按 PID 操作进程的竞态
反向代理后 CrossOriginProtection 误判来源怎么办
下一篇
反向代理后 CrossOriginProtection 误判来源怎么办
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    386次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    468次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    475次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    415次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    240次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码