【高性能网关soul学习】18. 插件之 waf
本文目标:
- 分析 soul 插件 SentinelPlugin 集成 Sentinel 的源码
waf 插件是由 soul网关自己实现的,是 soul 其他插件的前置插件,主要用来拦截非法请求,或者异常请求,并且给与相关的拒绝策略。
Soul 中 Waf 插件启动流程
-
依次启动 soul-admin、http测试服务、soul-bootstrap 网关服务
- 不需要额外增加依赖
-
打开 系统管理 >> 插件 >> 启用 Waf 插件
- 黑名单模式:当
model
设置为black
模式,只有匹配的流量才会执行拒绝策略 - 混合模式:当
model
设置为 mixed 模式,针对不同的流量,可以选择通过或者拒绝
- 黑名单模式:当
-
打开 插件列表 >> waf >> 选择器和规则配置
- 参考 选择器配置规则
-
选择器中可以针对 ip 和 host 进行匹配,然后执行拒绝策略,这种配置方式在针对攻击的时候非常有用
WafPlugin 执行流量过滤的原理
WafPlugin 继承于 AbstractSoulPlugin, 因此和其他流量插件一样,核心方法为 doExecute
- doExecute执行前,已经筛选到了最匹配的规则
- black模式
- mixed模式
- 如果没有配置 选择器和规则,则会直接报错返回403 error
protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
WafConfig wafConfig = Singleton.INST.get(WafConfig.class);
if (Objects.isNull(selector) && Objects.isNull(rule)) {
// 黑名单模式下,会继续执行
if (WafModelEnum.BLACK.getName().equals(wafConfig.getModel())) {
return chain.execute(exchange);
}
// 返回拒绝
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
Object error = SoulResultWrap.error(403, Constants.REJECT_MSG, null);
return WebFluxResultUtils.result(exchange, error);
}
// 从匹配的规则中获取配置的属性
String handle = rule.getHandle();
WafHandle wafHandle = GsonUtils.getInstance().fromJson(handle, WafHandle.class);
// 如果未配置则默认允许通过
if (Objects.isNull(wafHandle) || StringUtils.isBlank(wafHandle.getPermission())) {
log.error("waf handler can not configuration:{}", handle);
return chain.execute(exchange);
}
// 如果是拒绝策略,则执行拒绝逻辑
if (WafEnum.REJECT.getName().equals(wafHandle.getPermission())) {
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
Object error = SoulResultWrap.error(Integer.parseInt(wafHandle.getStatusCode()), Constants.REJECT_MSG, null);
return WebFluxResultUtils.result(exchange, error);
}
return chain.execute(exchange);
}
总结
- 由以上代码克制,Waf 插件的实现非常简单,只是简单的对两种模式及拒绝与否两种状态的判断、考虑选择器与规则未配置的情况等
- 关键的匹配 selector 和 rule 的逻辑已经在
AbstractSoulPlugin
中进行了实现