美文网首页
soul从入门到放弃18--防火墙waf插件

soul从入门到放弃18--防火墙waf插件

作者: 滴流乱转的小胖子 | 来源:发表于2021-02-05 07:18 被阅读0次

    一、前戏

    waf插件,主要是用来对流量实现防火墙的核心功能:拦截非法请求、异常请求、拒绝策略

    二、soul-admin配置

    • 插件配置

    soul-admin –> 插件管理-> waf 设置为开启

    注意模式的选择:

    model 设置为 black 模式的时候,只有匹配的流量才会执行拒绝策略,不匹配的,直接会跳过。

    model 设置为 mixed 模式的时候,所有的流量都会通过 waf插件,针对不同的匹配流量,用户可以设置是拒绝,还是通过。

    • 选择器配置

    采用通配符匹配,匹配/http开头的请求

    image
    • 规则配置

    为了后面测试,配置两天规则,通过状态开关进行切换

    规则1: 匹配 http开头的所有 如:http://127.0.0.1:9195/http/order/findById?id=2

    image

    测试结果如下:

    image

    规则2:匹配http开头,有userId参数的url,如:http://127.0.0.1:9195/http/test/findByUserId?userId=1

    image

    测试结果如下:

    image.png

    三、soul-bootstrap配置

    • pom引入依赖,重启网关
      <dependency>
          <groupId>org.dromara</groupId>
          <artifactId>soul-spring-boot-starter-plugin-waf</artifactId>
          <version>${last.version}</version>
      </dependency>
    

    四、WafPlugin源码分析

    在父类AbstractSoulPlugin中判断插件是否可用、匹配选择器、匹配规则

    public abstract class AbstractSoulPlugin implements SoulPlugin {
        public Mono<Void> execute(final ServerWebExchange exchange, final SoulPluginChain chain) {
            String pluginName = named();
            // 获取插件配置
            final PluginData pluginData = BaseDataCache.getInstance().obtainPluginData(pluginName);
            // 是否开启插件,没有开启则传递下一下插件去处理
            if (pluginData != null && pluginData.getEnabled()) {
                // 获取选择器
                final Collection<SelectorData> selectors = BaseDataCache.getInstance().obtainSelectorData(pluginName);
                if (CollectionUtils.isEmpty(selectors)) {
                    return handleSelectorIsNull(pluginName, exchange, chain);
                }
                // 匹配选择器
                final SelectorData selectorData = matchSelector(exchange, selectors);
                if (Objects.isNull(selectorData)) {
                    return handleSelectorIsNull(pluginName, exchange, chain);
                }
                selectorLog(selectorData, pluginName);
                // 获取规则列表
                final List<RuleData> rules = BaseDataCache.getInstance().obtainRuleData(selectorData.getId());
                if (CollectionUtils.isEmpty(rules)) {
                    return handleRuleIsNull(pluginName, exchange, chain);
                }
                RuleData rule;
                // 如果是full,则获取最近的一个规则
                if (selectorData.getType() == SelectorTypeEnum.FULL_FLOW.getCode()) {
                    //get last
                    rule = rules.get(rules.size() - 1);
                } else {
                    // 根据规则匹配
                    rule = matchRule(exchange, rules);
                }
                if (Objects.isNull(rule)) {
                    return handleRuleIsNull(pluginName, exchange, chain);
                }
                ruleLog(rule, pluginName);
                // 交由子类WafPlugin去处理
                return doExecute(exchange, chain, selectorData, rule);
            }
            // 交由下一个插件去处理
            return chain.execute(exchange);
        }
    

    对匹配规则的请求进行,进行拒绝策略的处理

    public class WafPlugin extends AbstractSoulPlugin {
        protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
            // 获取Waf配置
            WafConfig wafConfig = Singleton.INST.get(WafConfig.class);
            // 如果没有匹配的选择器和规则
            if (Objects.isNull(selector) && Objects.isNull(rule)) {
                // 如果waf配置是black模式,则跳过。交由下一个插件处理
                if (WafModelEnum.BLACK.getName().equals(wafConfig.getModel())) {
                    return chain.execute(exchange);
                }
                // 设置 403 status code
                exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
                // 设置 error 信息
                Object error = SoulResultWrap.error(HttpStatus.FORBIDDEN.value(), Constants.REJECT_MSG, null);
                // 返回response
                return WebFluxResultUtils.result(exchange, error);
            }
            // 获取规则配置信息
            String handle = rule.getHandle();
            WafHandle wafHandle = GsonUtils.getInstance().fromJson(handle, WafHandle.class);
            // 如规则为Null或者permission为空,交由下一个插件处理
            if (Objects.isNull(wafHandle) || StringUtils.isBlank(wafHandle.getPermission())) {
                log.error("waf handler can not configuration:{}", handle);
                return chain.execute(exchange);
            }
            // 如果permission是reject,则返回 403 status code
            if (WafEnum.REJECT.getName().equals(wafHandle.getPermission())) {
                exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
                Object error = SoulResultWrap.error(Integer.parseInt(wafHandle.getStatusCode()), Constants.REJECT_MSG, null);
                // 返回response
                return WebFluxResultUtils.result(exchange, error);
            }
            // 交由下一个插件处理
            return chain.execute(exchange);
        }
    }
    

    五、小结

    • 在AbstractSoulPlugin中匹配选择器和规则,在WafPlugin中处理拒绝策略
    • 日拱一卒

    相关文章

      网友评论

          本文标题:soul从入门到放弃18--防火墙waf插件

          本文链接:https://www.haomeiwen.com/subject/eehwtltx.html