zoukankan      html  css  js  c++  java
  • 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);
    }

    }


     
    小蚊子大人
  • 相关阅读:
    yii 引入文件
    CodeForces 621C Wet Shark and Flowers
    面试题题解
    POJ 2251 Dungeon Master
    HDU 5935 Car(模拟)
    HDU 5938 Four Operations(暴力枚举)
    CodeForces 722C Destroying Array(并查集)
    HDU 5547 Sudoku(dfs)
    HDU 5583 Kingdom of Black and White(模拟)
    HDU 5512 Pagodas(等差数列)
  • 原文地址:https://www.cnblogs.com/ywsheng/p/14976000.html
Copyright © 2011-2022 走看看