/// <summary> /// Получить html для AntiBot /// </summary> /// <param name="tplName">Имя шаблона</param> /// <param name="conf">Настройки AntiBot</param> /// <param name="CoreApiUrl">Ссылка на /core/</param> /// <param name="IP">IPv4/6</param> /// <param name="HostConvert">Домен</param> /// <param name="reCAPTCHASitekey">Секретный ключ reCAPTCHA</param> /// <param name="CacheAntiBot">Кеширование ответа</param> /// <param name="AntiBotHashKey">Дополнительный хеш для проверки "SignalR/JS"</param> static string Html(AntiBotType tplName, AntiBotBase conf, string CoreApiUrl, string IP, string HostConvert, string reCAPTCHASitekey, int CacheAntiBot, string AntiBotHashKey) { #region Базовые параметры string tplToUrl = string.Empty; var mass = new Dictionary <string, string>(); mass.Add("IP", IP); mass.Add("CoreApiUrl", CoreApiUrl); mass.Add("HourCacheToUser", conf.HourCacheToUser.ToString()); mass.Add("WaitUser", conf.WaitUser.ToString()); mass.Add("AddCodeToHtml", conf.AddCodeToHtml != null ? conf.AddCodeToHtml : string.Empty); mass.Add("JsToRewriteUser", JsToRewriteUser(conf.RewriteToOriginalDomain, HostConvert)); #endregion #region Хеш и куки switch (tplName) { case AntiBotType.SignalR: mass.Add("host", HostConvert); mass.Add("AntiBotHashKey", AntiBotHashKey); mass.Add("HashToSignalR", md5.text($"{IP}:{HostConvert}:{conf.HourCacheToUser}:{AntiBotHashKey}:{PasswdTo.salt}")); tplToUrl = File.Exists($"{Folders.Tpl.AntiBot}/{tplName}.html") ? "/statics/tpl/AntiBot/SignalR.html" : "/statics/tpl/AntiBot/default/SignalR.html"; break; case AntiBotType.reCAPTCHA: mass.Add("reCAPTCHASitekey", reCAPTCHASitekey); mass.Add("HashToreCAPTCHA", md5.text($"{IP}:{conf.HourCacheToUser}:{PasswdTo.salt}")); tplToUrl = File.Exists($"{Folders.Tpl.AntiBot}/{tplName}.html") ? "/statics/tpl/AntiBot/reCAPTCHA.html" : "/statics/tpl/AntiBot/default/reCAPTCHA.html"; break; case AntiBotType.CookieAndJS: string cookie = GetValidCookie(conf.HourCacheToUser, IP, "js", AntiBotHashKey); mass.Add("ValidCookie", cookie); mass.Add("AntiBotHashKey", AntiBotHashKey); Trigger.OnSetValidCookie((IP, HostConvert, cookie, "js", conf.HourCacheToUser)); tplToUrl = File.Exists($"{Folders.Tpl.AntiBot}/{tplName}.html") ? "/statics/tpl/AntiBot/CookieAndJS.html" : "/statics/tpl/AntiBot/default/CookieAndJS.html"; break; } #endregion // Сериализуем данные string json = JsonConvert.SerializeObject(mass); #region Создаем кеш if (CacheAntiBot != 0) { //IMemoryCache var memoryCache = Service.Get <IMemoryCache>(); memoryCache.Set(KeyToMemoryCache.AntiBotToCache(IP), (tplToUrl, json, tplName), TimeSpan.FromMilliseconds(CacheAntiBot)); } #endregion // Успех return(Html(tplToUrl, json)); }
/// <summary> /// Проверка запроса /// </summary> /// <param name="IP">IPv4/6</param> /// <param name="antiBotType">Cпособ проверки</param> /// <param name="HostConvert">Домен</param> /// <param name="method">Метод запроса</param> /// <param name="uri">Url запроса</param> /// <param name="HttpContext">Используется для проверки cookie</param> /// <param name="domain">Кеш настроек домена</param> /// <param name="DomainID">Id домена</param> /// <param name="outHtml">html для вывода пользователю</param> public static bool ValidRequest(string IP, AntiBotType antiBotType, string HostConvert, string method, string uri, HttpContext HttpContext, Models.core.Cache.CheckLink.Domain domain, int DomainID, out string outHtml) { // По умолчанию null outHtml = null; // Не выбран способ проверки if (antiBotType == AntiBotType.Off) { return(true); } #region Проверка Cookie if (IsValidCookie(HttpContext, IP, domain.AntiBot.HashKey, out string _verification)) { Trigger.OnValidCookie((IP, HostConvert, DomainID, true, _verification)); return(true); } else { Trigger.OnValidCookie((IP, HostConvert, DomainID, false, _verification)); } #endregion // IMemoryCache var memoryCache = Service.Get <IMemoryCache>(); // База var jsonDB = Service.Get <JsonDB>(); #region Отдаем данные с кеша if (jsonDB.Cache.AntiBot != 0 && memoryCache.TryGetValue(KeyToMemoryCache.AntiBotToCache(IP), out (string tplToUrl, string json, AntiBotType type)_cache)) { outHtml = Html(_cache.tplToUrl, _cache.json); Trigger.OnResponseView((IP, HostConvert, DomainID, _cache.type)); return(false); } #endregion // Достаем настройки AntiBot из кеша var antiBotToGlobalConf = GlobalConf(jsonDB.AntiBot); #region Проверка User-Agent if (HttpContext.Request.Headers.TryGetValue("User-Agent", out var userAgent)) { // Проверка пользовательского User-Agent if (WhiteUserList.IsWhiteUserAgent(userAgent)) { return(true); } string SearchBot = "(" + // https://yandex.ru/support/webmaster/robot-workings/check-yandex-robots.html "YandexBot|YandexAccessibilityBot|YandexMobileBot|YandexDirectDyn|YandexScreenshotBot|YandexImages|YandexVideo|YandexVideoParser|YandexMedia|YandexBlogs|YandexFavicons|YandexWebmaster|YandexPagechecker|YandexImageResizer|YandexAdNet|YandexDirect|YaDirectFetcher|YandexCalendar|YandexSitelinks|YandexMetrika|YandexNews|YandexCatalog|YandexMarket|YandexVertis|YandexForDomain|YandexSpravBot|YandexSearchShop|YandexMedianaBot|YandexOntoDB|YandexVerticals" + "|" + // https://support.google.com/webmasters/answer/1061943 "APIs-Google|Mediapartners-Google|AdsBot-Google|Googlebot" + "|" + // https://help.mail.ru/webmaster/indexing/robots/robot_log // https://www.bing.com/webmaster/help/how-to-verify-bingbot-3905dc26 "Mail.RU_Bot|Bingbot|msnbot" + ")"; // Проверка User-Agent на поискового бота if (Regex.IsMatch(userAgent, SearchBot, RegexOptions.IgnoreCase)) { #region Локальный метод - "DNSLookup" bool DNSLookup() { string ptr = null; string memKey = $"local-fb23a52e:DNSLookup-{IP}"; if (memoryCache.TryGetValue(memKey, out bool _cacheToDNSLookup)) { return(_cacheToDNSLookup); } // Создаем временный кеш на время проверки memoryCache.Set(memKey, true, TimeSpan.FromMinutes(5)); try { // Получаем имя хоста по IP var host = Dns.GetHostEntryAsync(IP).Result; // Получаем IP хоста по имени host = Dns.GetHostEntryAsync(host.HostName).Result; // Сохраняем PTR ptr = host.HostName; // Проверяем имя хоста и IP на совпадение if (host.AddressList.Where(i => i.ToString() == IP).FirstOrDefault() != null) { // Проверяем имя хоста на белый список DNSLookup if (Regex.IsMatch(host.HostName, @".*\.(yandex.(ru|net|com)|googlebot.com|google.com|mail.ru|search.msn.com)$", RegexOptions.IgnoreCase)) { // Добовляем IP в белый int HourCacheToBot = IsGlobalConf() ? antiBotToGlobalConf.conf.HourCacheToBot : domain.AntiBot.HourCacheToBot; WhitePtr.Add(IP, host.HostName, DateTime.Now.AddHours(HourCacheToBot)); Trigger.OnAddToWhitePtr((IP, HostConvert, DomainID, ptr, HourCacheToBot)); return(true); } } } catch { } // Записываем IP в кеш IPtables и журнал if (Check.Request.SetBlockedToIPtables(domain, IP, HostConvert, "AntiBot", DateTime.Now.AddMinutes(40), uri, userAgent, ptr)) { Trigger.OnBlockedIP((IP, ptr, HostConvert, DomainID, "AntiBot", 40)); } // Не удалось проверить PTR-запись memoryCache.Remove(memKey); return(false); } #endregion #region ежим проверки поискового бота if (IsGlobalConf() ? antiBotToGlobalConf.conf.FirstSkipToBot : domain.AntiBot.FirstSkipToBot) { // Проверяем DNSLookup в потоке ThreadPool.QueueUserWorkItem(i => DNSLookup()); } else { // Плохой бот if (!DNSLookup()) { outHtml = "Не удалось проверить PTR-запись"; return(false); } } #endregion // Бот может зайти на сайт return(true); } } #endregion // Нужна капча или нет bool IsRecaptcha = antiBotType == AntiBotType.reCAPTCHA; // Если капча установлена глобально, то нужно проверить домен в списке if (IsRecaptcha && IsGlobalConf() && antiBotToGlobalConf.conf.type == AntiBotType.reCAPTCHA) { IsRecaptcha = Regex.IsMatch(HostConvert, antiBotToGlobalConf.DomainsToreCaptchaRegex, RegexOptions.IgnoreCase); } // Выбираем настройки какого конфига использовать AntiBotBase antiBotConf = IsGlobalConf() ? (AntiBotBase)antiBotToGlobalConf.conf : (AntiBotBase)domain.AntiBot; #region Проверка пользователя в фоновом режиме if (antiBotConf.BackgroundCheck) { // Ключ для проверки запросов string memKey = $"Core:AntiBot/CountBackgroundRequest-{IP}"; if (method != "GET" && method != "HEAD") { // Если до этого был GET/HEAD запрос if (memoryCache.TryGetValue(memKey, out _)) { return(true); } } else { int CountBackgroundRequest; if (!memoryCache.TryGetValue(memKey, out CountBackgroundRequest)) { CountBackgroundRequest = 0; } // Пользователь не привысил значение if (antiBotConf.CountBackgroundRequest > CountBackgroundRequest) { // Увеличиваем количиство запросов if (!uri.Contains(".") || Regex.IsMatch(uri, antiBotConf.BackgroundCheckToAddExtensions, RegexOptions.IgnoreCase)) { // Записываем/Перезаписываем количиство запросов memoryCache.Set(memKey, ++CountBackgroundRequest, TimeSpan.FromHours(antiBotConf.BackgroundHourCacheToIP)); } // Без заглушки AntiBot return(true); } } } #endregion // reCAPTCHA, SignalR или JavaScript var tplName = (!IsRecaptcha && antiBotType == AntiBotType.reCAPTCHA) ? AntiBotType.SignalR : antiBotType; outHtml = Html(tplName, antiBotConf, jsonDB.Base.CoreAPI, IP, HostConvert, jsonDB.Security.reCAPTCHASitekey, jsonDB.Cache.AntiBot, domain.AntiBot.HashKey); Trigger.OnResponseView((IP, HostConvert, DomainID, tplName)); return(false); #region Локальный метод - "IsGlobalConf" bool IsGlobalConf() { return(antiBotToGlobalConf.conf.Enabled || domain.AntiBot.UseGlobalConf); } #endregion }