Envoy CSRF 保护过滤器实现分析

1. 概述

Envoy 的 CSRF 保护过滤器提供了一种简单而有效的方法来防止跨站点请求伪造攻击。它通过验证请求的 Origin 或 Referer 头部与目标 origin 匹配来实现保护,并提供了灵活的配置选项,包括:

  1. 运行时配置,可动态启用/禁用功能

  2. 影子模式,用于测试保护策略

  3. 附加受信任源配置,增强了保护的灵活性

  4. 详细的统计信息,帮助监控和识别潜在的攻击

该过滤器的设计简洁而高效,仅对修改方法请求进行验证,减少了不必要的处理。它与其他 Envoy 过滤器集成良好,并提供了与外部授权系统配合使用的支持。

通过正确配置 CSRF 保护过滤器,您可以显著提高应用程序的安全性,防止恶意网站利用用户的身份信息执行未经授权的操作。

2. 解决的问题

CSRF 保护过滤器主要解决以下问题:

2.1 防止跨站点请求伪造攻击

  • 验证请求的来源是否与目标 origin 匹配

  • 确保修改方法(如 POST、PUT、DELETE、PATCH)请求来自受信任的源

  • 防止恶意网站通过用户浏览器发送未经授权的请求

2.2 灵活的配置选项

  • 支持运行时配置,可在不重启 Envoy 的情况下启用或禁用功能

  • 提供影子模式(Shadow Mode),用于测试保护策略而不影响实际流量

  • 允许配置附加的受信任源,增加了保护的灵活性

2.3 性能优化

  • 仅对修改方法请求进行验证,减少了不必要的处理

  • 使用 StringMatcher 实现高效的 origin 匹配

  • 与其他 Envoy 过滤器集成良好

2.4 详细的统计信息

  • 提供关于请求验证结果的详细统计数据

  • 帮助监控和识别潜在的 CSRF 攻击

  • 支持日志记录和调试

3. 架构设计

3.1 核心组件架构

3.2 类图

4. 配置用例

4.1 基础配置

bash 复制代码
http_filters:- name: envoy.filters.http.csrf  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.csrf.v3.CsrfPolicy    filter_enabled:      runtime_key: "csrf.enabled"      default_value:        numerator: 100        denominator: HUNDRED    shadow_enabled:      runtime_key: "csrf.shadow_enabled"      default_value:        numerator: 0        denominator: HUNDRED    additional_origins:    - exact: "https://trusted-domain1.com"    - exact: "https://trusted-domain2.com"

4.2 运行时配置

makefile 复制代码
layered_runtime:  layers:  - name: static_layer    static_layer:      csrf:        enabled:          numerator: 100          denominator: HUNDRED        shadow_enabled:          numerator: 50          denominator: HUNDRED

4.3 按路由配置

css 复制代码
route_config:  name: local_route  virtual_hosts:  - name: backend    domains: ["*"]    routes:    - match: { prefix: "/public" }      route: { cluster: backend }    - match: { prefix: "/private" }      route: { cluster: backend }      typed_per_filter_config:        envoy.filters.http.csrf:          "@type": type.googleapis.com/envoy.extensions.filters.http.csrf.v3.CsrfPolicy          filter_enabled:            runtime_key: "csrf.private.enabled"            default_value:              numerator: 100              denominator: HUNDRED          additional_origins:          - exact: "https://private-trusted.com"

4.4 高级配置

swift 复制代码
http_filters:- name: envoy.filters.http.csrf  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.csrf.v3.CsrfPolicy    filter_enabled:      runtime_key: "csrf.enabled"      default_value:        numerator: 100        denominator: HUNDRED    shadow_enabled:      runtime_key: "csrf.shadow_enabled"      default_value:        numerator: 50        denominator: HUNDRED    additional_origins:    - exact: "https://trusted-domain.com"    - prefix: "https://*.trusted-domain.com"    - regex: "^https://.*\\.trusted-domain\\.com$"

5. 工作流程分析

5.1 过滤器执行流程

5.2 CSRF 保护交互流程

6. 代码实现 ER 图

7. 最佳实践

7.1 基本防护策略

bash 复制代码
http_filters:- name: envoy.filters.http.csrf  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.csrf.v3.CsrfPolicy    filter_enabled:      runtime_key: "csrf.enabled"      default_value:        numerator: 100        denominator: HUNDRED    additional_origins:    - exact: "https://your-trusted-domain.com"

7.2 影子模式配置

bash 复制代码
http_filters:- name: envoy.filters.http.csrf  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.csrf.v3.CsrfPolicy    filter_enabled:      runtime_key: "csrf.enabled"      default_value:        numerator: 0        denominator: HUNDRED    shadow_enabled:      runtime_key: "csrf.shadow_enabled"      default_value:        numerator: 100        denominator: HUNDRED

7.3 高级 origin 匹配

swift 复制代码
http_filters:- name: envoy.filters.http.csrf  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.csrf.v3.CsrfPolicy    additional_origins:    - exact: "https://api.your-domain.com"    - prefix: "https://*.your-domain.com"    - regex: "^https://.*\\.your-domain\\.com$"

