Use redis para hacer un módulo de defensa simple para resistir ataques de solicitud http maliciosos

Use redis para hacer un módulo de defensa simple para resistir ataques de solicitud http maliciosos


Prefacio

Soy un novato y no suelo tener el hábito de escribir csdn. Acabo de terminar un pequeño proyecto de subcontratación y no sucedió pronto. De repente tuve un capricho y una idea audaz. Durante muchos años, debido a que no podía creer el rendimiento del servidor Alibaba Cloud 2G + 1M, siempre he querido intentar construir un módulo de seguridad HTTP simple por mí mismo para evitar que los malos usen el acceso http a mi servidor a través de un navegador o programa. Vacío, planeo usar el redis recién aprendido para detectar ataques http maliciosos en el proyecto springboot original del mercado de segunda mano desarrollado por mí mismo. Ahora estoy haciendo un gran registro de este glorioso momento en csdn. Estoy acostumbrado a usar el código como parte del dictado del artículo. , Y no copiará el código a gran escala, por lo que puede haber cierta incomodidad si el springboot es débil. Por favor, perdóneme


Sugerencia: El siguiente es el contenido de este artículo, los siguientes casos son para referencia

1. Principios e ideas

Dado que redis es un servidor de caché basado en memoria, tiene un alto rendimiento y estabilidad y ha resistido la prueba del mercado. Se utilizan interceptores personalizados, solicitudes de conexión y redis para registrar el número de visitas recientes a cada ip de solicitud http. Si se encuentra una situación anormal (Enviar una gran cantidad de solicitudes en un corto período de tiempo) puede considerarse un ataque de solicitud HTTP malicioso. La IP se puede bloquear y la IP se puede registrar en el registro.

2. Pasos del procedimiento

1. Introduce dependencias y configura redis

Para facilitar las pruebas, utilizo mi computadora de trabajo para depurar y ejecutar el proyecto springboot, y el servidor de redis está construido en Alibaba Cloud. 

<!--redis 依赖-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>


#redis配置
spring.redis.host = ...
spring.redis.port = ... [默认6379]
spring.redis.password = [如果你的redis服务器有密码]
 

2. Personalice el serializador de redis y RedisTemplate

Necesitamos una RedisTemplate de tipo <String, Integer>, y requerimos que su valor se use de manera flexible como un entero en java y como una cadena en redis, sin conversión manual por nuestra parte, y al mismo tiempo, se puede garantizar en el servidor de redis. Legibilidad. La API de integración de redis en springboot proporciona la estúpida RedisTemplate <String, Integer>. Debido a que la serialización de Integer obviamente no cumple con nuestros requisitos, solo puedo personalizar una RedisTemplate y un serializador propio. Estoy acostumbrado a construir uno config, cree su propio bean de configuración a través del método bean en la clase del paquete

2.1. Serializador

  Defina una clase que implemente la interfaz RedisSerializer <Integer> y anule sus métodos de serialización y deserialización.

La idea de realización es muy simple, porque nuestro propósito es almacenar como caracteres de cadena en redis, y aparecer en forma de entero en java. Al serializar, convierta el entero en cadena y luego serialice, y deserialice el serializado. Convertir cadena en entero

@Override
public byte[] serialize(@Nullable Integer integer) throws SerializationException {
    return integer== null ? null : integer.toString().getBytes(StandardCharsets.UTF_8);
}



@Override
public Integer deserialize(@Nullable byte[] bytes) throws SerializationException {
    return bytes == null ? null : Integer.valueOf(new String(bytes, 
        StandardCharsets.UTF_8));
}

2.2.RedisTemplate

Simplemente podemos crear un objeto RedisTemplate <String, Integer> y usar una estrategia de serialización de cadenas para su clave (nota, no uses el estúpido serializador predeterminado de jdk, cuya estrategia de serialización no usa objetos de cadena como caracteres. La matriz de bytes se almacena y serializa en un símbolo extraño usado por humanos antiguos) Se usa el valor del serializador que personalizamos anteriormente, por lo que la operación principal es

setKeySerializer (nuevo StringRedisSerializer ());

setValueSerializer (intRedisSerializer);

El código completo es el siguiente

@Configuration
public class RedisConfig {

    @Autowired
    RedisSerializer<Integer> intRedisSerializer;

    @Bean("intRedisTemplate")
    public RedisTemplate<String, Integer> IntRedisTemplate(RedisConnectionFactory rcf){
        RedisTemplate<String, Integer> re = new RedisTemplate();
        re.setConnectionFactory(rcf);
        re.setKeySerializer(new StringRedisSerializer());
        re.setValueSerializer(intRedisSerializer);

        return re;
    }
}

Descripción: nombré intRedisSerializer al serializador de enteros anterior y lo inyecté en RedisTemplate

 

3. La clase de detective implementa la función principal de detectar ataques http.

Inteligente, es posible que hayas descubierto que el color de la fuente se ha vuelto más oscuro. Esto no se debe a que no sepa cómo cambiar el color de la fuente , ¡pero nuestro código central está a punto de comenzar! ! !

