Используйте redis, чтобы создать простой модуль защиты для защиты от вредоносных атак http-запросов

Используйте redis, чтобы создать простой модуль защиты для защиты от вредоносных атак http-запросов


Предисловие

Я новичок, и обычно у меня нет привычки писать csdn. Я только что закончил небольшой аутсорсинговый проект, и в этом нет ничего плохого. Вдруг у меня появляется прихоть и смелая идея. В течение многих лет, поскольку я не мог поверить в производительность облачного сервера Alibaba 2G + 1M, я всегда хотел попытаться самостоятельно создать простой модуль безопасности HTTP, чтобы злоумышленники не могли использовать http-доступ к моему серверу через браузер или программу. Пусто, я планирую использовать недавно изученный redis для обнаружения вредоносных http-атак на исходный проект springboot для вторичного рынка, разработанный мной. Теперь я делаю отличную запись этого славного момента на csdn. Я привык использовать код как часть диктовки статьи. , И не будет копировать код в больших масштабах, поэтому может возникнуть некоторый дискомфорт, если основа Springboot слабая. Пожалуйста, простите меня


Совет: Ниже приводится содержание этой статьи, следующие случаи приведены для справки.

1. Принципы и идеи

Поскольку redis является кеш-сервером на основе памяти, он обладает высокой производительностью и стабильностью и выдержал рыночные испытания. Пользовательские перехватчики, запросы на соединение и redis используются для записи количества недавних посещений каждого IP-адреса http-запроса. Если обнаружена ненормальная ситуация (Отправка большого количества запросов за короткий период времени) может рассматриваться как злонамеренная атака HTTP-запросов. IP-адрес может быть заблокирован, а IP-адрес может быть записан в журнал.

2. Этапы процедуры

1. Введите зависимости и настройте Redis.

Чтобы облегчить тестирование, я использую свой рабочий компьютер для отладки и запуска проекта springboot, а сервер Redis построен на 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. Настройте сериализатор Redis и RedisTemplate.

Нам нужен RedisTemplate типа <String, Integer>, и мы требуем, чтобы его значение гибко использовалось как целое число в java и как строка в redis, без ручного преобразования с нашей стороны, и в то же время это может быть гарантировано на сервере Redis. Удобочитаемость. API интеграции redis в Springboot предоставляет глупый RedisTemplate <String, Integer>. Поскольку сериализация Integer явно не соответствует нашим требованиям, я могу настроить только RedisTemplate и сериализатор самостоятельно. Я привык создавать его config, создайте свой собственный компонент конфигурации с помощью метода компонента в классе пакета.

2.1. Сериализатор

  Определите класс, реализующий интерфейс RedisSerializer <Integer>, и переопределите его методы сериализации и десериализации.

Идея реализации очень проста, потому что наша цель - хранить строковые символы в Redis и отображать их в виде целых чисел в java. При сериализации преобразуйте целое число в строку, а затем сериализуйте и десериализуйте сериализованный Преобразовать строку в целое число

@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

Мы можем просто создать объект RedisTemplate <String, Integer> и использовать стратегию сериализации строк для его ключа (обратите внимание, не используйте глупый сериализатор по умолчанию jdk, стратегия сериализации которого не использует строковый объект в качестве символа Массив байтов сохраняется и сериализуется в странный символ, используемый древними людьми). Используется значение сериализатора, которое мы настроили выше, поэтому основная операция

setKeySerializer (новый StringRedisSerializer ());

setValueSerializer (intRedisSerializer);

Весь код выглядит следующим образом

@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;
    }
}

Описание: я назвал предыдущий целочисленный сериализатор intRedisSerializer и ввел его в RedisTemplate.

 

3. Детективный класс реализует основную функцию обнаружения http-атак.

Умно, возможно, вы обнаружили, что цвет шрифта стал темнее. Это не потому, что я не знаю, как изменить цвет шрифта , но наш основной код вот-вот начнется! ! !

Имя Detective (HttpDetective) заняло у меня почти 10 минут. Интерфейс только объявляет метод проверки (String ip), чтобы определить, может ли этот ip получить доступ к вашему серверу, а затем мы создаем HttpDetectiveImpl для реализации его функций. Мы используем Простая и отказоустойчивая стратегия, игнорирующая фактические ошибки параметров, которые могут быть вызваны асинхронностью, но это не повлияет на нашу работу и безопасность. Конкретный код выглядит следующим образом

@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;
            }
        }
    }
}

 

Мы внедряем предыдущий шаблон RedisTemplate в класс детективов в качестве инструмента для класса детективов. Чтобы облегчить последующие модификации, мы определяем три константы, все в миллисекундах.

    RECORD_TIME: проверить временной интервал http доступа
    ALLOW_TIMES: проверить количество посещений во временном интервале REFUSE_TIME:
    время блокировки для злоумышленника

Мы используем IP-адрес, переданный клиентом, в качестве ключа redis. Когда клиент обращается в первый раз, будет создана пара ключ-значение, а ее время жизни будет установлено как RECORD_TIME. Здесь мы устанавливаем его равным одной секунде. В течение этой секунды пользователь будет Получите доступ к интерфейсу снова, соответствующее значение будет увеличено на единицу. Если значение будет добавлено к ALLOW_TIMES в течение жизненного цикла, оно будет установлено как злоумышленник и больше не сможет получить доступ к нашему URL-адресу в течение REFUSE_TIME. То есть IP-адрес будет заблокирован Вернет false в течение периода времени, и если злоумышленник продолжит попытки доступа к интерфейсу http, время блокировки будет обновлено. Здесь он будет зарегистрирован как bean-компонент с именем httpDetective

 

 

4. Установите детективный класс в перехватчик, чтобы реализовать обнаружение перехвата http.

4.1 кастомный перехватчик

Поскольку перехватчик решает, следует ли выдавать, возвращая истину или ложь, необходимо только напрямую ввести вышеуказанный детективный класс, чтобы вернуть его метод проверки.

@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 Зарегистрируйте перехватчик в Springboot

Перехватчик регистрации Springboot очень удобен, поскольку он наследует WebMvcConfigurer и добавляет и изменяет перехватчик в своем методе addInterceptors (реестр InterceptorRegistry), обратите внимание на аннотацию этого класса как @Configuratio, здесь больше не нужно говорить

@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("/**");

    }
}

Три, функциональный тест

Я использую подержанный торговый центр, который был разработан в качестве примера, и сначала запускаю сервер

Сервер запускается нормально

Откройте браузер и отчаянно пролистайте http (многие люди могут не достичь моей скорости, или вы можете провести по URL-адресу, написав программу)

 

Мы видим, что в http-запросе я делал 20 кистей в секунду, все запросы после шестого раза были перехвачены и не могли быть доступны в течение 3 минут.

Redis на сервере также имеет соответствующую запись Redis

Четыре, резюме и последующие слова

Хотя я хочу знать, что должны быть связанные функции и стабильный и эффективный фреймворк, мне все же нравится реализовывать мои внезапные или предыдущие идеи самостоятельно.Код может иметь определенные отклонения из-за общей асинхронной структуры фреймворка Springboot. Но это не повлияет на его безопасность, и те, кто заинтересован, могут также реализовать более стабильную или эффективную реализацию интерфейса HttpDetective. Это первая csdn, которую я написал серьезно. Поскольку я не очень опытен, это заняло у меня быстро Три часа на завершение. Пожалуйста, простите меня за опечатки в статье. Автор более опытен. Если есть что-то не так или есть предложение, дайте мне совет.

рекомендация

отblog.csdn.net/pass_JMC/article/details/109392153