• gateway


    SQL注入,跨站脚本攻击(XSS),跨站请求伪造(CSRF)

    ApiRequestGlobalFilter api请求全局过滤器
    ApiRequestXssSqllFilter api请求XssSql过滤器

    ApiResponseGlobalFilter api返回全部过滤器

    VerifyCondition 验证
    CorsConfigration 跨域配置
    WhiteListProperties 白名单配置
    ManageGatewayProperties 网关配置


    Exception
    error 处理
    jsonException 处理


    package com.box.manage.gateway.filter;

    import com.box.common.core.constant.RequestConstant;
    import com.box.common.core.enums.ErrorCodeEnum;
    import com.box.common.core.exception.AuthException;
    import com.box.common.core.utils.GatewayUtils;
    import com.box.common.core.utils.JwtUtils;
    import com.box.common.core.utils.StringUtils;
    import com.box.redis.service.RedisService;
    import io.jsonwebtoken.Claims;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.core.Ordered;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.MediaType;
    import org.springframework.stereotype.Component;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;

    import javax.annotation.Resource;
    import java.io.UnsupportedEncodingException;
    import java.net.URLEncoder;
    import java.util.function.Consumer;

    /**
    * 授权认证 https://blog.csdn.net/zzxzzxhao/article/details/83381876
    *
    * @author yuan.dingwang
    * @date 2020年11月26日 15:53
    */
    @Slf4j
    @Component
    class ApiRequestGlobalFilter implements GlobalFilter, Ordered {

    final static String METHOD = "POST";

    @Autowired
    RedisService redisService;

    @Resource
    VerifyCondition verify;


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

    String token = exchange.getRequest().getHeaders().getFirst(RequestConstant.HEADER_ACCESS_TOKEN);
    log.info("ApiRequestGlobalFilter token:{}",token);
    //platform用于区分不同的端
    String platform = exchange.getRequest().getHeaders().getFirst(RequestConstant.HEADER_PLATFORM);
    if (StringUtils.isBlank(platform)) {
    platform = exchange.getRequest().getQueryParams().getFirst(RequestConstant.HEADER_PLATFORM);
    }
    String requestUrl = exchange.getRequest().getPath().toString();
    String subject = "";
    //回调地址直接过滤
    if (requestUrl.contains("/v2/api-docs") || requestUrl.contains("/threeParties/notice/")) {

    Consumer<HttpHeaders> headersConsumer = httpHeaders -> {
    httpHeaders.set(RequestConstant.HEADER_SAFETY_LABEL_NAME,RequestConstant.HEADER_SAFETY_LABEL_VAL);
    // httpHeaders.setContentType(MediaType.APPLICATION_JSON);
    };

    exchange.mutate().request(exchange.getRequest().mutate()
    .headers(headersConsumer).build()).build();
    return chain.filter(exchange);
    }

    //验证平台端编码是否正确
    if (verify.checkPlatform(platform)) {
    return GatewayUtils.responseError(exchange, ErrorCodeEnum.AUTH_PLATFORM);
    }
    //白名单验证
    if (!verify.checkWhiteIsLogin(requestUrl)) {
    //验证token是否有效
    if (verify.checkToken(token, Integer.valueOf(platform))) {
    log.info("ApiRequestGlobalFilter checkToken");
    return GatewayUtils.responseError(exchange, ErrorCodeEnum.AUTH_TOKEN_INVALID);
    }
    //验证用户是在别的地方登陆
    if (verify.checkRedis(token, Integer.valueOf(platform))) {
    return GatewayUtils.responseError(exchange, ErrorCodeEnum.AUTH_TOKEN_SWITCH);
    }

    try {
    Claims claims = JwtUtils.infoJWT(token, Integer.valueOf(platform));
    subject = URLEncoder.encode(claims.getSubject(), "utf-8");
    } catch (UnsupportedEncodingException e) {
    log.error("[{}] 请求参数:{}, 网关解析参数encode错误:{}", requestUrl, token, e);
    return GatewayUtils.responseError(exchange, ErrorCodeEnum.SERVER);
    }
    }
    if (!verify.checkWhiteIsPer(requestUrl)) {
    //验证用户是否有权限访问
    if (!verify.checkPermissions(token, Integer.valueOf(platform), requestUrl)) {
    return GatewayUtils.responseError(exchange, ErrorCodeEnum.AUTH_PERMISSIONS);
    }
    }

    exchange.mutate().request(exchange.getRequest().mutate().header(RequestConstant.HEADER_USER_LOGIN_INFO, subject).build()).build();
    exchange.mutate().request(exchange.getRequest().mutate().header(RequestConstant.HEADER_ACCESS_TOKEN, token).build()).build();
    exchange.mutate().request(exchange.getRequest().mutate().header(RequestConstant.HEADER_PLATFORM, platform).build()).build();
    exchange.mutate().request(exchange.getRequest().mutate().header(RequestConstant.HEADER_SAFETY_LABEL_NAME,
    RequestConstant.HEADER_SAFETY_LABEL_VAL).build()).build();
    return chain.filter(exchange);

    }

    @Override
    public int getOrder() {
    return 1;
    }
    }




    package com.box.manage.gateway.filter;

    import com.alibaba.fastjson.JSONObject;
    import com.box.common.core.enums.ErrorCodeEnum;
    import com.box.common.core.rt.Result;
    import com.box.common.core.utils.*;
    import io.netty.buffer.ByteBufAllocator;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.core.Ordered;
    import org.springframework.core.io.buffer.DataBuffer;
    import org.springframework.core.io.buffer.DataBufferUtils;
    import org.springframework.core.io.buffer.NettyDataBufferFactory;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpMethod;
    import org.springframework.http.MediaType;
    import org.springframework.http.server.reactive.ServerHttpRequest;
    import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
    import org.springframework.http.server.reactive.ServerHttpResponse;
    import org.springframework.stereotype.Component;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Flux;
    import reactor.core.publisher.Mono;

    import java.io.UnsupportedEncodingException;
    import java.net.URI;
    import java.nio.charset.StandardCharsets;
    import java.util.Optional;

    /**
    * 文件描述
    *
    * @author yuan.dingwang
    * @date 2021年02月26日 15:35
    */
    @Slf4j
    @Component
    public class ApiRequestXssSqllFilter implements GlobalFilter, Ordered {

    private static final String START_TIME = "startTime";

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    log.info("----自定义网关全局过滤器生效----");
    ServerHttpRequest serverHttpRequest = exchange.getRequest();
    HttpMethod method = serverHttpRequest.getMethod();
    String contentType = serverHttpRequest.getHeaders().getFirst(HttpHeaders.CONTENT_TYPE);
    URI uri = exchange.getRequest().getURI();

    //记录请求开始时间
    exchange.getAttributes().put(START_TIME, SystemClockUtils.millisClock().now());

    // 排除流文件类型,比如上传的文件contentType.contains("multipart/form-data")
    if (GatewayUtils.isUploadFile(serverHttpRequest.getHeaders().getContentType())) {

    log.info("{} - [{}] 文件上传请求放行", method, uri.getPath());
    return chain.filter(exchange);
    }

    //过滤get请求
    if (method == HttpMethod.GET) {

    String rawQuery = uri.getRawQuery();
    log.info("{} - [{}] 请求参数:{}", method, uri.getPath(), rawQuery);
    if (StringUtils.isBlank(rawQuery)) {
    return chain.filter(exchange);
    }
    // 执行sql注入校验清理
    boolean chkRet = false;
    try {
    rawQuery = XssCleanRuleUtils.xssGetClean(rawQuery);
    chkRet = SqLinjectionRuleUtils.getRequestSqlKeyWordsCheck(rawQuery);
    } catch (UnsupportedEncodingException e) {
    log.error("{} - [{}] 请求参数:{}, 网关解析参数错误:{}", method, uri.getPath(), rawQuery, e);
    return GatewayUtils.responseError(exchange, ErrorCodeEnum.SERVER);
    }

    //如果存在sql注入,直接拦截请求
    if (chkRet) {
    log.info("请求【" + uri.getRawPath() + uri.getRawQuery() + "】参数中包含不允许sql的关键词, 请求拒绝");
    return GatewayUtils.responseError(exchange, ErrorCodeEnum.CHECK_SQL_ILLEGAL);
    }
    //透传参数,不对参数做任何处理
    return chain.filter(exchange).then(Mono.fromRunnable(() -> {
    Long startTime = exchange.getAttribute(START_TIME);
    if (startTime != null) {
    Long executeTime = (SystemClockUtils.millisClock().now() - startTime);
    log.info("【{}】 耗时:{} ms", exchange.getRequest().getURI().getRawPath(), executeTime);
    }
    }));
    } else if (method == HttpMethod.POST) {
    //post请求时,如果是文件上传之类的请求,不修改请求消息体
    return DataBufferUtils.join(serverHttpRequest.getBody()).flatMap(d -> Mono.just(Optional.of(d))).defaultIfEmpty(
    Optional.empty())
    .flatMap(optional -> {
    // 取出body中的参数
    String bodyString = "";
    if (optional.isPresent()) {
    byte[] oldBytes = new byte[optional.get().readableByteCount()];
    optional.get().read(oldBytes);
    bodyString = new String(oldBytes, StandardCharsets.UTF_8);
    }
    HttpHeaders httpHeaders = serverHttpRequest.getHeaders();
    // 执行XSS清理
    boolean chkRet = false;
    log.info("{} - [{}] 请求参数:{}", method, uri.getPath(), bodyString);
    if (MediaType.APPLICATION_JSON_VALUE.equals(contentType)) {
    //如果MediaType是json才执行json方式验证
    bodyString = XssCleanRuleUtils.xssPostClean(bodyString);
    chkRet = SqLinjectionRuleUtils.postRequestSqlKeyWordsCheck(bodyString);
    } else {
    //form表单方式,需要走get请求
    try {
    bodyString = XssCleanRuleUtils.xssGetClean(bodyString);
    chkRet = SqLinjectionRuleUtils.getRequestSqlKeyWordsCheck(bodyString);
    } catch (UnsupportedEncodingException e) {
    log.error("{} - [{}] 请求参数:{}, 网关解析参数错误:{}", method, uri.getPath(), bodyString, e);
    return GatewayUtils.responseError(exchange, ErrorCodeEnum.SERVER);
    }
    }

    // 如果存在sql注入,直接拦截请求
    if (chkRet) {
    log.info("{} - [{}] 参数:{}, 包含不允许sql的关键词,请求拒绝", method, uri.getPath(), bodyString);
    return GatewayUtils.responseError(exchange, ErrorCodeEnum.CHECK_SQL_ILLEGAL);
    }
    ServerHttpRequest newRequest = serverHttpRequest.mutate().uri(uri).build();
    // 重新构造body
    byte[] newBytes = bodyString.getBytes(StandardCharsets.UTF_8);
    DataBuffer bodyDataBuffer = GatewayUtils.toDataBuffer(newBytes);
    Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);

    // 重新构造header
    HttpHeaders headers = new HttpHeaders();
    headers.putAll(httpHeaders);
    // 由于修改了传递参数,需要重新设置CONTENT_LENGTH,长度是字节长度,不是字符串长度
    int length = newBytes.length;
    headers.remove(HttpHeaders.CONTENT_LENGTH);
    headers.setContentLength(length);
    headers.set(HttpHeaders.CONTENT_TYPE, serverHttpRequest.getHeaders().getFirst(HttpHeaders.CONTENT_TYPE));
    // 重写ServerHttpRequestDecorator,修改了body和header,重写getBody和getHeaders方法
    newRequest = new ServerHttpRequestDecorator(newRequest) {
    @Override
    public Flux<DataBuffer> getBody() {
    return bodyFlux;
    }

    @Override
    public HttpHeaders getHeaders() {
    return headers;
    }
    };
    exchange.getResponse();
    return chain.filter(exchange.mutate().request(newRequest).build()).then(Mono.fromRunnable(() -> {
    Long startTime = exchange.getAttribute(START_TIME);
    if (startTime != null) {
    Long executeTime = (SystemClockUtils.millisClock().now() - startTime);
    log.info("【{}】 耗时:{} ms", exchange.getRequest().getURI().getRawPath(), executeTime);
    }
    }));
    });
    } else {
    return GatewayUtils.responseError(exchange, ErrorCodeEnum.SERVER_NOT_METHOD);
    }

    }

    @Override
    public int getOrder() {
    return 0;
    }



    }




    package com.box.manage.gateway.filter;

    import lombok.extern.slf4j.Slf4j;
    import org.reactivestreams.Publisher;
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.core.Ordered;
    import org.springframework.core.io.buffer.DataBuffer;
    import org.springframework.core.io.buffer.DataBufferFactory;
    import org.springframework.core.io.buffer.DataBufferUtils;
    import org.springframework.http.HttpMethod;
    import org.springframework.http.server.reactive.ServerHttpResponse;
    import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
    import org.springframework.stereotype.Component;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Flux;
    import reactor.core.publisher.Mono;

    import java.net.URI;
    import java.nio.charset.Charset;

    /**
    * 文件描述
    *
    * @author yuan.dingwang
    * @date 2021年04月14日 10:26
    */
    @Slf4j
    @Component
    public class ApoResponseGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public int getOrder() {
    // -1 is response write filter, must be called before that
    return -2;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    ServerHttpResponse originalResponse = exchange.getResponse();
    DataBufferFactory bufferFactory = originalResponse.bufferFactory();
    HttpMethod method = exchange.getRequest().getMethod();
    URI uri = exchange.getRequest().getURI();
    ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
    @Override
    public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
    if (body instanceof Flux) {
    Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
    return super.writeWith(fluxBody.map(dataBuffer -> {
    // probably should reuse buffers
    byte[] content = new byte[dataBuffer.readableByteCount()];
    dataBuffer.read(content);
    //释放掉内存
    DataBufferUtils.release(dataBuffer);
    String data = new String(content, Charset.forName("UTF-8"));
    log.info("{} - [{}] 响应数据:{}", method, uri.getPath(), data);
    //TODO,data就是response的值,想修改、查看就随意而为了
    byte[] uppedContent = new String(content, Charset.forName("UTF-8")).getBytes();
    return bufferFactory.wrap(uppedContent);
    }));
    }
    // if body is not a flux. never got there.
    return super.writeWith(body);
    }
    };
    return chain.filter(exchange.mutate().response(decoratedResponse).build());
    }
    }



    package com.box.manage.gateway.filter;

    import com.box.common.core.constant.CacheKeyConstant;
    import com.box.common.core.enums.PlatformEnum;
    import com.box.common.core.utils.JwtUtils;
    import com.box.common.core.utils.StringUtils;
    import com.box.manage.gateway.config.WhiteListProperties;
    import com.box.redis.service.RedisService;
    import io.jsonwebtoken.Claims;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;

    import javax.annotation.Resource;

    /**
    * 验证类
    *
    * @author yuan.dingwang
    * @date 2020年12月16日 16:54
    */
    @Component
    public class VerifyCondition {

    @Autowired
    RedisService redisService;

    @Resource
    WhiteListProperties whiteListProperties;

    /**
    * 验证平台端访问参数
    *
    * @param platform
    * @return
    */
    public boolean checkPlatform(String platform) {
    //验证平台端编码是否正确
    if (StringUtils.isBlank(platform)) {
    return true;
    }
    //验证平台端编码是否正确
    if (!PlatformEnum.isCheck(Integer.valueOf(platform))) {
    return true;
    }
    return false;
    }

    /**
    * 不需要登录的地址
    *
    * @param path
    * @return
    */
    public boolean checkWhiteIsLogin(String path) {
    return whiteListProperties.loginVerify(path);
    }

    /**
    * 不需要登录的地址
    *
    * @param path
    * @return
    */
    public boolean checkWhiteIsPer(String path) {
    return whiteListProperties.perVerify(path);
    }


    /**
    * 验证token是否有效
    *
    * @param token
    * @return
    */
    public boolean checkToken(String token, Integer platform) {
    //验证token是否有效
    if (StringUtils.isBlank(token)) {
    return true;
    }
    //验证token是否有效
    if (!JwtUtils.checkJWT(token, platform)) {
    return true;
    }
    //验证用户是否过期
    Claims claims = JwtUtils.infoJWT(token, platform);
    if (StringUtils.isNull(claims) || StringUtils.isNull(claims.getId())
    || StringUtils.isNull(claims.get("roles"))) {
    return true;
    }
    return false;
    }

    /**
    * 验证用户是否在别处登录
    *
    * @param token
    * @return
    */
    public boolean checkRedis(String token, Integer platform) {
    Claims claims = JwtUtils.infoJWT(token, platform);
    //验证用户是否过期
    StringBuffer key = new StringBuffer(CacheKeyConstant.CECHE_MANAGE_USER_TOKEN).append(platform).append(":").append(claims.getId());
    Object dbToken = redisService.get(key.toString());
    if (StringUtils.isNull(dbToken)) {
    return true;
    }
    //验证用户是在别的地方登陆
    if (!token.equals(dbToken.toString())) {
    return true;
    }
    return false;
    }

    /**
    * 验证权限
    *
    * @param token
    * @param platform
    * @param path
    * @return
    * /merchants/merchants/manage/getMerchantByPage 20210528000000191240
    */
    public boolean checkPermissions(String token, Integer platform, String path) {
    path = newPath(path);
    Claims claims = JwtUtils.infoJWT(token, platform);
    String roles = claims.get("roles").toString();
    StringBuffer key = new StringBuffer(CacheKeyConstant.CECHE_MANAGE_PERMISSION).append(platform);
    Object dbRoles = redisService.hget(key.toString(), path);
    String[] roleArray = roles.split(",");
    for (String role : roleArray) {
    if (roles.equals("000000")){
    //系统端超级管理员
    return true;
    }
    }
    if (StringUtils.isNull(dbRoles)) {
    return false;
    }
    //当前用户角色id是否在dbRoles内
    Boolean bool = false;
    for (String role : roleArray) {
    if (dbRoles.toString().contains(role)) {
    bool = true;
    break;
    }
    }
    return bool;
    }

    public static void main(String[] args) {
    //System.out.println("66666,22222".contains("66666,1111"));
    String aa = "/open/manage/scoreBanck/openDeails";
    String url = "/manage/scoreBanck/openDeails";
    String r = "20210615000000462987,20210603000000384153,20210525000000128275,20210603000000446357,20210615000000368119,20210608000001015766,20210607000000578123,20210525000000128174";
    VerifyCondition v = new VerifyCondition();
    aa = aa.substring(5);
    System.out.println(aa);
    System.out.println(aa.equals(url));

    }

    private String newPath(String path) {
    //return path.replace("/open", "");
    return path.substring(5);
    }

    }


     
    小蚊子大人
  • 相关阅读:
    Project2013 界面目录清单
    informix11.7界面入门工具
    informix11.7默认数据库表
    Informix服务器端和客户端配置都用服务器软件配置情况
    RHEL7.1安装后进入X环境
    pluswell on rhel5.4
    vmware10在centos6.5上安装log记录
    LINUX自带多路径详解
    安装win7英文语言包(通用)
    亚信的点滴生活
  • 原文地址:https://www.cnblogs.com/ywsheng/p/14976000.html
Copyright © 2020-2023  润新知