CyberX

Unwired mind project homepage

RevolveR CMF v.1.7 coming soon

Few days we have to release next version of RevolveR CMF that's in previous versions named like CMS. Some works are done and we add new futures to code base such as interface improvements, additional API functions and layers, translations support, SEO additions, security fixes and some Data Base includes.

So. New logo are accomplished.

RevolveR CMF new logotype
RevolveR CMF new logotype

Как немного защитить сервер от взлома на Windows или UNIX

Данная статья не для ознакомления юных хакеров о том, как нагадить SEO ссылками на чужие сайты через взлом, а о том, как немного защитить сервер от взлома

Есть в PHP для операционных систем семейства Windows и UNIX(Linux, BSD, Mac OS, Android, etc..) интерсная инструкция для получения доступа к оболочке терминала или консоли shell_exec(). Посмотрим, что можно сдлеать с помощью нее.

Выполняем просмотр файла hosts вашего сервера:

Добавим в любой скрипт PHP строки кода:

shell_exec('cp -R /etc/hosts '.  $_SERVER['DOCUMENT_ROOT'] .'/test.txt' );

Сохраняем файл и выполняем скрипт. В папке public лежит файл hosts сервера с расширением txt.

Выполняем любой исполняемый бинарный скомпилированный ELF файл:

Ничего не будем химичить и просто вытащим из /bin/ исполняемый бинарник для просмотра файлов и директорий:


shell_exec('cp -R /bin/ls '.  $_SERVER['DOCUMENT_ROOT'] .'/test.jpg' );

Смотрим в public folder и видим исполняемый файл листинга под именем test.jpg.

Выполним его:

print shell_exec($_SERVER['DOCUMENT_ROOT'] .'/test.jpg -la' );

Видим, что ls под видом test.jpg выполнился на ура и мы можем распечатать все содержимое public_folder и посмотреть даже xATTRs.

Как предостеречь сервер от взлома

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

К счастью, защитить систему мы чуть чуть можем, просто проверив сигнатуру загружаемого файла, а не MIME тип, который можно легко скомпрометировать.

$upload_allow = !isset(explode('0000000: 7f45', shell_exec('xxd '. $file['file_tmp'] .' | head -5'))[1]) ? true : null;

Тем же самым shell_exec() прямо при загрузке файла, долго не думая, проверяем прямо пока файл лежит в temp и не перемещен его сигнатуру. Флаг $upload_allow true разрешает загрузку, а null блокирует.

Здесь мы считываем первые байты ELF файла и сверяем, что он не является исполняемым.

Кроме того, также не забывайте про операционную систему Windows. PHP также имеет инструкцию для доступа к CMD и там можно выполнить EXE, много чего интересного, а может даже опасного. Ищите сигнатуры самостоятельно.

Что может сделать хороший программист?

Без доступа к SSH установить на любой хостинг любые нужные утилиты и языки программирования именя только интерпретатор PHP. Например, развернуть среду Ruby, чтобы не переплачивать за хостинг и писать на чем угодно.

Кроме того, не забывайте проверять права на файлы.

Немного об атрибутах integrity и identity для загружаемых в браузер ресурсах

В связи с появлением в браузерных функциях решений криптографии на базе Subtle Crypt становится актуальным проверять целостность и оригинальность загружаемых при ходе парсинга HTML файлов таких как JavaScript файлы, CSS файлы, шрифты и картинки. Делается это путем хэширования всего содержимого файла получаемого по HTTP или HTTPS с последующим указанием атрибута хэша, который будет сверять наличие в файле изменений и блокировать обработку этих файлов при наличии коррумпированности содержимого.

Решения для проверки контрольной суммы содержимого загружаемого в браузер

Существует их 2 и они очень похожи.

  • Integrity проверка на базе CORS;
  • Indentity проверка без взаимодействия с CORS.

Проверять CORS на данный момент является дурным тоном. Он еле включается в браузере и должен быть выставлен в положение включено сервером. Я, например, не смог активировать Cross Origin путем установки заголовка сервером Apache и решил использовать identity, которая работает так же, но гораздо лучше.

Проверка хэширования файлов на базе Identity

Вот пример объявления проверки на наличие сбоев в контенте файла, которые могут быть обусловлены подменой содержимого или какой-то коллизией сети.


<script data-module="revolver core" src="/app/revolver.js" identity="sha512-46045bb024235cb263a67020252cf384491c34be4d7b202f3832cdd641017f2a2ea4a3b820057af0bae3e3553fdb13ddbd9bdf3b0089d7d2fc9e71ee1e50943c" crossorigin="anonymous"></script>

