如何阻止Google App Engine任意子域名匹配默认服务?
我在Google App Engine标准环境部署了Strapi作为默认服务,默认URL为https://my-project.uc.r.appspot.com。当创建其他版本或服务时,新URL格式为https://[identifier]-dot-my-project.uc.r.appspot.com,但现在任意替换[identifier]都能访问到Strapi应用,希望仅允许合法的URL(比如dev-dot-my-project.uc.r.appspot.com)访问,非法URL直接拒绝。
问题根源
Google App Engine标准环境中,默认服务(default service)的路由逻辑是兜底规则:任何未匹配到现有服务/版本的[anything]-dot-[project-id].uc.r.appspot.com请求,都会被自动路由到默认服务。这就是为什么随便输入identifier都能打开你的应用——和Strapi无关,是GAE的默认路由特性。
解决方案
方案一:在Strapi中添加Host头校验(推荐,无需修改GAE服务结构)
利用GAE会将完整请求Host传递给应用的特性,在Strapi中添加自定义中间件,只允许指定的Host访问。
- 创建自定义中间件文件
在Strapi项目中新建./src/middlewares/host-validation/index.js,写入以下代码:
module.exports = (strapi) => { return { initialize() { strapi.app.use(async (ctx, next) => { // 配置允许访问的合法Host列表 const allowedHosts = [ 'my-project.uc.r.appspot.com', 'dev-dot-my-project.uc.r.appspot.com' // 按需添加其他合法版本/服务的URL ]; const requestHost = ctx.request.host; if (!allowedHosts.includes(requestHost)) { ctx.status = 403; ctx.body = 'Forbidden: Invalid Host'; return; } await next(); }); }, }; };
- 注册中间件
修改./config/middlewares.js,将自定义中间件放在最前面,确保优先执行校验:
module.exports = [ './middlewares/host-validation', // 放在最顶部 'strapi::errors', 'strapi::security', 'strapi::cors', 'strapi::poweredBy', 'strapi::logger', 'strapi::query', 'strapi::body', 'strapi::session', 'strapi::favicon', 'strapi::public', ];
- 重新部署Strapi到GAE
修改完成后,重新部署应用即可生效。此时非法Host的请求会直接返回403禁止访问。
方案二:放弃默认服务,使用明确命名的服务
如果不想在应用层处理,可以彻底抛弃默认服务,创建明确命名的服务(如prod、dev),这样只有对应服务的URL能被路由到应用,其他随机URL会返回GAE的404页面。
- 修改
app.yaml,添加服务名称
在原app.yaml顶部添加service: prod,将默认服务改为命名服务:
runtime: nodejs16 env: standard service: prod # 添加这一行 instance_class: F2 env_variables: HOST: '0.0.0.0' NODE_ENV: 'production' # 其他环境变量... beta_settings: cloud_sql_instances: '<instance_identifier>'
- 部署命名服务
执行部署命令:
gcloud app deploy --service=prod
- 为其他环境创建独立服务
比如创建dev环境的配置文件app-dev.yaml,设置service: dev,部署到dev服务:
gcloud app deploy app-dev.yaml --service=dev
此时只有prod-dot-my-project.uc.r.appspot.com和dev-dot-my-project.uc.r.appspot.com能访问对应服务,其他任意identifier的URL会返回404。
为什么修改handlers的url规则无效?
你尝试修改url: .*为url: /.*没用,是因为handlers中的url字段匹配的是请求路径(比如/admin、/api/posts),而不是请求的Host头。问题出在GAE的服务路由层面,不是路径匹配,所以修改handlers无法限制子域名访问。
内容的提问来源于stack exchange,提问作者Sizzin

