Используйте 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, которую я написал серьезно. Поскольку я не очень опытен, это заняло у меня быстро Три часа на завершение. Пожалуйста, простите меня за опечатки в статье. Автор более опытен. Если есть что-то не так или есть предложение, дайте мне совет.