В этой статье и последующих за ней публикациях цикла мы будем говорить о внутреннем устройстве антивируса для сайтов Вирусдай, о выбранных подходах и используемых технологиях.



Мы уже писали о возможностях сервиса в предыдущих постах. Сегодня мы расскажем о его общей архитектуре. Вы узнаете как Вирусдай работает с сайтами (серверами) пользователей, почему мы выбрали именно такой принцип построения сервиса и какие преимущества он дает, а также о том, насколько это безопасно.

Общая архитектура сервиса


Нашей задачей было создание удобного и эффективного сервиса для лечения и защиты сайтов от вирусов и атак. Решено было реализовать проект в форме SaaS, или говоря проще, в виде веб-сервиса.

Ведь действительно, сегодня все самые удобные инструменты предоставляются людям в виде приложений и веб-сервисов. С ними удобно работать, они экономят время.

Итак, архитектурно Вирусдай — это централизованная система, взаимодействующая с подключенными к ней серверами (сайтами) пользователей.



Другими словами, пользователи могут работать со своими сайтами (управлять функциями сервиса Вирусдай: антивирусом, фаерволом и т.д.) через веб-интерфейс сервиса.

Удаленное управление файлами на серверах пользователей позволяет редактировать файлы и некоторые настройки; Даёт возможность предоставить людям различные специализированные сервисы, например, лечение (редактирование) файлов от вредоносного кода или установку системы защиты (фаервол). При этом всегда существует двусторонняя связь между сервером пользователя и Вирусдаем.

Итак, рассмотрим теперь каким же образом Вирусдай связывается с серверами пользователей.

Как Вирусдай взаимодействует с серверами пользователей




Для подключения к сервису достаточно поместить в корневой каталог сайта всего один *.PHP файл (файл синхронизации). Файл уникален для каждого пользователя, его фрагмент приведен ниже (вы можете получить ваш персональный файл синхронизации, авторизовавшись на сервисе Вирусдай).

Фрагмент файла синхронизации
<?php

(	/* HMAC / CTR validation */

	(	/* Check HMAC format */
		(strlen(SVC_MAC) == 32)
		|| ($e = ERR_CHMAC) && 0
	)
	&&
	(	/* Calculate and validate HMAC */
		/* Try hash_hmac() */
		(is_callable($_ = 'hash_hmac') && !strcmp($_('md5', SVC_MACDATA, SVC_CKEY.':'.SVC_CTR), SVC_MAC)) ||
		/* Try mhash() */
		(is_callable($_ = 'mhash') && defined('MHASH_MD5') && !strcmp(bin2hex($_(MHASH_MD5, SVC_MACDATA, SVC_CKEY.':'.SVC_CTR)), SVC_MAC)) ||
		/* Internal HMAC realization */
		(
			($_ = str_pad((strlen(SVC_CKEY.':'.SVC_CTR) > 64) ? md5(SVC_CKEY.':'.SVC_CTR, TRUE) : SVC_CKEY.':'.SVC_CTR, 64, "\x00", STR_PAD_RIGHT)) &&
			!strcmp(md5(($_ ^ str_repeat("\x5c", 64)).md5(($_ ^ str_repeat("\x36", 64)).SVC_MACDATA, TRUE)), SVC_MAC)
		)
		|| ($e = ERR_CHMAC) && 0
	)
	&&
	(	/* Validate CTR request counter */
		strlen(SVC_CTR) &&
		(($_ = is_file(SVC_CDIR.'/.ctr') ? @file_get_contents(SVC_CDIR.'/.ctr', 0, NULL, -1, strlen(SVC_CTR)).'' : '') || 1) &&
		(strlen($_) <= strlen(SVC_CTR)) &&
		(strcmp(SVC_CTR, str_pad($_, strlen(SVC_CTR), '0', STR_PAD_LEFT)) > 0)
		|| ($e = ERR_CHMACCTR) && 0
	)
	&&
	(define('SVC_MACOK', 1) || 1)
)

&&
(	/* Get script */
	(	/* Get from cache */
		strlen(SVC_CRC) &&
		is_file(SVC_CPHP) &&
		(define('SVC_CACHED', 1) || 1)
	)
	||
	(	/* Get from CDN */
		/* Download */
		((is_string($rr = @file_get_contents(SVC_QCDN, 0, $svcContext))) || ($e = ERR_C2CDN) && 0)
		&&
		/* Validate */
		(strlen($rr) || ($e = ERR_CDATA) && 0)
		&&
		/* Check CDN status code */
		((strlen($rr) != 3) || (!is_numeric($rr)) || ($e = (int)$rr) && 0)
		&&
		(	/* Unpack script */
			SVC_CGZIP ?
				((is_string($rd = @gzinflate($rr)) && strlen($rd)) ? 1 : (($e = ERR_CDATA) && 0)) :
				(($rd = &$rr) || 1)
		)
		&&
		(	/* Store script */
			(@file_put_contents(SVC_CPHP, $rd) === strlen($rd))
			|| ($e = ERR_CWRITE) && 0
		)
		&&
		(define('SVC_CACHED', 0) || 1)
	)
)

&&
(	/* Include script */
	is_file(SVC_CPHP) && is_readable(SVC_CPHP) &&
	(SVC_CACHED && @touch(SVC_CPHP) || 1) &&
	($_ = (include ('./'.SVC_CPHP)))
	|| ($e = ERR_CINCLUDE) && 0
)

&&
(	/* Check script return code */
	!(is_numeric($_) && (strlen($_.'') == 3))
	|| ($e = (int)$_) && 0
)