El nombre Detective (HttpDetective) me tomó casi 10 minutos. La interfaz solo declara un método de inspección (String ip) para determinar si esta ip puede acceder a su servidor, y luego creamos HttpDetectiveImpl para implementar sus funciones. Usamos Una estrategia simple y tolerante a fallas, ignorando el error de parámetro real que puede ser causado por asíncrono, pero esto no afectará nuestra función y seguridad. El código específico es el siguiente

@Component("httpDetective")
public class HttpDetectiveImpl implements HttpDetective {


    @Autowired
    private RedisTemplate<String, Integer> intRedisTemplate;

    /**单位均为毫秒*/
    private final int RECORD_TIME = 1000;
    private final int ALLOW_TIMES = 6;
    private final int REFUSE_TIME = 180000;


    @Override
    public boolean inspection(String ip) {
        Integer times = intRedisTemplate.opsForValue().get(ip);
        if(times == null){
            System.out.println("有正常人进入");
            intRedisTemplate.opsForValue().set(ip, 1, RECORD_TIME, TimeUnit.MILLISECONDS);
            return true;
        }else{
            if(times >= ALLOW_TIMES){
                System.out.println("认定为入侵行为 拦截访问 并且禁止目标短时间内再次访问并且记录 入侵者ip"+ ip);
                intRedisTemplate.opsForValue().set(ip, ALLOW_TIMES, REFUSE_TIME, TimeUnit.MILLISECONDS);
                return false;
            }else{
                System.out.println("有可疑人进入.  "+times);
                intRedisTemplate.opsForValue().increment(ip);
                return true;
            }
        }
    }
}

 

Inyectamos la RedisTemplate anterior en la clase de detective como herramienta para la clase de detective. Para facilitar las modificaciones posteriores, definimos tres constantes, todas en milisegundos

    RECORD_TIME: verifique el intervalo de tiempo para el acceso http
    ALLOW_TIMES: verifique el número de visitas dentro del intervalo de tiempo REFUSE_TIME:
    tiempo de bloqueo para el intruso

Usamos la ip pasada por el cliente como la clave de redis. Cuando el cliente acceda por primera vez, se creará el par clave-valor, y su ciclo de vida se configurará como RECORD_TIME. Aquí lo configuramos en un segundo. Durante este segundo, el usuario Acceda nuevamente a la interfaz, el valor correspondiente se incrementará en uno. Si el valor se agrega a ALLOW_TIMES durante la vida útil, se configurará como un intruso y ya no podrá acceder a nuestra url dentro de REFUSE_TIME. Es decir, la ip será bloqueada Devolverá falso dentro del período de tiempo, y si el intruso continúa intentando acceder a la interfaz http, se actualizará el tiempo de bloqueo. Aquí, se registrará como un bean llamado httpDetective

 

 

4. Monte la clase detective en el interceptor para lograr la detección de interceptación http

4.1 interceptor personalizado

Dado que el interceptor decide si emitir devolviendo verdadero y falso, solo es necesario inyectar directamente la clase de detective anterior para devolver su método de inspección.

@Autowired
HttpDetective httpDetective;

@Bean
public HandlerInterceptor visitorRegistration(){

    return new HandlerInterceptor(){
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            return httpDetective.inspection(request.getRemoteAddr());
        }
    };
}

4.3 Registrar el interceptor en springboot

El interceptor de registro Springboot es muy conveniente, siempre y cuando herede WebMvcConfigurer y agregue y cambie el interceptor en su método addInterceptors (registro InterceptorRegistry), preste atención para anotar esta clase como @Configuratio, no es necesario decir más aquí

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Resource
    HandlerInterceptor visitorRegistration;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        System.out.println("添加拦截器");
        // TODO Auto-generated method stub
        registry.addInterceptor(visitorRegistration)
                // 拦截路劲
                .addPathPatterns("/**");

    }
}

Tres, prueba funcional

Utilizo un centro comercial de segunda mano que se ha desarrollado como ejemplo y en primer lugar inicio el servidor

El servidor se inicia normalmente

Abra el navegador y deslice http frenéticamente (es posible que muchas personas no alcancen la velocidad de mi mano, o puede elegir deslizar la URL escribiendo un programa)

 

Podemos ver que en mi solicitud http que deslizo 20 segundos por segundo, todas las solicitudes después de la sexta vez han sido interceptadas y ya no se puede acceder a ellas en 3 minutos.

El redis en el servidor también tiene un registro de redis correspondiente

Cuatro, resumen y palabras posteriores

Aunque quiero saber que debe haber funciones relacionadas y un marco estable y eficiente, todavía me gusta implementar mis ideas repentinas o anteriores por mí mismo. El código puede tener ciertas desviaciones debido a la estructura asincrónica general del marco springboot. Pero esto no afectará su seguridad, y aquellos que estén interesados ​​también pueden implementar una implementación más estable o eficiente de la interfaz HttpDetective. Esta es la primera csdn que escribí en serio. Como no soy muy hábil, me tomó rápido Tres horas para completar. Perdóname por los errores tipográficos en el artículo. El autor es más hábil. Si hay algo incorrecto o sugerencia, por favor dame un consejo.

Supongo que te gusta

Origin blog.csdn.net/pass_JMC/article/details/109392153
Recomendado
Clasificación