WAF和注射保护
1)为什么WAF在API时代
即使经过严格的验证和参数化,注射也是由于以下原因引起的:- 集成的"长尾巴"(遗传代码,附属网络手册),
- 解析差异(代理↔框架),
- 新的协议/混淆旁路技术。
- WAF在代码发布之前给出了早期故障(早期破坏)和"虚拟补丁"的界限,但无法替代安全开发。
2)威胁模型: API的注射类型
SQLi/ORMi: classic/boolean/time-based/stacked;blind通过延迟。
NoSQLi (Mongo/Elastic):运算符'$ne/$gt'、JSON injection, regex-DoS。
Command Injection/RCE: shell-metasivols,变换参数,unsafe deserialization → code exec。
XXE: XML 中的外部实体/DTD。
SSRF: 访问'169。254.169.254英寸/内部服务;DNS-rebinding.
Template Injection: Jinja/Thymeleaf/Handlebars; `{{77}}`.
LDAP/EL Injection, XPath, Header injection (CRLF), Path traversal.
GraphQL特定:"__计划"引入,查询深度/复杂性。
JSON/JS特定:原型Pollution("__原型__","constructor")。
gRPC/Protobuf:超频消息,通过电路不匹配进行现场窃听。
3) WAF架构
CDN-WAF周边:快速geo/ASN过滤、基本机器人控制、缓存/反打孔。
L7外围(NGINX/Envoy/APISIX/Kong):精确的解析、深层规则、与PDP/限制的集成。
Sidekar/Mashe (Envoy WASM/Filter):接近数据的per服务对内部API的假阳性较小。
建议:双层模型(CDN-WAF+L7 WAF)。
4)分离,正常化和反旁路
WAF必须看到与应用程序相同的规范表示:- 路径正常化('/a/% 2e% 2e/b' →故障),'UTF-8'/Unicode confusables, NUL字节。
- 统一解码:URL -/HTML -/Unicode -/Base64层,禁止双重解码。
- 限制:"max_headers","max_header_size","max_body_size","max_args",JSON深度,多片限制,2x gzip/zip炸弹禁令。
- Content-Type策略:"application/json"仅适用于JSON尾端;拒绝"polyglot"。
5)规则模型
负面(签名):OWASP CRS(SQLi/XSS/SSRF/Java/Node RCE等)。快速启动。
正面(allow-list):严格的方案(JSON Schema/Protobuf),类型和范围;沿着路线。
异常/得分:"可疑"特征的总和→锁定阈值。
上下文:"POST/payments"和"GET/status"的不同配置文件;小于FP。
6)保护单元(捆绑在一起)
1.方案和类型:JSON 方案/Protobuf验证业务逻辑。
2.参数化:准备好的表达式,ORM宾语,禁止串联。
3.输出映射:HTML/JS/SQL上下文。
4.主体策略:Content-Type,尺寸,multipart限制,JSON手柄禁止二进制。
5.WAF规则:CRS+定制负面/正面。
6.Rate/Quota/Concurrency:brute/turtle DDoS抑制,公共形式的防护帽/挑战。
7.网络隔离:SSRF的egress策略(deny RFC1918/metadata/Unix sockets)。
8.头部卫生:"X-Conte-Type-Options:nosniff",前部的"Content-Security-Policy","Referrer-Policy"。
9.GraphQL guard:深度/复杂性限制,禁止在销售(或角色门)中引入。
7)配置示例
7.1 NGINX + ModSecurity (OWASP CRS)
nginx load_module modules/ngx_http_modsecurity_module.so;
modsecurity on;
modsecurity_rules_file /etc/modsecurity/modsecurity.conf;
modsecurity_rules '
SecRuleEngine On
Подключаем CRS
Include /etc/modsecurity/crs/crs-setup.conf
Include /etc/modsecurity/crs/rules/.conf
Позитивные правила: только JSON и ограничение размера
SecRule REQUEST_HEADERS:Content-Type "!@rx ^application/json($;)" "id:10001,phase:1,deny,status:415,msg:'Only JSON allowed'"
SecRequestBodyLimit 1048576
SecRequestBodyNoFilesLimit 1048576
Блок локальных адресов (SSRF)
SecRule REQUEST_HEADERS:Host "@ipmatch 127.0.0.0/8 10.0.0.0/8 169.254.0.0/16 192.168.0.0/16" \
"id:10002,phase:1,deny,status:403,msg:'Blocked private range'"
';
server {
listen 443 ssl http2;
server_name api.example.com;
client_max_body_size 1m;
proxy_request_buffering on; # защита от slow-POST proxy_read_timeout 300ms;
proxy_connect_timeout 100ms;
location /v1/ {
proxy_pass http://app_backends;
}
}
7.2 Envoy HTTP WAF (WASM + JSON Schema + SSRF egress-deny)
yaml http_filters:
- name: envoy.filters.http.wasm typed_config:
config:
vm_config: { vm_id: waf, code: { local: { filename: /plugins/waf.wasm } } }
configuration:
"@type": type.googleapis.com/google.protobuf.Struct value:
crs_profile: "strict"
deny_patterns: ["(?i)union.select", "(?i)(sleep benchmark)\\s\\("]
json_schema:
"/v1/payments:create": "/schemas/payments_create.json"
- name: envoy.filters.http.router
Egress SSRF guard (L4): deny private ranges from gateway filter_chains:
- filters:
- name: envoy.filters.network.tcp_proxy typed_config:
stat_prefix: egress cluster: internet access_log: [...]
tunneling_config:
hostname: "%REQ(:authority)%"
transport_socket:
name: envoy.transport_sockets.tls
7.3 APISIX:类型限制和反溷淆
yaml routes:
- uri: /v1/
plugins:
cors: { allow_origins: "https://app.example.com" }
request-validation:
body_schema:
{"type":"object","properties":{"amount":{"type":"number","minimum":1}},"required":["amount"]}
uri-blocker:
block_rules: ["..","%2e%2e","%2f..","\\x00"] # traversal/NULL proxy-rewrite:
headers:
set:
X-Content-Type-Options: "nosniff"
8)调节和减少误报(FP)
按路线配置文件:仅在适当时才有严格的规则(例如"/search"允许"/"%")。
Shadow/Report-Only:在单元前计算触发;A/B比较指标。
"嘈杂"合法参数的定制allow列表。
评分:仅在指标和>阈值时阻止。
实验:→自动回滚的新规则的流量百分比很小。
9)可观察性和力学
Метрики: `waf_block_total{rule}`, `waf_anomaly_score`, `request_body_rejected_total`, `schema_violation_total`, `ssrf_block_total`.
Logi(采样):规则,查询的一部分(编辑),"trace_id", "tenant", "route",原因。伪装PII/秘密。
Dashbords:顶级规则/路径,FP集群,发布后的扬声器。
事件:保存工件(payload、pcap如有必要)、RCA产品和"虚拟补丁"。
10)测试和溷乱场景
WAF绕行语料库(SQLi/XSS/SSRF),双/三重编码,由Unicode混合。
Parsing差异:发送代理和框架可能发散的payload(参数对比、数组、'vs'&)。
Slow-POST/oversize,zip炸弹,多件形式,有缺陷的边界。
GraphQL:深度/复杂度发生器,限制和计时器检查。
11)反模式
"打开CRS并忘记了":没有电路,没有路线调整。
带有原始查询体和PII的日志。
没有标准化/尺寸限制→绕行,每个解析的DoS。
跳过"Content-Type"/charset检查→多重攻击。
云元数据的SSRF →缺少无表征滤波器。
一个用于外部和内部API的通用配置文件。
"伙伴"的失控例外→外围漏洞。
12) iGaming/财务细节
加固的支付/输出手柄上的配置文件:小型车身限制、严格的方桉、帐户/IBAN/PAN字段的deny列表(掩蔽、格式检查)。
PSP/KYC的Webhooks:HMAC签名/互连TLS,单独的WAF配置文件,反复制。
地理/ASN过滤器和行为限制,以防止机器人注册和奖励算法。
事件日志不变(审计),按司法管辖区存储。
13)准备就绪支票清单
- 双层WAF (CDN+L7)、单一规范化和尺寸限制。
- OWASP CRS包括在内,按路线定制规则;写笔上的JSON 计划/Protobuf。
- Content-Type/charset策略;禁止双重解码/NULL/traversal。
- SSRF-egress 单元到私有范围/metadata;DNS重组保护。
- Rate/Quota/Concurrency和Anti-Bot(挑战)在公共表格上。
[] Shadow/Report-Only → canary → enforce;SLO和FP上的自动回滚。
- 蒙版度量/logi/traces;"顶级规则"/FP dashbords。
- 虚拟补丁和RCA的花花公子;定期的绕行测试。
- PSP/KYC网络手册、支付笔和内部API的单独配置文件。
14) TL;DR
按层构建保护:归一化和限制→方桉/类型→参数化→ WAF (CRS+cast) → rate/bot过滤器→ egress SSRF单元。在阴影→金丝雀中按路线调节,运行新规则,关注度量/FP,并在代码虚假化之前进行"虚拟补丁"。对于支付/webhook路径-单独严格的配置文件,HMAC/mTLS和最低限度的信任窗口。