Обратите внимание на атрибут identity. Он может содержать два формата checksum файла. Обычно это либо hash файла в формате строки SHA, либо это тот же SHA, но с дополнительной оберткой в base64.

Вы вычисляете контрольную строку JavaScript файла с помощью библиотеки Open SSL или существует онолайн генератор: SRI generator; объявляете атрибуты identity или crossorigin. После этого браузер парсит теги и сверяет контрольные суммы. Если кто-то или что-то повредили файлы, подменили содержимое или возникла коллизия сети ‐ браузер блокирует выполнение этих файлов или отрисовку изображений, а также обработку CSS или шрифта.

Автоматическая генерация SHA Hash для локальных файлов сервера на PHP

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

Вот решение на PHP 7 для автоматической генерации тегов script с автоматической установкой атрибутов identity и контрольных сумм.


define('scripts', [
	[
		'part' => 'core', 
		'path' => '/app/revolver.js',
		'name' => 'revolver core'
	],

	[
		'part' => 'module', 
		'path' => '/app/revolver-cmf-module-1.js',
		'name' => 'revolver-executable-1'
	],

]);

// Generate identity hashes for core JS

$scripts = [];
foreach (scripts as $s) {

	$scriptTag = '<script data-module="'. $s['name'] .'" src="'. $s['path'] .'" identity="sha512-'. hash('sha512', file_get_contents(site_host . $s['path'])) .'" crossorigin="anonymous"';

	switch ($s['part']) {

		case 'core':
				
			$scriptTag .= '></script>';

			break;
		
		case 'module':
			
			$scriptTag .= ' defer="defer">';

			break;
	}
	
	
	$scripts[] = $scriptTag;
}

Описываем данные JavaScript файлов и указываем параметры. Параметр part установленный в значение module просто помогает системе добавить атрибут defer="defer", который позволяет не писать проверку на Contents Loaded или подобную в браузере, не писать проверку на инициализацию и просто запускает все defer скрипты в последний момент после обработки HTML браузером.

Здесь я использую самый злобный из доступных алгоритм SHA-512.

Далее, скрипты можно вывести в шаблон.

<?php foreach ($scripts as $s) print $s; ?>

Аналогично вы можете использовать автоматические контрольные суммы для картинок, шрифтов и CSS файлов.

Integrity и Identity возможно не нужны для соединеий по SSL

Скорее всего эти целостности(identity & integrity) хороши для протокола HTTP, но не имеют смысла для порта 443 и протокола HTTPS, который и так шифрует содержимое передаваемое в сети, однако, чем черт не шутит.

Данное решение также уже интегрировано в следующий release RevolveR CMF.

Перенаправление на HTTPS с проверкой доступнойсти зеркала без блокировки Nginx

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

Что мы не можем использовать? Не можем использовать Apache потому что большинство серверов работает в связке с nginx, который сломает проверку портов и условие не заработает.

В таком случае используем чистый PHP:


 Check for SSL domain mirror availible */