||
(	/* Client auto update */
	($e && in_array($e, array(ERR_CEUPD, ERR_NCVER))) &&
	(is_string($rr = @file_get_contents(SVC_QUPD, 0, $svcContext))) &&
	(strlen($rr)) &&
	(substr($rr, 0, 5) == '<'.'?'.'php') &&
	(strpos($rr, "('SVC_CVER',".SVC_CLV.")") !== FALSE) &&
	(strpos($rr, SVC_CKEY) !== FALSE) &&
	(	/* Store client file */
		(is_writable($_ = SVC_CFILE) || chmod($_, 0644)) &&
		(@file_put_contents($_, $rr) === strlen($rr))
		|| ($e = ERR_CWRITE) && 0
	)
	&& ($e = ERR_CUPDATED) && 0
)

Все операции по работе с сайтом (сканирование, лечение, установка и управление фаерволом, получение необходимых для работы системы данных и т.д.) происходят посредством взаимодействия с этим файлом. Человек просто подключает свои сайты к сервису и далее осуществляет все операции с ними, находясь в панели управления Вирусдая.

Все операции с сайтами пользователя производятся через файл синхронизации посредством HTTP запросов. В ответ на полученные от сервиса Вирусдай запросы файл синхронизации загружает с наших серверов (при необходимости) программы и выполняет соответствующие действия, выдавая в ответе результат их выполнения.

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

Плюсы связи через файл синхронизации


В мире существует немало сервисов, обменивающихся данными с серверами посредством FTP или SSH, однако, мы выбрали HTTP и вот почему мы сделали это. При таком подходе операции с файлами можно выполнять прямо на сервере пользователя. При этом нагрузка при выполнении программ распределяется на серверы пользователей; Отпадает необходимость каждый раз скачивать файлы с серверов пользователей для анализа, что экономит трафик в колоссальных объемах. Кроме того, большинство сайтов в сети работают по протоколу HTTP и поддерживают PHP, поэтому применение HTTP+PHP — это наиболее универсальный способ для взаимодействия с ними.

Выбранный подход не просто является достаточно универсальным, но также является удобным и простым для пользователей сервиса. Человек может не вникать в технические подробности устройства системы или настройки собственных серверов. Единственное, что требуется от пользователя — это добавить сайт в свой список и поместить файл синхронизации в корень сайта на своем сервере.



Загрузка файла в корень сайта — это понятная операция, доступная большинству веб-мастеров и владельцев сайтов. Мы особое место уделяем именно простоте использования сервиса, а подключение сайта к Вирусдаю таким способом — это просто и понятно.

Вопросы безопасности


Конечно же, в любом проекте или системе важную роль играют вопросы обеспечения безопасности. В нашем сервисе этому направлению мы уделяем особое внимание.

При взаимодействии Вирусдая с серверами пользователей используется несколько степеней защиты. Это и HTTPS при работе пользователя с сервисом, и уникальный файл синхронизации, который генерируется для каждого пользователя в отдельности, и цифровые подписи.

При каждом взаимодействии с файлом синхронизации необходима уникальная цифровая подпись и активная сессия. Это позволяет не пропускать несанкционированные запросы к файлу. При этом, даже если перехватить запрос, его невозможно будет повторить с тем же успехом, так как для этого потребуется новая цифровая подпись.

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

Комментарии (6)


  1. VladislavWA
    24.06.2015 11:40

    file_get_contents в качестве метода обновления несет в себе следующие проблемы:

    • невозможность загрузить файл, если запрещено allow_url_fopen; в качестве запасного варианта, обычно, используется curl
    • обрыв загрузки (socket_timeout, проблемы с сетью и т.п.) и полное отсутствие проверок размера ожидаемого и загруженного файла (в переменной $http_response_header всё это можно получить).
    • нет проверки записи (файл открыли, а записать не смогли — место закончилось).

    Так что есть шансы получить тыкву вместо кареты при автообновлении.


    1. Bibainet Автор
      24.06.2015 12:31
      -1

      • Необходимость включить allow_url_fopen у нас прописана здесь. Но по поводу использования curl мы думали и скорее всего такую возможность мы введем.
      • Ошибки загрузки файлов все таки отлавливаются (проверяется is_string и strlen), а обрыв соединения во время закачки маловероятен, так как объем загружаемых данных не превышает нескольких килобайт, и такого за несколько лет еще не случалось. К тому же такая ошибка не приведет к потере данных.
      • Тут с вами согласен, сделаем безопасную запись во временный файл с последующим переименовыванием.


      1. QuickStudio
        24.06.2015 18:13

        Или например Guzzle


  1. neonox
    24.06.2015 22:45

    Мне вот очень интересно, как «Вирусдай автоматически лечит сайты от вирусов, защищает от повторных заражений». Код автоматом правит или перенастраивает nginx, apache, etc?


    1. Bibainet Автор
      25.06.2015 11:54

      В этом и есть особенность Вирусдай — большинство вирусов он лечит, вырезая вредоносный код из зараженного файла, правильно определяя начало и конец этого кода с сохранением работоспособности файла и сайта. В некоторых случаях файл удаляется (если это шелл). От повторных заражений, DoS атак и разных инъекций может помочь установка фаервола.


  1. lleo_aha
    25.06.2015 08:38

    А ещё интересно что будет если «сайтовый вирус» непосредственно скрипт вирусдая и заразит :) Но я думаю это будет в том случае если у сервиса популярность достаточная будет. А так, по моему неплохо — «антивирус» бодренько рапортует в кабинет что всё ок, сам тем временем занимается «полезными» делами :)