Защита от сканирования сайта ботами

Судя по вот этому посту на drupal.ru, не я один подвергаюсь периодическим набегам ботов :) Поделюсь как решил эту проблему у себя в блоге.

В .htaccess, в секцию <IfModule mod_rewrite.c> нужно добавить:

RewriteRule \.(cgi|rdf)$ - [F]
RewriteRule http: - [F]
RewriteRule xmlrpc\.php$ - [F]
RewriteRule ^wp- - [F]
RewriteRule ^modx/ - [F]
RewriteRule ^e107 - [F]
RewriteRule ^bitrix/ - [F]
RewriteRule ^netcat - [F]
RewriteRule ^typo3/ - [F]
RewriteRule ^cms/ - [F]
RewriteRule ^administrator/components/ - [F]
RewriteRule mambots/ - [F]
RewriteRule ^includes/ - [F]
RewriteCond %{QUERY_STRING} http:
RewriteRule .* - [F]

Добавлено: 22 Июля 2018 10:13:40 Добавил: Андрей Ковальчук

mod_rewrite и GET параметры

В директиве RewriteRule нельзя обращаться к GET параметрам (той части запроса, которая идёт после символа ?), т.е. нельзя написать так:

# not work
RewriteRule ^node\?p=(\d+) index.php?q=node&page=$1

Зато это можно сделать в директиве RewriteCond:
# work
RewriteCond %{QUERY_STRING} p=(\d+)
RewriteRule ^node$ index.php?q=node&page=%1

Добавлено: 19 Июля 2018 21:50:02 Добавил: Андрей Ковальчук

Примеры использования HTTP/1.1 304 Not Modified

Для разгрузки канала клиента за счет кеширования браузером страниц можно использовать следующий код, позволяющий браузеру не загружать те страницы, которые у него уже есть в кэше. Аналогично можно сделать и для изображений. C помощью директив файла .htaccess сделана настройка чтобы все файлы с сервера отправлялись через index.php:

<?php
global $url;
$url    = $_SERVER['REQUEST_URI'];

if($url==""||$url=="/")
   $url="index.htm" ;
else $url=substr($url, 1);

if ( !file_exists( $url ) )     { header("HTTP/1.0 404 Not Found"); exit();}

// Получаем время последней модификации кэш-файла
$lastModified = max(filemtime($url),filemtime('index.php')); $slastModified = gmdate('D, d M Y H:i:s', $lastModified) . ' GMT';
// Выдаём заголовок HTTP Last-Modified
header('Last-Modified: ' . $slastModified ); 
// Получаем заголовки запроса клиента - только для Apache
$headers = getallheaders(); 
if (isset($headers['If-Modified-Since'])) {  // Разделяем If-Modified-Since (Netscape < v6 отдаёт их неправильно) 
   $modifiedSince = explode(';', $headers['If-Modified-Since']); 
   // Преобразуем запрос клиента If-Modified-Since в таймштамп
   $modifiedSince = strtotime($modifiedSince[0]); 
   // Сравниваем время последней модификации контента с кэшем клиента
   if ($lastModified <= $modifiedSince) { header('HTTP/1.1 304 Not Modified'); exit(); } // Разгружаем канал передачи данных!
   } 
echo "<DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n<HTML>\n";
echo "<HEAD>\n";
echo "<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=windows-1251\">\n";
echo "<meta http-equiv=\"Last-Modified\" content=\"".$slastModified."\">\n";
?>

.htaccess:
RewriteEngine On
RewriteCond %{REQUEST_URI} !index\.php$
RewriteCond %{REQUEST_URI} !\.jpg$
RewriteCond %{REQUEST_URI} !\.gif$
RewriteCond %{REQUEST_URI} !\.png$
RewriteCond %{REQUEST_URI} !\.js$
RewriteCond %{REQUEST_URI} !\.txt$
RewriteCond %{REQUEST_URI} !\.xml$
RewriteCond %{REQUEST_URI} !\.html$
RewriteCond %{REQUEST_URI} !\.htm$
RewriteCond %{REQUEST_URI} !\.mid$
RewriteCond %{REQUEST_URI} !\.avi$
RewriteCond %{REQUEST_URI} !\.css$
RewriteRule ^(.*)$ /index.php [L]