if( (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || $_SERVER['SERVER_PORT'] == 443 ) {

	// SSL Enabled & Core started over HTTPS

} 
else {

	if( (bool)file_get_contents('https://'. $_SERVER['HTTP_HOST'] .'/License.txt', false, stream_context_create(['http' => ['timeout' => 1]])) ) {

		header('Location: https://'. $_SERVER['HTTP_HOST'] );

	}
}

Что-то конкретное поясняить здесь не хочется, но стоит уточнить, что нужен какой-то текстовый файл небольшого размера, лежащий в корне сайта. Он будет служить источником выражения true для проверки доступа к нему через HTTPS. У соединения задан timeout 1 секунда и поэтому все происходит очень быстро.

Например, для RevolveR CMF мы выбрали в качестве проверочного файла лицензию.

Как получить при JOIN MySQL запросе совпадающие по имени столбцы

В очередной раз улучшая фирменные алгоритмы нашего фирменного движка Базы Данных DBX на базе синтаксиса ABQ, мы смогли слегка улучшить алгоритмы построения сложных JOIN SQL запросов.

Что характерно для функций MySQLi, входящих в стандартный набор PHP 7, так это наличие функций в основном для схлопывания резултата SQL запроса в строки, когда ассоциативный массив или объект, а также нумерованный массив ячеект таблицы накапливается для вывода.

Все три самые важные функции работают таким образом, что создают либо многомерный именованный массив или именованный объект, или нумарованный массив без пояснения наименования ячеек таблицы. Представим, что у нас три таблицы и в каждой есть ячейка с именем `FIELD_ID`. При выполнении операци fetch и сборе данных из БД значение `FIELD_ID` будет всегда перезаписано данными из последней выборки. Поскольку значения могут в разных таблицах ячейки с одним и тем же именем иметь разные значения, мы не имеем большого смысла в MySQL запросе JOIN.

Вопрос не к вопросу о проектировании БД таким образом, что бы все стобцы во всех таблицах имели уникальные названия, а к вопросу отом, что могло бы быть удобным называть некоторые из них одинаково. Например, поля с числовым автоинкремент.

Я написал небольшой алгоритм для сбора всех данных из БД для определенных таблиц с использованием MySQL запроса JOIN таким образом, что данные дублированных имен ячеек не схлопываются и не перезаписываются последней строкой прохода цикла fetch.

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


$result = $DBX[0]->query('SELECT `revolver__nodes`.field_id, 
`revolver__nodes`.field_title, 
`revolver__nodes`.field_content, 
`revolver__nodes`.field_description, 
`revolver__nodes`.field_user, 
`revolver__nodes`.field_time, 
`revolver__nodes`.field_route, 
`revolver__nodes`.field_category, 
`revolver__nodes`.field_published, 
`revolver__nodes`.field_mainpage, 
`revolver__nodes`.field_country, 
`revolver__categories`.field_id, 
`revolver__categories`.field_title, 
`revolver__categories`.field_description, 
`revolver__comments`.field_id, 
`revolver__comments`.field_node_id, 
`revolver__comments`.field_user_id, 
`revolver__comments`.field_user_name, 
`revolver__comments`.field_content, 
`revolver__comments`.field_time, 
`revolver__comments`.field_published, 
`revolver__comments`.field_country 

FROM `revolver__nodes` 

INNER JOIN `revolver__categories` ON(`revolver__nodes`.field_category=`revolver__categories`.field_id) 
INNER JOIN `revolver__comments` ON(`revolver__nodes`.field_id=`revolver__comments`.field_node_id);', MYSQLI_USE_RESULT);

$fields = mysqli_fetch_fields($result);

$row_count = 0;

while($row = mysqli_fetch_array($result, MYSQLI_NUM)) {

    $fields_count = 0;

    foreach ($row as $field) {

        $row_data[$fields[$fields_count]->table][$fields[$fields_count]->name] = $field; 
        $fields_count++;
    
    }

    DBX::$result['result'][$counter++] = $row_data;

    $row_count++;
}

mysqli_free_result($result);

Здесь использован двойной цикл, раскладывающий данные в массив по индексам имен таблицы. Он простой и оптимизированный. Может быть пдобная проблема есть и у PDO, но я это не проверял. Алгоритм подключения к БД вы можете дописать сами.

Этот тройной JOIN выведет следующий результат, что дает исчерпывающие данные для любых манипуляций, а также упрощает работу с backend:

            [8] => Array
                (
                    [revolver__nodes] => Array
                        (
                            [field_id] => 4
                            [field_title] => ASUS K541UV: budget hackintosh for development
                            [field_content] => some text
                            [field_description] => budget hackintosh ASUS K541UV for $580
                            [field_user] => CyberX
                            [field_time] => 26/05/2019 20:05
                            [field_route] => /en-US/mac-os/asus-k541uv/
                            [field_category] => 4
                            [field_published] => 1
                            [field_mainpage] => 
                            [field_country] => 840
                        )

                    [revolver__categories] => Array
                        (
                            [field_id] => 4
                            [field_title] => Mac OS
                            [field_description] => Hackintosh tips
                        )

                    [revolver__comments] => Array
                        (
                            [field_id] => 16
                            [field_node_id] => 4
                            [field_user_id] => 1
                            [field_user_name] => CyberX
                            [field_content] => hi, marco. What mac os version have this problem?
                            [field_time] => 14/01/2019
                            [field_published] => 1
                            [field_country] => 840
                        )

                )

Это фрагмент массива результата запроса MySQL TRIPLE JOIN, где сохранены повторяющиеся имена столбцов с разными данными, оформленными в разных именованных индексах.

В новой версии DBX реализованы такие алгоритмы и чуть улучшены алгоритмы отношения с сервером БД. Запросы eXtended JOIN будут доступны в связке с автоматическим кэшированим в следующем релизе RevolveR CMF. Также мы проектируем алгоритм защиты от падения БД, когда можно будет получать полный доступ к сайтам на RevolveR CMF, но только для чтения. В мечтах так-же промежуточная обвязка для временного хранения данных данных, отправленных в БД, когда сам сервер БД лежит или не доступен, а данные будут закомичены при появлении соединения с хостом сервера данных.