7.4 结合认证使用

bash 复制代码
http_filters:- name: envoy.filters.http.jwt_authn  typed_config:    # 认证配置...- name: envoy.filters.http.csrf  typed_config:    "@type": type.googleapis.com/envoy.extensions.filters.http.csrf.v3.CsrfPolicy    filter_enabled:      runtime_key: "csrf.enabled"      default_value:        numerator: 100        denominator: HUNDRED    additional_origins:    - exact: "https://your-trusted-domain.com"

8. 代码实现细节

8.1 方法验证逻辑

cpp 复制代码
bool isModifyMethod(const Http::RequestHeaderMap& headers) {  const absl::string_view method_type = headers.getMethodValue();  if (method_type.empty()) {    return false;  }  const auto& method_values = Http::Headers::get().MethodValues;  return (method_type == method_values.Post || method_type == method_values.Put ||          method_type == method_values.Delete || method_type == method_values.Patch);}

8.2 来源验证逻辑

cpp 复制代码
std::string sourceOriginValue(const Http::RequestHeaderMap& headers) {  const auto origin = hostAndPort(headers.getInlineValue(origin_handle.handle()));  if (!origin.empty()) {    return origin;  }  return hostAndPort(headers.getInlineValue(referer_handle.handle()));}
std::string targetOriginValue(const Http::RequestHeaderMap& headers) {  const auto host_value = headers.getHostValue();
  if (host_value.empty()) {    return EMPTY_STRING;  }
  const auto absolute_url = fmt::format(      "{}://{}", headers.Scheme() != nullptr ? headers.getSchemeValue() : "http", host_value);  return hostAndPort(absolute_url);}
bool CsrfFilter::isValid(const absl::string_view source_origin, Http::RequestHeaderMap& headers) {  const auto target_origin = targetOriginValue(headers);  if (source_origin == target_origin) {    return true;  }
  for (const auto& additional_origin : policy_->additionalOrigins()) {    if (additional_origin->match(source_origin)) {      return true;    }  }
  return false;}

8.3 策略决策逻辑

php 复制代码
void CsrfFilter::determinePolicy() {  const CsrfPolicy* policy =      Http::Utility::resolveMostSpecificPerFilterConfig<CsrfPolicy>(callbacks_);  if (policy != nullptr) {    policy_ = policy;  } else {    policy_ = config_->policy();  }}
Http::FilterHeadersStatus CsrfFilter::decodeHeaders(Http::RequestHeaderMap& headers, bool) {  determinePolicy();
  if (!policy_->enabled() && !policy_->shadowEnabled()) {    return Http::FilterHeadersStatus::Continue;  }
  if (!isModifyMethod(headers)) {    return Http::FilterHeadersStatus::Continue;  }
  bool is_valid = true;  const auto source_origin = sourceOriginValue(headers);  if (source_origin.empty()) {    is_valid = false;    config_->stats().missing_source_origin_.inc();  }
  if (!isValid(source_origin, headers)) {    is_valid = false;    config_->stats().request_invalid_.inc();  }
  if (is_valid == true) {    config_->stats().request_valid_.inc();    return Http::FilterHeadersStatus::Continue;  }
  if (policy_->shadowEnabled() && !policy_->enabled()) {    return Http::FilterHeadersStatus::Continue;  }
  callbacks_->sendLocalReply(Http::Code::Forbidden, "Invalid origin", nullptr, absl::nullopt,                             RcDetails::get().OriginMismatch);  return Http::FilterHeadersStatus::StopIteration;}
相关推荐
sbjdhjd1 小时前
Redis 主从复制、哨兵高可用与 Cluster 集群部署实验手册
运维·前端·redis·云原生·开源·bootstrap·html
乐兮创想 小林1 小时前
企业官网移动端性能优化实战:从 Core Web Vitals 到图片/CDN/响应式的工程清单
前端·性能优化·网站建设·北京网站建设公司
前端一小卒2 小时前
不手写代码的第 30 天,我才明白前端这个岗位还剩什么
前端·javascript·ai编程
Ajie'Blog2 小时前
Copilot Agent Tasks API 开放:AI 编程开始进入后台任务时代
服务器·前端·javascript·人工智能·copilot·ai编程
老毛肚2 小时前
jeecgboot vue TS & 模板化 04
前端·javascript·vue.js
AI_零食4 小时前
鸿蒙PC Electron跨平台应用开发:24时区时间表应用详解
前端·华为·electron·开源·harmonyos·鸿蒙
Electrolux4 小时前
[onlyoffice-v9]纯前端怎么实现编辑预览office
前端·javascript·github
码云之上5 小时前
聊聊如何设计一个高效、稳定的 Node.js 接入层
前端·后端·node.js
kyriewen5 小时前
我读了一遍 Babel 编译后的 async/await,终于搞懂了它的原理(附 20 行手写实现)
前端·javascript·面试
IT_陈寒6 小时前
Vite项目build后路由404了?你可能漏了这个小配置
前端·人工智能·后端