Добавлено: 29 Мая 2018 19:31:22 Добавил: Андрей Ковальчук

Управление доступом

Очень часто возникает необходимость запретить доступ к определенным файлам или папкам для определенных групп пользователей. В Web сервере Apache есть встроенные средства для решения данной проблемы.

Для запрета или разрешения доступа ко всем файлам и папкам в текущей и во всех вложенных директориях используется директива Order синтаксис ее очень прост:

Order [Deny,Allow] | [Allow,Deny]

# По умолчанию Deny,Allow

В зависимости от того в каком порядке указаны директивы меняется логика работы сервера. В случае если Deny,Allow то запрещается доступ со всех IP кроме оговоренных, в случае если Allow,Deny разрешается доступ со всех IP кроме оговоренных. Далее должны идти секции описания для доступа и запрета. Ключевое слово all означает со всех IP

Например, мы хотим запретить (блокировать) доступ с IP 81.222.144.12 и 81.222.144.20 и разрешить всем остальным нам необходимо добавить в .htaccess следующий код:
Order Allow,Deny
Allow from all
Deny from 81.222.144.12 81.222.144.20

Для обратной ситуации, когда мы хотим запретить доступ со всех IP кроме 81.222.144.12 и 81.222.144.20 нам необходимо добавить в .htaccess следующий код:
Order Deny,Allow
Deny from all
Allow from 81.222.144.12 81.222.144.20

Запрет или разрешение на доступ можно указывать не только на все файлы, но так же можно указывать на отдельный файл или группы файлов. Например, мы хотим запретить доступ всех пользователей кроме IP 81.222.144.12 к файлуpasswd.html, который расположен в текущей директории.
<Files "passwd.html">
  Order Deny,Allow
  Deny from all
  Allow from 81.222.144.12
</Files>

Так же можно запретить или разрешить доступ к определенной группе файлов. Например, к файлам с расширением «.key«:
<Files "\.(key)$">
  Order Deny,Allow
  Deny from all
  Allow from 81.222.144.12
</Files>

Добавлено: 29 Мая 2018 08:44:39 Добавил: Андрей Ковальчук

Хочу динамично создавать поддомены вида username.site.zone

Как это сделать правильно?
Если нет необходимости поддержки различных директорий, то получается что-то вроде этого:

RewriteEngine on
    RewriteCond   %{HTTP_HOST}                 ^www\.[^.]+\.host\.com$
    RewriteRule   ^(.+)                        %{HTTP_HOST}$1          [C]
    RewriteRule   ^www\.([^.]+)\.host\.com(.*) /home/thescript.php?domain=$1&path=$2

Добавлено: 24 Мая 2018 21:35:39 Добавил: Андрей Ковальчук

Кодировка

Иногда браузер пользователя не может корректно определить тип кодировки выдаваемого документа. Для решения этой проблемы используемая кодировка указывается в настройках Web сервера Apache и заголовке передаваемого документа. Причем для корректного распознания эти кодировки должны совпадать. На наших серверах по умолчанию используется кодировка cp1251

В HTML для указания кодировки используется тег:

<meta http-equiv="content-type" content="text/html; charset=Windows-1251">

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

Windows-1251 — Кириллица (Windows).
KOI8-r — Кириллица (КОИ8-Р)
cp866 — Кириллица (DOS).
Windows-1252 — Западная Европа (Windows).
Windows-1250 — Центральная Европа (Windows).
UTF-8 — двух байтовая кодировка

