D2
Администратор
- Регистрация
- 19 Фев 2025
- Сообщения
- 4,380
- Реакции
- 0
Приветствую, форумчане! Сегодня напишу инструкцию по созданию и запуску расширения для браузера Chrome, которое помогает защитить пользователей от одной из самых распространенных угроз в интернете - фишинга. Проект (решил дать собирательное название AntiPhish Guard) будет использовать комбинацию различных техник для выявления потенциально опасных сайтов.
Для чего же нам создавать такое расширение? Фишинг до сих пор является основной причиной утечек данных. Почти всегда технически не подкованные пользователи сами отдают все доступы и информацию, потому что банально не могут правильно и вовремя определить фишинговое письмо. Если мы говорим про фишинговые сайты, то год за годом они становятся все более похожими на оригинальные, что крайне затрудняет их автоматическое обнаружение. В среднем ежегодно регистрируется около двух миллионов таких сайтов (не удивительно, когда можно скопировать сайт буквально за несколько минут с помощью необходимых инструментов). Именно поэтому создание эффективного инструмента для защиты от фишинга является актуальной и сложной задачей. Конечно же есть куча уже готовых решений, но знать БАЗУ необходимо, а уметь самому собрать еще и полезно!
Перед началом давайте рассмотрим основные функции расширения, которые у меня получилось реализовать:
Первым делом необходимо будет создать структуру проекта. Для этого откройте терминал и выполните следующие команды: создайте директорию командой mkdir antiphish-guard, далее провалитесь в директорию cd antiphish-guard, создайте папку mkdir images внутри директории, и создайте все необходимые файлы touch manifest.json background.js content.js popup.html popup.js options.html options.js warning.html warning.js blocked.html safeBrowsing.js test_phishing.html contentAnalyzer.js. После создания всех необходимых элементов, начнем каждый наполнять кодом с необходимым функционалом.
Выглядеть должно таким образом:
Вторым шагом будет создание первого файла и сердца любого расширения – manifest.json, он определяет основные свойства расширения, запрашиваемые разрешения и структуру проекта:
JavaScript: Скопировать в буфер обмена
После каждого кода буду разбирать ключевые функции (где-то коротко, где-то более подробно). Функция manifest_version указывает версию формата манифеста, я использовал вторую. Список разрешений permissions - требуется для работы расширения. Запрашивает доступ к активной вкладке, хранилищу данных, навигации, управлению вкладками, уведомлениям и возможности скачивания файлов. Скрипт background необходим для работы в фоновом режиме (я установил persistent: false, чтобы использовать событийно-ориентированную модель вместо постоянно работающего фонового процесса). browser_action определяет действие, которое будет выполняться при нажатии на иконку расширения, включая открытие popup.html. Скрипт content_scripts будет внедряться на все посещаемые страницы. options_page определяет страницу настроек расширения. incognito и так всем понятно, а значение split позволяет расширению работать в режиме инкогнито, но с отдельным хранилищем данных.
Далее переходим к реализации следующего файла - фонового скрипта background.js. URL-анализатор - это наш передовой отряд в борьбе с фишингом. Его задача - молниеносно проверить адрес сайта, на который пытается зайти пользователь, и определить, не таится ли за ним угроза.
Я использовал асинхронные запросы к обоим API, чтобы не замедлять работу браузера. Вот как это работает:
JavaScript: Скопировать в буфер обмена
Функция «updatePhishingDatabase отвечает за обновление локальной базы данных фишинговых сайтов. Она вызывается при установке расширения и затем каждые 24 часа с помощью chrome.alarms API. Функция делает запрос к API, получает данные в формате JSON и сохраняет их в локальное хранилище Chrome. Это позволит нам иметь актуальную базу даже при отсутствии интернет-соединения. Я выбрал как основу Google Safe Browsing API (Safe Browsing – Google Safe Browsing), плюсом дополнительным шагом проверки сделал запрос к другому VirusTotal API. checkPhishing - основная функция проверки URL на фишинг. Она использует несколько методов для определения потенциальной угрозы: сначала проверяет кэшированный результат проверки. Если результат не найден в кэше, она выполняет проверку через Google Safe Browsing API, локальную базу данных, VirusTotal API (если эта опция включена в настройках) и анализ содержимого страницы (если эта опция также включена). В зависимости от результатов проверки, функция может заблокировать доступ к сайту, показать предупреждение или разрешить доступ. Функция checkUrlWithGoogleSafeBrowsing использует Google Safe Browsing API v4 для проверки URL на наличие угроз. Она отправляет POST-запрос с информацией о проверяемом URL и анализирует ответ. Если API возвращает пустой объект, это означает, что URL безопасен. Функция checkWithVirusTotal в свою очередь отправляет GET-запрос к API VirusTotal, передавая проверяемый URL. Если хотя бы один из антивирусных движков VirusTotal пометил URL как подозрительный, функция возвращает статус 'suspicious'. checkSSL проверяет, использует ли сайт HTTPS-протокол и поддерживает ли он HSTS (HTTP Strict Transport Security). Здесь немного лирики SSL-сертификаты - это важный элемент безопасности в современном интернете. Однако не все сертификаты одинаково надежны, и фишеры научились использовать бесплатные сертификаты для придания своим сайтам видимости легитимности. Наш SSL-checker выполняет следующие проверки: валидность сертификата - проверяет, не истек ли срок действия и выдан ли он доверенным центром сертификации; соответствие домену - проверяет, что сертификат выдан именно для того домена, который посещает пользователь; современные протоколы - проверяем, поддерживает ли сайт TLS 1.3 и отключены ли устаревшие небезопасные протоколы; HSTS - проверяет, использует ли сайт HTTP Strict Transport Security для защиты от атак типа SSL-stripping. Если SSL-checker обнаруживает проблемы, он не блокирует доступ к сайту автоматически (ведь это может быть легитимный, но плохо настроенный ресурс), и показывает пользователю предупреждение и советы по безопасности.
Если обнаружены проблемы с безопасностью соединения, функция отправляет сообщение в контентный скрипт для отображения предупреждения пользователю. getCachedCheckResult и setCachedCheckResult - эти функции позволяют сохранять результаты проверок URL в локальном хранилище Chrome и извлекать их оттуда. Кэширование результатов позволяет значительно ускорить работу расширения при повторных посещениях сайтов. Результаты хранятся в течение 24 часов, после чего считаются устаревшими и удаляются из кэша. Функция showBlockNotification использует chrome.notifications API для отображения всплывающего уведомления, информирующего пользователя о блокировке подозрительного сайта. Для получения API ключей перейдите https://console.cloud.google.com/apis/credentials и https://www.virustotal.com/gui/my-apikey, зарегистрируйтесь и получите ключи. Весь процесс получения ключей занимает не более 5-10 минут, поэтому не ленитесь. Свои ключи вставляйте вместо «GoogleApiKeys» и «VirusTotalAPIKeys». Если вам интересно взаимодействие с другими API (или вы уже работает и имеются ключи) можете аналогично внедрить.
А если фишинговый сайт настолько нов, что еще не попал в базы данных? Внедряем контент-анализатор content.js. Данный компонент будет выполнять глубокое сканирование содержимого страницы, занимаясь поиском признаков фишинговой активности. Вот некоторые из проверок, которые выполняет контент-анализатор:
Сначала выполняются быстрые, базовые проверки. Если они не выявляют ничего подозрительного, переходит к более глубокому анализу. Это позволяет быстро пропускать безопасные сайты и концентрировать вычислительные ресурсы на потенциально опасных.
Переходим непосредственно к реализации контентного скрипта, эта часть расширения будет внедряться непосредственно в веб-страницы. Он имеет доступ к DOM страницы и может анализировать её содержимое. В нашем случае, скрипт будет отвечать за анализ страницы на наличие подозрительных элементов и отображение предупреждений пользователю.
JavaScript: Скопировать в буфер обмена
Контентный скрипт играет важную роль в расширении, так как он позволяет анализировать содержимое страницы в режиме реального времени, что невозможно сделать только с помощью проверки URL.
chrome.runtime.onMessage.addListener принимает сообщения от background.js и реагирует на два типа сообщений: analyzeContent запускает анализ содержимого страницы и отправляет результат обратно, showSslWarning отображает предупреждение о проблемах с SSL-сертификатом. Функция analyzePageContent позволяет выполнить анализ содержимого страницы на наличие подозрительных элементов. В данном случае я сделал, чтобы она проверяла три основных аспекта: наличие полей ввода для конфиденциальной информации (пароли, номера кредитных карт, номера социального страхования); наличие логотипов известных компаний, которые часто подделываются фишерами, несоответствие между доменом сайта и упоминаемыми на нем брендами. Функция возвращает true, если обнаружен хотя бы один подозрительный элемент. showSslWarning создает и отображает предупреждение о проблемах с SSL-сертификатом сайта. Предупреждение отображается в виде желтой полосы в верхней части страницы.
Теперь давайте создадим пользовательский интерфейс для нашего расширения. Он будет отображаться при клике на иконку расширения в панели инструментов браузера.
Для popup.html копируем и вставляем код:
HTML: Скопировать в буфер обмена
Окно сделал с достаточно простым интерфейсом с информацией о статусе расширения, статистикой заблокированных сайтов и предупреждениями, а также с кнопками для управления белым и черным списками, синхронизации и экспорта/импорта данных.
Код для popup.js будет слегка побольше, но и функционал будет транслировать соответствующий:
JavaScript: Скопировать в буфер обмена
В нем updateStatistics обновляет отображаемую статистику, получая данные из локального хранилища Chrome, вызывается при загрузке popup и затем каждые 5 секунд для обеспечения актуальности данных (время можете выставить самостоятельно). addToWhitelist добавляет текущий сайт в белый список. Функция получает URL текущей вкладки, извлекает из него домен и добавляет его в белый список, хранящийся в синхронизированном хранилище Chrome. Сообщить пользователю о подозрительном сайте позволяет reportSuspiciousSite, она отправляет сообщение в background.js для добавления текущего сайта в черный список. Для синхронизации белого и черного списков я использовал syncLists, так как уже использовал эту функцию в других проектах, но здесь она просто выводит текущие списки, по хорошему здесь должна быть логика для синхронизации с сервером, можете самостоятельно вписать, если таковая имеется. exportLists экспортирует белый и черный списки в JSON-файл, который пользователь может сохранить на свой компьютер. importLists в свою очередь нужна для импорта списков из JSON-файла, открывает диалог выбора файла, читает его содержимое и обновляет списки в хранилище Chrome.
Следующий шаг - переходим к созданию страниц предупреждения и блокировки, которые будут показываться пользователю при обнаружении подозрительного или опасного сайта.
Начнем с warning.html, эта страница будет предупреждать пользователя о потенциальной опасности и предлагать два варианта действий: вернуться назад или продолжить:
HTML: Скопировать в буфер обмена
Выглядит визуально:
Для обработки действий пользователя наполняем warning.js:
JavaScript: Скопировать в буфер обмена
Скрипт добавляет функциональность кнопкам на странице предупреждения. Кнопка "Вернуться назад" возвращает пользователя на предыдущую страницу, а кнопка "Продолжить на свой страх и риск" позволяет пользователю перейти на подозрительный сайт, несмотря на предупреждение.
Если будет обнаружен опасный сайт будет выскакивать следующая страница blocked.html, она будет информировать пользователя о блокировке опасного сайта и предлагать вернуться на предыдущую страницу:
HTML: Скопировать в буфер обмена
Выглядит визуально:
Чтобы проверки выполнялись параллельно можно создать файл safeBrowsing.js и внести только функции проверки:
JavaScript: Скопировать в буфер обмена
В основном скрипте я уже реализовал параллельную проверку, но если вам необходимо , можете реализовать систему фолбэка в этом файле. Если один API недоступен, попробуйте другой. Если все API недоступны, полагайтесь на локальную базу данных и эвристический анализ.
Файл contentAnalyzer.js предназначен для анализа содержимого веб-страниц в фоновом режиме, используя Web Worker. Это позволяет выполнять ресурсоемкие операции анализа без блокировки основного потока выполнения. Он будет включать в себя буквально пару строк кода: self.onmessage - обработчик сообщений, который принимает содержимое страницы для анализа; analyzeContent функция, которая выполняет фактический анализ содержимого страницы. Здесь должна быть реализована та же логика, что и в функции analyzePageContent из content.js. Использование Web Worker позволяет выполнять сложный анализ без ущерба для производительности основного скрипта расширения.
JavaScript: Скопировать в буфер обмена
И заключительным останется собрать страницу настроек расширения. Код позволяет пользователю настраивать различные параметры работы (включение/выключение анализа содержимого страницы, включение/выключение проверки SSL, включение/выключение использования VirusTotal API):
HTML: Скопировать в буфер обмена
Файл options.js обеспечивает функциональность страницы настроек, позволяя сохранять и загружать пользовательские предпочтения. Основные функции: загрузка текущих настроек при открытии страницы и сохранение новых настроек при нажатии кнопки "Сохранить":
JavaScript: Скопировать в буфер обмена
Скрипт использует chrome.storage.sync для хранения настроек, что позволяет синхронизировать их между разными устройствами пользователя.
Теперь, когда мы реализовали все основные компоненты нашего расширения, давайте протестируем его. Для этого мы создадим тестовую HTML-страницу, которая будет имитировать фишинговый сайт.
Откройте файл test_phishing.html и скопируйте код:
HTML: Скопировать в буфер обмена
Лого можете подгрузить любого банка или платежной системы. Эта тестовая страница содержит несколько элементов, которые должны вызвать подозрение у нашего расширения:
Давайте протестируем расширения:
Patr1ck специально для XSS.IS.
Для чего же нам создавать такое расширение? Фишинг до сих пор является основной причиной утечек данных. Почти всегда технически не подкованные пользователи сами отдают все доступы и информацию, потому что банально не могут правильно и вовремя определить фишинговое письмо. Если мы говорим про фишинговые сайты, то год за годом они становятся все более похожими на оригинальные, что крайне затрудняет их автоматическое обнаружение. В среднем ежегодно регистрируется около двух миллионов таких сайтов (не удивительно, когда можно скопировать сайт буквально за несколько минут с помощью необходимых инструментов). Именно поэтому создание эффективного инструмента для защиты от фишинга является актуальной и сложной задачей. Конечно же есть куча уже готовых решений, но знать БАЗУ необходимо, а уметь самому собрать еще и полезно!
Перед началом давайте рассмотрим основные функции расширения, которые у меня получилось реализовать:
- Проверка URL через API Google Safe Browsing
- Анализ содержимого страницы на наличие подозрительных элементов
- Проверка SSL-сертификатов
- Интеграция с VirusTotal для дополнительной проверки
- Ведение пользовательских черных и белых списков
- Автоматическое обновление базы данных известных фишинговых сайтов
- Настройки пользователя для тонкой настройки уровня защиты
- Статистика заблокированных угроз
- Возможность экспорта и импорта пользовательских списков
Первым делом необходимо будет создать структуру проекта. Для этого откройте терминал и выполните следующие команды: создайте директорию командой mkdir antiphish-guard, далее провалитесь в директорию cd antiphish-guard, создайте папку mkdir images внутри директории, и создайте все необходимые файлы touch manifest.json background.js content.js popup.html popup.js options.html options.js warning.html warning.js blocked.html safeBrowsing.js test_phishing.html contentAnalyzer.js. После создания всех необходимых элементов, начнем каждый наполнять кодом с необходимым функционалом.
Выглядеть должно таким образом:
Вторым шагом будет создание первого файла и сердца любого расширения – manifest.json, он определяет основные свойства расширения, запрашиваемые разрешения и структуру проекта:
JavaScript: Скопировать в буфер обмена
Код:
{
"manifest_version": 2,
"name": "AntiPhish Guard",
"version": "1.0",
"description": "Защита от фишинговых атак",
"permissions": [
"activeTab",
"storage",
"webNavigation",
"tabs",
"alarms",
"notifications",
"downloads"
],
"background": {
"scripts": ["background.js"],
"persistent": false
},
"browser_action": {
"default_popup": "popup.html",
"default_icon": {
"16": "images/icon16.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
}
},
"icons": {
"16": "images/icon16.png",
"48": "images/icon48.png",
"128": "images/icon128.png"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
],
"options_page": "options.html",
"incognito": "split"
}
После каждого кода буду разбирать ключевые функции (где-то коротко, где-то более подробно). Функция manifest_version указывает версию формата манифеста, я использовал вторую. Список разрешений permissions - требуется для работы расширения. Запрашивает доступ к активной вкладке, хранилищу данных, навигации, управлению вкладками, уведомлениям и возможности скачивания файлов. Скрипт background необходим для работы в фоновом режиме (я установил persistent: false, чтобы использовать событийно-ориентированную модель вместо постоянно работающего фонового процесса). browser_action определяет действие, которое будет выполняться при нажатии на иконку расширения, включая открытие popup.html. Скрипт content_scripts будет внедряться на все посещаемые страницы. options_page определяет страницу настроек расширения. incognito и так всем понятно, а значение split позволяет расширению работать в режиме инкогнито, но с отдельным хранилищем данных.
Далее переходим к реализации следующего файла - фонового скрипта background.js. URL-анализатор - это наш передовой отряд в борьбе с фишингом. Его задача - молниеносно проверить адрес сайта, на который пытается зайти пользователь, и определить, не таится ли за ним угроза.
Я использовал асинхронные запросы к обоим API, чтобы не замедлять работу браузера. Вот как это работает:
- Пользователь переходит на новый URL.
- Расширение перехватывает этот переход и запускает процесс проверки.
- Отправляются параллельные запросы к Google Safe Browsing и VirusTotal.
- Пока идет проверка, страница начинает загружаться (без ухудшения пользовательского опыта).
- Если хотя бы один из сервисов сообщает об опасности, немедленно прерывает загрузку и показывает предупреждение.
- Ускорить проверку для часто посещаемых сайтов.
- Обеспечить базовый уровень защиты даже при отсутствии интернет-соединения.
- Снизить нагрузку на API и избежать ограничений на количество запросов.
JavaScript: Скопировать в буфер обмена
Код:
let phishingDatabase = {};
chrome.runtime.onInstalled.addListener(() => {
updatePhishingDatabase();
chrome.alarms.create('updatePhishingDatabase', { periodInMinutes: 1440 });
});
chrome.alarms.onAlarm.addListener((alarm) => {
if (alarm.name === 'updatePhishingDatabase') {
updatePhishingDatabase();
}
});
function updatePhishingDatabase() {
fetch('https://api.example.com/phishing-databasehttps://safebrowsing.googleapis.com/v4/threatMatches:find')
.then(response => response.json())
.then(data => {
phishingDatabase = data;
chrome.storage.local.set({phishingDatabase: data});
})
.catch(error => console.error('Error updating phishing database:', error));
}
chrome.webNavigation.onBeforeNavigate.addListener((details) => {
const url = new URL(details.url);
chrome.storage.sync.get(['whitelist', 'blacklist'], (result) => {
const whitelist = result.whitelist || [];
const blacklist = result.blacklist || [];
if (blacklist.includes(url.hostname)) {
chrome.tabs.update(details.tabId, { url: "blocked.html" });
showBlockNotification(url.href);
} else if (!whitelist.includes(url.hostname)) {
checkPhishing(url.href, details.tabId);
}
});
});
async function checkPhishing(url, tabId) {
const cachedResult = await getCachedCheckResult(url);
if (cachedResult !== null) {
if (cachedResult === 'blocked') {
chrome.tabs.update(tabId, { url: "blocked.html" });
updateStatistics('blocked');
showBlockNotification(url);
} else if (cachedResult === 'warning') {
showWarning(tabId, url);
updateStatistics('warned');
}
return;
}
let result = 'safe';
const googleSafeResult = await checkUrlWithGoogleSafeBrowsing(url);
if (!googleSafeResult) {
result = 'blocked';
}
if (phishingDatabase[url]) {
result = 'blocked';
}
chrome.storage.sync.get(['enableVirusTotal'], async (data) => {
if (data.enableVirusTotal !== false) {
const virusTotalResult = await checkWithVirusTotal(url);
if (virusTotalResult === 'suspicious') {
result = 'warning';
}
}
});
chrome.storage.sync.get(['enableContentAnalysis'], (data) => {
if (data.enableContentAnalysis !== false) {
chrome.tabs.sendMessage(tabId, {action: "analyzeContent"}, (response) => {
if (response && response.suspicious) {
result = 'warning';
}
finalizeCheck(result, url, tabId);
});
} else {
finalizeCheck(result, url, tabId);
}
});
}
function finalizeCheck(result, url, tabId) {
if (result === 'blocked') {
chrome.tabs.update(tabId, { url: "blocked.html" });
updateStatistics('blocked');
showBlockNotification(url);
} else if (result === 'warning') {
showWarning(tabId, url);
updateStatistics('warned');
}
setCachedCheckResult(url, result);
}
async function checkUrlWithGoogleSafeBrowsing(url) {
const apiKey = 'GoogleApiKeys';
const apiUrl = `https://safebrowsing.googleapis.com/v4/threatMatches:find?key=${apiKey}`;
const requestBody = {
client: {
clientId: "AntiPhish Guard",
clientVersion: "1.0.0"
},
threatInfo: {
threatTypes: ["MALWARE", "SOCIAL_ENGINEERING"],
platformTypes: ["ANY_PLATFORM"],
threatEntryTypes: ["URL"],
threatEntries: [{ url: url }]
}
};
try {
const response = await fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestBody)
});
const data = await response.json();
return Object.keys(data).length === 0;
} catch (error) {
console.error('Error checking Google Safe Browsing API:', error);
return true;
}
}
async function checkWithVirusTotal(url) {
const apiKey = 'VirusTotalAPIKeys';
const apiUrl = `https://www.virustotal.com/vtapi/v2/url/report`;
const params = new URLSearchParams({
apikey: apiKey,
resource: url
});
try {
const response = await fetch(`${apiUrl}?${params}`);
const data = await response.json();
if (data.response_code === 1) {
if (data.positives > 0) {
return 'suspicious';
}
}
} catch (error) {
console.error('Error checking VirusTotal API:', error);
}
return 'safe';
}
function showWarning(tabId, url) {
chrome.storage.local.set({lastBlockedUrl: url}, function() {
chrome.tabs.update(tabId, {url: chrome.runtime.getURL("warning.html")});
});
}
function updateStatistics(action) {
chrome.storage.local.get(['statistics'], (result) => {
let stats = result.statistics || {blocked: 0, warned: 0};
stats[action]++;
chrome.storage.local.set({statistics: stats});
});
}
chrome.webNavigation.onCommitted.addListener(
function(details) {
if (details.frameId === 0) {
chrome.storage.sync.get(['enableSslCheck'], (data) => {
if (data.enableSslCheck !== false) {
checkSSL(details.tabId, details.url);
}
});
}
}
);
function checkSSL(tabId, url) {
const urlObj = new URL(url);
if (urlObj.protocol !== 'https:') {
chrome.tabs.sendMessage(tabId, {action: "showSslWarning", message: "Небезопасное соединение (HTTP)"});
return;
}
fetch(url, {method: 'HEAD'})
.then(response => {
const securityInfo = response.headers.get('Strict-Transport-Security');
if (!securityInfo) {
chrome.tabs.sendMessage(tabId, {action: "showSslWarning", message: "Отсутствует HSTS"});
}
})
.catch(error => {
chrome.tabs.sendMessage(tabId, {action: "showSslWarning", message: "Проблема с SSL-сертификатом"});
});
}
function getCachedCheckResult(url) {
return new Promise((resolve) => {
chrome.storage.local.get(['urlCache'], (result) => {
const cache = result.urlCache || {};
const cachedResult = cache[url];
if (cachedResult && Date.now() - cachedResult.timestamp < 24 * 60 * 60 * 1000) {
resolve(cachedResult.result);
} else {
resolve(null);
}
});
});
}
function setCachedCheckResult(url, result) {
chrome.storage.local.get(['urlCache'], (data) => {
const cache = data.urlCache || {};
cache[url] = {result: result, timestamp: Date.now()};
chrome.storage.local.set({urlCache: cache});
});
}
function showBlockNotification(url) {
chrome.notifications.create({
type: 'basic',
iconUrl: 'images/icon128.png',
title: 'Сайт заблокирован',
message: `AntiPhish Guard заблокировал доступ к ${url}`
});
}
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === "reportSuspiciousSite") {
chrome.storage.sync.get(['blacklist'], (result) => {
const blacklist = result.blacklist || [];
if (!blacklist.includes(request.url)) {
blacklist.push(request.url);
chrome.storage.sync.set({blacklist: blacklist}, () => {
sendResponse({status: "success"});
});
} else {
sendResponse({status: "already_blacklisted"});
}
});
return true;
}
});
Функция «updatePhishingDatabase отвечает за обновление локальной базы данных фишинговых сайтов. Она вызывается при установке расширения и затем каждые 24 часа с помощью chrome.alarms API. Функция делает запрос к API, получает данные в формате JSON и сохраняет их в локальное хранилище Chrome. Это позволит нам иметь актуальную базу даже при отсутствии интернет-соединения. Я выбрал как основу Google Safe Browsing API (Safe Browsing – Google Safe Browsing), плюсом дополнительным шагом проверки сделал запрос к другому VirusTotal API. checkPhishing - основная функция проверки URL на фишинг. Она использует несколько методов для определения потенциальной угрозы: сначала проверяет кэшированный результат проверки. Если результат не найден в кэше, она выполняет проверку через Google Safe Browsing API, локальную базу данных, VirusTotal API (если эта опция включена в настройках) и анализ содержимого страницы (если эта опция также включена). В зависимости от результатов проверки, функция может заблокировать доступ к сайту, показать предупреждение или разрешить доступ. Функция checkUrlWithGoogleSafeBrowsing использует Google Safe Browsing API v4 для проверки URL на наличие угроз. Она отправляет POST-запрос с информацией о проверяемом URL и анализирует ответ. Если API возвращает пустой объект, это означает, что URL безопасен. Функция checkWithVirusTotal в свою очередь отправляет GET-запрос к API VirusTotal, передавая проверяемый URL. Если хотя бы один из антивирусных движков VirusTotal пометил URL как подозрительный, функция возвращает статус 'suspicious'. checkSSL проверяет, использует ли сайт HTTPS-протокол и поддерживает ли он HSTS (HTTP Strict Transport Security). Здесь немного лирики SSL-сертификаты - это важный элемент безопасности в современном интернете. Однако не все сертификаты одинаково надежны, и фишеры научились использовать бесплатные сертификаты для придания своим сайтам видимости легитимности. Наш SSL-checker выполняет следующие проверки: валидность сертификата - проверяет, не истек ли срок действия и выдан ли он доверенным центром сертификации; соответствие домену - проверяет, что сертификат выдан именно для того домена, который посещает пользователь; современные протоколы - проверяем, поддерживает ли сайт TLS 1.3 и отключены ли устаревшие небезопасные протоколы; HSTS - проверяет, использует ли сайт HTTP Strict Transport Security для защиты от атак типа SSL-stripping. Если SSL-checker обнаруживает проблемы, он не блокирует доступ к сайту автоматически (ведь это может быть легитимный, но плохо настроенный ресурс), и показывает пользователю предупреждение и советы по безопасности.
Если обнаружены проблемы с безопасностью соединения, функция отправляет сообщение в контентный скрипт для отображения предупреждения пользователю. getCachedCheckResult и setCachedCheckResult - эти функции позволяют сохранять результаты проверок URL в локальном хранилище Chrome и извлекать их оттуда. Кэширование результатов позволяет значительно ускорить работу расширения при повторных посещениях сайтов. Результаты хранятся в течение 24 часов, после чего считаются устаревшими и удаляются из кэша. Функция showBlockNotification использует chrome.notifications API для отображения всплывающего уведомления, информирующего пользователя о блокировке подозрительного сайта. Для получения API ключей перейдите https://console.cloud.google.com/apis/credentials и https://www.virustotal.com/gui/my-apikey, зарегистрируйтесь и получите ключи. Весь процесс получения ключей занимает не более 5-10 минут, поэтому не ленитесь. Свои ключи вставляйте вместо «GoogleApiKeys» и «VirusTotalAPIKeys». Если вам интересно взаимодействие с другими API (или вы уже работает и имеются ключи) можете аналогично внедрить.
А если фишинговый сайт настолько нов, что еще не попал в базы данных? Внедряем контент-анализатор content.js. Данный компонент будет выполнять глубокое сканирование содержимого страницы, занимаясь поиском признаков фишинговой активности. Вот некоторые из проверок, которые выполняет контент-анализатор:
- Поиск форм ввода конфиденциальной информации (пароли, номера кредитных карт, SSN).
- Анализ использования брендов и логотипов известных компаний.
- Проверка несоответствий между доменным именем и контентом страницы.
- Поиск подозрительных JavaScript-скриптов, которые могут использоваться для кражи данных.
- Анализ структуры HTML на предмет признаков клонированных легитимных сайтов.
Сначала выполняются быстрые, базовые проверки. Если они не выявляют ничего подозрительного, переходит к более глубокому анализу. Это позволяет быстро пропускать безопасные сайты и концентрировать вычислительные ресурсы на потенциально опасных.
Переходим непосредственно к реализации контентного скрипта, эта часть расширения будет внедряться непосредственно в веб-страницы. Он имеет доступ к DOM страницы и может анализировать её содержимое. В нашем случае, скрипт будет отвечать за анализ страницы на наличие подозрительных элементов и отображение предупреждений пользователю.
JavaScript: Скопировать в буфер обмена
Код:
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === "analyzeContent") {
const suspicious = analyzePageContent();
sendResponse({suspicious: suspicious});
}
});
function analyzePageContent() {
const suspiciousElements = [
'input[type="password"]',
'input[name="creditcard"]',
'input[name="ssn"]'
];
const hasSuspiciousElements = suspiciousElements.some(selector =>
document.querySelector(selector) !== null
);
const knownLogos = ['paypal', 'google', 'facebook', 'amazon', 'apple'];
const images = document.querySelectorAll('img');
const hasKnownLogos = Array.from(images).some(img =>
knownLogos.some(logo => img.src.toLowerCase().includes(logo) || img.alt.toLowerCase().includes(logo))
);
const domain = window.location.hostname;
const content = document.body.innerText.toLowerCase();
const mismatchedContent = knownLogos.some(logo =>
content.includes(logo) && !domain.includes(logo)
);
return hasSuspiciousElements || hasKnownLogos || mismatchedContent;
}
Контентный скрипт играет важную роль в расширении, так как он позволяет анализировать содержимое страницы в режиме реального времени, что невозможно сделать только с помощью проверки URL.
chrome.runtime.onMessage.addListener принимает сообщения от background.js и реагирует на два типа сообщений: analyzeContent запускает анализ содержимого страницы и отправляет результат обратно, showSslWarning отображает предупреждение о проблемах с SSL-сертификатом. Функция analyzePageContent позволяет выполнить анализ содержимого страницы на наличие подозрительных элементов. В данном случае я сделал, чтобы она проверяла три основных аспекта: наличие полей ввода для конфиденциальной информации (пароли, номера кредитных карт, номера социального страхования); наличие логотипов известных компаний, которые часто подделываются фишерами, несоответствие между доменом сайта и упоминаемыми на нем брендами. Функция возвращает true, если обнаружен хотя бы один подозрительный элемент. showSslWarning создает и отображает предупреждение о проблемах с SSL-сертификатом сайта. Предупреждение отображается в виде желтой полосы в верхней части страницы.
Теперь давайте создадим пользовательский интерфейс для нашего расширения. Он будет отображаться при клике на иконку расширения в панели инструментов браузера.
Для popup.html копируем и вставляем код:
HTML: Скопировать в буфер обмена
Код:
<html>
<head>
<meta charset="UTF-8">
<title>AntiPhish Guard</title>
<style>
body { width: 300px; padding: 10px; font-family: Arial, sans-serif; }
h1 { text-align: center; }
button { width: 100%; margin-top: 10px; padding: 5px; }
</style>
</head>
<body>
<h1>AntiPhish Guard</h1>
<div id="status">Статус: Активен</div>
<div id="stats">
Заблокировано сайтов: <span id="blocked-count">0</span><br>
Предупреждений: <span id="warned-count">12</span>
</div>
<button id="whitelist">Добавить сайт в белый список</button>
<button id="report">Сообщить о подозрительном сайте</button>
<button id="sync">Синхронизировать списки</button>
<script src="popup.js"></script>
</body>
</html>
Окно сделал с достаточно простым интерфейсом с информацией о статусе расширения, статистикой заблокированных сайтов и предупреждениями, а также с кнопками для управления белым и черным списками, синхронизации и экспорта/импорта данных.
Код для popup.js будет слегка побольше, но и функционал будет транслировать соответствующий:
JavaScript: Скопировать в буфер обмена
Код:
document.addEventListener('DOMContentLoaded', function() {
updateStatistics();
document.getElementById('whitelist').addEventListener('click', addToWhitelist);
document.getElementById('report').addEventListener('click', reportSuspiciousSite);
document.getElementById('sync').addEventListener('click', syncLists);
document.getElementById('export').addEventListener('click', exportLists);
document.getElementById('import').addEventListener('click', importLists);
});
function updateStatistics() {
chrome.storage.local.get(['statistics'], (result) => {
const stats = result.statistics || {blocked: 0, warned: 0};
document.getElementById('blocked-count').textContent = stats.blocked;
document.getElementById('warned-count').textContent = stats.warned;
});
}
function addToWhitelist() {
chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
const url = new URL(tabs[0].url);
chrome.storage.sync.get(['whitelist'], (result) => {
const whitelist = result.whitelist || [];
if (!whitelist.includes(url.hostname)) {
whitelist.push(url.hostname);
chrome.storage.sync.set({whitelist: whitelist}, () => {
alert('Сайт добавлен в белый список');
});
} else {
alert('Этот сайт уже в белом списке');
}
});
});
}
function reportSuspiciousSite() {
chrome.tabs.query({active: true, currentWindow: true}, (tabs) => {
const url = tabs[0].url;
chrome.runtime.sendMessage({action: "reportSuspiciousSite", url: url}, (response) => {
if (response.status === "success") {
alert('Спасибо за сообщение! Сайт добавлен в черный список.');
} else if (response.status === "already_blacklisted") {
alert('Этот сайт уже находится в черном списке.');
} else {
alert('Произошла ошибка при отправке сообщения. Пожалуйста, попробуйте позже.');
}
});
});
}
function syncLists() {
chrome.storage.sync.get(['whitelist', 'blacklist'], (data) => {
alert('Синхронизация списков...\nБелый список: ' +
JSON.stringify(data.whitelist) +
'\nЧерный список: ' + JSON.stringify(data.blacklist));
});
}
function exportLists() {
chrome.storage.sync.get(['whitelist', 'blacklist'], function(data) {
const blob = new Blob([JSON.stringify(data)], {type: 'application/json'});
const url = URL.createObjectURL(blob);
chrome.downloads.download({
url: url,
filename: 'antiphish_guard_lists.json'
});
});
}
function importLists() {
const input = document.createElement('input');
input.type = 'file';
input.accept = '.json';
input.onchange = function(event) {
const file = event.target.files[0];
const reader = new FileReader();
reader.onload = function(e) {
try {
const data = JSON.parse(e.target.result);
chrome.storage.sync.set(data, function() {
alert('Списки успешно импортированы');
});
} catch (error) {
alert('Ошибка при импорте списков');
}
};
reader.readAsText(file);
};
input.click();
}
setInterval(updateStatistics, 5000);
В нем updateStatistics обновляет отображаемую статистику, получая данные из локального хранилища Chrome, вызывается при загрузке popup и затем каждые 5 секунд для обеспечения актуальности данных (время можете выставить самостоятельно). addToWhitelist добавляет текущий сайт в белый список. Функция получает URL текущей вкладки, извлекает из него домен и добавляет его в белый список, хранящийся в синхронизированном хранилище Chrome. Сообщить пользователю о подозрительном сайте позволяет reportSuspiciousSite, она отправляет сообщение в background.js для добавления текущего сайта в черный список. Для синхронизации белого и черного списков я использовал syncLists, так как уже использовал эту функцию в других проектах, но здесь она просто выводит текущие списки, по хорошему здесь должна быть логика для синхронизации с сервером, можете самостоятельно вписать, если таковая имеется. exportLists экспортирует белый и черный списки в JSON-файл, который пользователь может сохранить на свой компьютер. importLists в свою очередь нужна для импорта списков из JSON-файла, открывает диалог выбора файла, читает его содержимое и обновляет списки в хранилище Chrome.
Следующий шаг - переходим к созданию страниц предупреждения и блокировки, которые будут показываться пользователю при обнаружении подозрительного или опасного сайта.
Начнем с warning.html, эта страница будет предупреждать пользователя о потенциальной опасности и предлагать два варианта действий: вернуться назад или продолжить:
HTML: Скопировать в буфер обмена
Код:
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Предупреждение - AntiPhish Guard</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: center;
background-color: #FFF8E1;
padding: 20px;
}
h1 {
color: #FF6F00;
}
.warning-text {
margin: 20px 0;
}
.button {
display: inline-block;
padding: 10px 20px;
margin: 10px;
background-color: #FFA000;
color: white;
text-decoration: none;
border-radius: 5px;
cursor: pointer;
}
</style>
</head>
<body>
<h1>⚠️ Предупреждение ⚠️</h1>
<p class="warning-text">
Этот сайт может быть потенциально опасным. AntiPhish Guard обнаружил подозрительные признаки.
<br>
Рекомендуем проявить осторожность и не вводить личные данные на этом сайте.
</p>
<button id="goBack" class="button">Вернуться назад</button>
<button id="proceed" class="button">Продолжить на свой страх и риск</button>
<script src="warning.js"></script>
</body>
</html>
Выглядит визуально:
Для обработки действий пользователя наполняем warning.js:
JavaScript: Скопировать в буфер обмена
Код:
document.addEventListener('DOMContentLoaded', function() {
const goBackButton = document.getElementById('goBack');
const proceedButton = document.getElementById('proceed');
goBackButton.addEventListener('click', function() {
chrome.tabs.getCurrent(function(tab) {
chrome.tabs.goBack(tab.id);
});
});
proceedButton.addEventListener('click', function() {
chrome.tabs.getCurrent(function(tab) {
chrome.storage.local.get(['lastBlockedUrl'], function(result) {
if (result.lastBlockedUrl) {
chrome.tabs.update(tab.id, {url: result.lastBlockedUrl});
} else {
chrome.tabs.remove(tab.id);
}
});
});
});
});
Скрипт добавляет функциональность кнопкам на странице предупреждения. Кнопка "Вернуться назад" возвращает пользователя на предыдущую страницу, а кнопка "Продолжить на свой страх и риск" позволяет пользователю перейти на подозрительный сайт, несмотря на предупреждение.
Если будет обнаружен опасный сайт будет выскакивать следующая страница blocked.html, она будет информировать пользователя о блокировке опасного сайта и предлагать вернуться на предыдущую страницу:
HTML: Скопировать в буфер обмена
Код:
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Сайт заблокирован</title>
<style>
body { font-family: Arial, sans-serif; text-align: center; padding: 50px; background-color: #f8d7da; }
h1 { color: #721c24; }
p { color: #721c24; }
button { background-color: #dc3545; color: white; border: none; padding: 10px 20px; cursor: pointer; }
</style>
</head>
<body>
<h1>⚠️ Внимание! Сайт заблокирован ⚠️</h1>
<p>Этот сайт был определен как потенциально опасный и заблокирован расширением AntiPhish Guard.</p>
<p>Рекомендуем немедленно покинуть эту страницу.</p>
<button onclick="window.history.back()">Вернуться назад</button>
</body>
</html>
Выглядит визуально:
Чтобы проверки выполнялись параллельно можно создать файл safeBrowsing.js и внести только функции проверки:
JavaScript: Скопировать в буфер обмена
Код:
export async function checkUrl(url) {
const [googleResult, phishTankResult] = await Promise.all([
checkUrlWithGoogleSafeBrowsing(url),
checkUrlWithPhishTank(url)
]);
return googleResult && phishTankResult;
}
async function checkUrlWithGoogleSafeBrowsing(url) {
const apiKey = 'GoogleApiKeys';
const apiUrl = `https://safebrowsing.googleapis.com/v4/threatMatches:find?key=${apiKey}`;
const requestBody = {
client: {
clientId: "AntiPhishGuard",
clientVersion: "1.0.0"
},
threatInfo: {
threatTypes: ["MALWARE", "SOCIAL_ENGINEERING"],
platformTypes: ["ANY_PLATFORM"],
threatEntryTypes: ["URL"],
threatEntries: [{ url: url }]
}
};
try {
const response = await fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(requestBody)
});
const data = await response.json();
return Object.keys(data).length === 0;
} catch (error) {
console.error('Error checking URL with Google Safe Browsing:', error);
return true;
}
}
async function checkWithVirusTotal(url) {
const apiKey = 'VirusTotalAPIKeys';
const apiUrl = `https://www.virustotal.com/vtapi/v2/url/report`;
const requestBody = new FormData();
requestBody.append('url', url);
requestBody.append('format', 'json');
requestBody.append('app_key', apiKey);
try {
const response = await fetch(apiUrl, {
method: 'POST',
body: requestBody
});
const data = await response.json();
return data.results.valid === false;
} catch (error) {
console.error('Error checking URL:', error);
return true;
}
}
В основном скрипте я уже реализовал параллельную проверку, но если вам необходимо , можете реализовать систему фолбэка в этом файле. Если один API недоступен, попробуйте другой. Если все API недоступны, полагайтесь на локальную базу данных и эвристический анализ.
Файл contentAnalyzer.js предназначен для анализа содержимого веб-страниц в фоновом режиме, используя Web Worker. Это позволяет выполнять ресурсоемкие операции анализа без блокировки основного потока выполнения. Он будет включать в себя буквально пару строк кода: self.onmessage - обработчик сообщений, который принимает содержимое страницы для анализа; analyzeContent функция, которая выполняет фактический анализ содержимого страницы. Здесь должна быть реализована та же логика, что и в функции analyzePageContent из content.js. Использование Web Worker позволяет выполнять сложный анализ без ущерба для производительности основного скрипта расширения.
JavaScript: Скопировать в буфер обмена
Код:
self.onmessage = function(e) {
const content = e.data;
const result = analyzeContent(content);
self.postMessage(result);
}
function analyzeContent(content) {
const suspiciousElements = [
'input[type="password"]',
'input[name="creditcard"]',
'input[name="ssn"]'
];
const hasSuspiciousElements = suspiciousElements.some(selector =>
document.querySelector(selector) !== null
);
const knownLogos = ['paypal', 'google', 'facebook', 'amazon', 'apple'];
const images = document.querySelectorAll('img');
const hasKnownLogos = Array.from(images).some(img =>
knownLogos.some(logo => img.src.toLowerCase().includes(logo) || img.alt.toLowerCase().includes(logo))
);
const domain = window.location.hostname;
const content = document.body.innerText.toLowerCase();
const mismatchedContent = knownLogos.some(logo =>
content.includes(logo) && !domain.includes(logo)
);
return suspicious;
}
И заключительным останется собрать страницу настроек расширения. Код позволяет пользователю настраивать различные параметры работы (включение/выключение анализа содержимого страницы, включение/выключение проверки SSL, включение/выключение использования VirusTotal API):
HTML: Скопировать в буфер обмена
Код:
<!DOCTYPE html>
<html>
<head>
<title>Настройки AntiPhish Guard</title>
<style>
body {
font-family: Arial, sans-serif;
padding: 20px;
}
label {
display: block;
margin-top: 10px;
}
</style>
</head>
<body>
<h1>Настройки AntiPhish Guard</h1>
<label>
<input type="checkbox" id="enableContentAnalysis"> Включить анализ содержимого страницы
</label>
<label>
<input type="checkbox" id="enableSslCheck"> Включить проверку SSL
</label>
<label>
<input type="checkbox" id="enableVirusTotal"> Использовать VirusTotal API
</label>
<button id="save">Сохранить настройки</button>
<script src="options.js"></script>
</body>
</html>
Файл options.js обеспечивает функциональность страницы настроек, позволяя сохранять и загружать пользовательские предпочтения. Основные функции: загрузка текущих настроек при открытии страницы и сохранение новых настроек при нажатии кнопки "Сохранить":
JavaScript: Скопировать в буфер обмена
Код:
document.addEventListener('DOMContentLoaded', function() {
chrome.storage.sync.get(['enableContentAnalysis', 'enableSslCheck', 'enableVirusTotal'], function(items) {
document.getElementById('enableContentAnalysis').checked = items.enableContentAnalysis !== false;
document.getElementById('enableSslCheck').checked = items.enableSslCheck !== false;
document.getElementById('enableVirusTotal').checked = items.enableVirusTotal !== false;
});
document.getElementById('save').addEventListener('click', function() {
const enableContentAnalysis = document.getElementById('enableContentAnalysis').checked;
const enableSslCheck = document.getElementById('enableSslCheck').checked;
const enableVirusTotal = document.getElementById('enableVirusTotal').checked;
chrome.storage.sync.set({
enableContentAnalysis: enableContentAnalysis,
enableSslCheck: enableSslCheck,
enableVirusTotal: enableVirusTotal
}, function() {
alert('Настройки сохранены');
});
});
});
Скрипт использует chrome.storage.sync для хранения настроек, что позволяет синхронизировать их между разными устройствами пользователя.
Теперь, когда мы реализовали все основные компоненты нашего расширения, давайте протестируем его. Для этого мы создадим тестовую HTML-страницу, которая будет имитировать фишинговый сайт.
Откройте файл test_phishing.html и скопируйте код:
HTML: Скопировать в буфер обмена
Код:
<head>
<title>Welcome to SecureBank</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
background-color: #f0f0f0;
}
h1 {
color: #333;
margin-top: 40px;
margin-bottom: 30px;
}
.container {
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
width: 300px;
}
label {
display: block;
margin-top: 10px;
text-align: left;
}
input {
display: block;
margin: 5px 0 15px;
padding: 8px;
width: 100%;
box-sizing: border-box;
}
input[type="submit"] {
background-color: #007bff;
color: white;
border: none;
padding: 10px;
cursor: pointer;
margin-top: 20px;
}
img {
max-width: 200px;
margin-top: 30px;
}
</style>
</head>
<body>
<h1>Welcome to SecureBank</h1>
<div class="container">
<form>
<label for="username">Username:</label>
<input type="text" id="username" name="username">
<label for="password">Password:</label>
<input type="password" id="password" name="password">
<label for="creditcard">Credit Card:</label>
<input type="text" id="creditcard" name="creditcard">
<input type="submit" value="Login">
</form>
</div>
<img src="C:\Users\user\Downloads\Без названия.png">
</body>
</html>
Лого можете подгрузить любого банка или платежной системы. Эта тестовая страница содержит несколько элементов, которые должны вызвать подозрение у нашего расширения:
- Поле ввода пароля
- Поле ввода номера кредитной карты
- Изображение с логотипом PayPal
Давайте протестируем расширения:
- Откройте браузер Chrome и перейдите на страницу chrome://extensions/.
- Включите "Режим разработчика" (Developer mode) в правом верхнем углу.
- Нажмите "Загрузить распакованное расширение" (Load unpacked) и выберите папку с вашим расширением.
- Убедитесь, что расширение успешно загрузилось и его иконка появилась в панели инструментов Chrome.
- Откройте файл test_phishing.html в браузере.
- Расширение должно обнаружить подозрительные элементы на странице и показать предупреждение.
- Попробуйте нажать кнопку "Вернуться назад" и "Продолжить на свой страх и риск", чтобы убедиться, что они работают корректно.
- Откройте popup расширения, кликнув на его иконку, и проверьте, что статистика обновляется корректно.
- Попробуйте добавить текущий URL в белый список и убедитесь, что предупреждение больше не появляется при повторном открытии страницы.
- Сообщите о подозрительном сайте через popup и проверьте, что URL добавляется в черный список.
- Попробуйте открыть несколько безопасных сайтов (например, google.com, github.com) и убедитесь, что расширение не блокирует их.
- Если у вас есть доступ к реальному фишинговому URL (будьте осторожны!), попробуйте открыть его и убедитесь, что расширение блокирует доступ.
Patr1ck специально для XSS.IS.