Теперь рассмотрим указание кодировки по умолчанию через .htaccess. AddDefaultCharset задает дефолтную таблицу символов (кодировку) для всех выдаваемых страниц на веб сервере Apache. Указываем кодировку на все файлы, в которой по умолчанию получает документы браузер:
AddDefaultCharset WINDOWS-1251

При загрузке файла на сервер, возможна перекодировка, его — указываем, что все получаемые файлы будут иметь кодировку windows-1251, для того что бы указать кодировку на загружаемые файлы напишем:
CharsetSourceEnc WINDOWS-1251

Если необходимо отменить перекодировку сервером файлов:
CharsetDisable on

Добавлено: 24 Мая 2018 20:32:41 Добавил: Андрей Ковальчук

Паролирование директорий

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

AuthName "Protected area, need authorization"
AuthType Basic
AuthUserFile /home/t/test/.authfile
require valid-user

Данный файл нужно положить в ту директории, на которую мы хотим поставить пароль.

Директива AuthName выводит сообщение при запросе пароля, все сообщение необходимо писать в одну строчку, синтаксис директивы тривиален:
AuthName "SEE TEXT"

Директива AuthType выбирает тип аутентификации. Возможны следующие типы: Basic или Digest. Второй может не поддерживаться некоторыми браузерами, поэтому пользоваться им не рекомендуется.
AuthType Basic | Digest

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

Создать данный файл можно двумя способами. Если у Вас установлена операционная система семейства Windows вы можете скачать отсюда программу которая генерирует данный файл. Либо подключится к серверу по SSH (инструкцию по подключению можно найти тут) и воспользоваться утилитой htpasswd.

Запустив htpasswd без параметров мы увидим:
beget@ginger ~ # htpasswd
Usage:
htpasswd [-cmdps] passwordfile username
htpasswd -b[cmdps] passwordfile username password
-c Create a new file.
beget@ginger ~ #

Здесь не будут рассматриваться все параметры этой команды, но вы можете сами прочитать подробности, запустивhtpasswd в unix shell или ознакомившись с соответствующей страницей документации по Apache.

Итак, изначально у нас еще нет файла с паролями и нам нужно его создать:
beget@ginger ~ # htpasswd -c authfile test1
New password:
Re-type new password
Adding password for user test1
beget@ginger ~ #

Здесь не будут рассматриваться все параметры этой команды, но вы можете сами прочитать подробности, запустивhtpasswd в unix shell или ознакомившись с соответствующей страницей документации по Apache.

После выполнения данной операции htpasswd создаст файл passwords, в котором окажется пользователь test1 и его пароль в зашифрованном виде:
beget@ginger ~ $ cat .authfile
   test1:zgco1KREjBY8M
 beget@ginger ~ $

А теперь мы хотим добавить еще одного пользователя. Так как файл с паролями у нас уже есть, мы просто не будем использовать ключ ‘-c’ :
beget@ginger ~ # htpasswd .authfile test2
New password:
Re-type new password:
Adding password for user test2beget@ginger ~ $ cat .authfile
test1:zgco1KREjBY8M
test2:eN3uA6t0kzV1c
beget@ginger ~ $

Вернемся к описанию директив паролирования директорий. Директива Require определяет пользователей, которые могут получить доступ
Require USER_NAME | valid-user

Указывая valid-user, вы разрешаете доступ всем пользователям, перечисленным в файле паролей.

Приведем пример для доступа определенных пользователей из файла с паролями .htpasswd
AuthName "Protected area, need authorization"
AuthType Basic
AuthUserFile /home/t/test/.authfile
require Alexey Kondr Fenix

Так же как и с запретом доступа по IP здесь можно использовать расширение <Files> ниже приведены два примера: установки пароля на группу файлов и на один определенный файл.
<Files "passwd.html">
  AuthName "Protected area, need authorization"
  AuthType Basic
  AuthUserFile /home/t/test/.authfile
  require valid-user
</Files>
 

<Files "\.(key)$">
  AuthName "Protected area, need authorization"
  AuthType Basic
  AuthUserFile /home/t/test/.authfile
  require valid-user
</Files>

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

Добавлено: 20 Мая 2018 21:03:56 Добавил: Андрей Ковальчук

Индексные страницы

Когда пользователь заходит на хост например http://gentoo.org принято, что открывается индексный файл index.* при его отсутствии — либо содержимое каталога, либо ошибку 403 (FORBIDDEN) если опция отключена — запрещен просмотр директорий.

За листинг файлов отвечает директива Indexes (показывать посетителю список файлов, если в выбранном каталоге нет файла index.html или его аналога).

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

# Запрет выдачи листинга пустого каталога
Options -Indexes

А чтобы выдавал листинг, нужно:
Options Indexes

Если же понадобиться разрешить просматривать список файлов, но чтобы при этом чаcть файлов определенного формата не отображалась, то запишем:
IndexIgnore *.php* *.pl

Выдает листинг каталога, т.е. его содержание со всем содержанием, за исключением файлов-скриптов PHP и Perl.

Если ваш веб-сайт построен на скриптах, то в качестве индексных часто могут использоваться файлы с другими расширениями — указать эти файлы можно с помощью директивы DirectoryIndex .
DirectoryIndex index.html index.shtml index.pl index.cgi index.php

Если же вы хотите что бы при обращении к каталогу открывался не index.html, а например, файл htaccess.php или /cgi-bin/index.pl:
DirectoryIndex htaccess.php /cgi-bin/index.pl

Добавлено: 18 Мая 2018 06:37:38 Добавил: Андрей Ковальчук

Задаем кодировку через htaccess

Кодировка – одна из тех вещей, «борьба» с которой потребляет порой немало времени.

Многих проблем можно избежать, задав кодировку по умолчанию в файле htaccess:

addDefaultCharset UTF-8

Еще один способ – прописать заголовок перед выводом текста в php-файле:
header('Content-Type: text/html; charset=utf-8');

Добавлено: 17 Мая 2018 19:54:27 Добавил: Андрей Ковальчук

Конфигурация для отладки или разработки

# PHP error handling for development servers
php_flag display_startup_errors on
php_flag display_errors on
php_flag html_errors on
php_flag log_errors on
php_flag ignore_repeated_errors off
php_flag ignore_repeated_source off
php_flag report_memleaks on
php_flag track_errors on
php_value docref_root 0
php_value docref_ext 0
php_value error_log /home/path/public_html/domain/PHP_errors.log
# [see footnote 3] # php_value error_reporting 999999999
php_value error_reporting -1
php_value log_errors_max_len 0

<Files /home/path/public_html/domain/PHP_errors.log>
Order allow,deny
Deny from all
Satisfy All
</Files>

Добавлено: 17 Мая 2018 11:17:45 Добавил: Андрей Ковальчук

Настройки для сайта в рабочем режиме

# PHP error handling for production servers
php_flag display_startup_errors off
php_flag display_errors off
php_flag html_errors off
php_flag log_errors on
php_flag ignore_repeated_errors off
php_flag ignore_repeated_source off
php_flag report_memleaks on
php_flag track_errors on
php_value docref_root 0
php_value docref_ext 0
php_value error_reporting -1
php_value log_errors_max_len 0

<Files /home/path/public_html/domain/PHP_errors.log>
Order allow,deny
Deny from all
Satisfy All
</Files>

Добавлено: 17 Мая 2018 11:17:10 Добавил: Андрей Ковальчук

Выставляем уровень вывода ошибок

integer - флаг, который задает глубину вывода ошибок. 0 - не выводить ничего, 8191- выводить в лог все. Значение 1 - выводит ошибки. Более подробное описение в документации по PHP.

# general directive for setting php error level
php_value error_reporting integer

Добавлено: 17 Мая 2018 11:15:43 Добавил: Андрей Ковальчук