The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

Ответы на типовые вопросы пользователей web-хостинга.

Подборка документации по web-программированию, Подборка статей по web-технологиям, Ссылки на информационные ресурсы.

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

При написании CGI скриптов, пожалуйста, изучите руководство по написанию безопасных web-скриптов и ознакомитесь с ответами на часто задаваемые вопросы (Дополнительное руководство 1, Дополнительное руководство 2).

Если Вы используйте PHP, прочитайте данный документ.
Пример участка кода с ошибкой:

    $fh=$query->upload($name);
    open (OUTFILE,"$userpath/$username/$name.tmp.jpg");
  1. Всегда нужно указывать направление потока в open, "<" отсутствует в данном примере.
  2. Обязательно необходимо параноидально проверять каждую переменную в open().
как минимум:

    $var ~ s/[^\w\-\.\_\d]//g;
    $var =~ s/\.\.//g;
Или лучше всего использовать перед каждым системным вызовом open(), system(), exec(), `..` и т.д. функцию:

# check_file($var);
sub check_file{                                                                           
        my($str) = @_;                                                                    
    if (($str =~ /[^\d\w\-\_\.\/]/) || ($str =~ /\.\./)){                                     
	die "Detected filename mistification !!!."
    }                                                                                     
    return 0;                                                                             
} 
Как должен выглядеть правильный код:

$fh=$query->upload($name);
check_file("$userpath/$username/$name.tmp.jpg");
open (OUTFILE,"<$userpath/$username/$name.tmp.jpg")|| die "Невозможно открыть файл.";

Вопрос кодировок.

Рекомендуется сохранять все документы на сервере в кодировке KOI8-R.

Клиенту документы в любом случае буду выдаваться в зависимости от его операционной системы, для пользователей Windows в cp1251, Unix - koi8-r.

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

Для активации русской локали необходимо в скрипт поместить код следующего вида:


use POSIX;
use locale;
$loc = POSIX::setlocale( &POSIX::LC_ALL, "ru_RU.KOI8-R" );

Диагностика ошибок.

На этапе тестирования работы скриптов, при отсутствии доступа к лог файлам, необходимо представить вывод ошибок интерпретатора perl в виде читаемом из обычно браузера. Для установки данного режима, на время отладки, рекомендуется вписать в начале неработающего скрипта use CGI::Carp 'fatalsToBrowser';

Не забудьте правильно прописать путь к интерпретатору языка perl в первой строке вашего скрипта (#!/usr/bin/perl) и убедится в отсутствии символа возврата каретки (код 0x0D) в надписи "#!/usr/bin/perl" (должен быть только символ перевода строки 0x0A, сохраните файл как unix текст в FAR [Shift+F2]). Если скрипт так и не подает признаков жизни, проверьте права доступа на документы закаченные на сервер, например с помощью ftp клиента файлового менеджера FAR. Для html документов права должны быть "-rw-r--r--", для CGI скриптов - "-rwxr-xr-x".

Помните, Две самые распространенные ошибки пользователей хостинга - это неправильно выставленные права доступа и присутствие символа возврата каретки (0x0D) в вашем скрипте.


Проблемы с закачкой файлов.

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


#!/usr/bin/perl
use CGI qw/:standard/;
$in_file = param('file');

..............

   if ( $in_file ) {

#	$mimetype = uploadInfo($in_file)->{'Content-Type'} || ''; Если нужно определить Mime тип закачиваемого обьекта.

	open (JPEG,">${http_dir}${pics_base}/${in_num}_${time}.jpg");
	binmode(JPEG);
	flock(JPEG, 2);
        while ($bytesread=read($in_file,$buffer,1024)) {
            print JPEG $buffer;
        }
	close(JPEG);
	close $in_file;


# Если нужно сохранить закачиваемый объект во временный файл кусок кода будет выглядеть:

	$tmp_file=tmpFileName($in_file);

	open (JPEG,">$realimg_dir/$g_user_name/$file_name");
	binmode(JPEG);
	binmode($t_file);
	flock(JPEG, 2);
	$counter=0;
	while (read ($t_file, $buff, 1024)) {
	    print JPEG $buff;
	}
	close(JPEG);
	close $t_file;
	unlink($t_file);

   }
Форма для закачки файла должна выглядеть следующим образом:

<FORM METHOD="POST" ACTION="/cgi-bin/script.cgi" enctype="multipart/form-data">
<input type="file" name="file">

Внимание !!! В случае использования русского апача с активизированной автоматической перекодировкой, для соблюдения целостности закачиваемого бинарного объекта необходимо в директории со скриптом создать файл .htaccess содержащий директиву CharsetRecodeMultipartForms Off.


Установка необходимых пользователю perl модулей.

Очень часто пользователи обращаются к администраторам систем хостинга с просьбой установить в систему perl-модуль необходимый для функционирования их скрипта. Ниже дается объяснение как установить свой модуль без вмешательства системного администратора. (Нужный модуль проще всего найти на http://search.cpan.org)

Установка модуля:

  1. Создайте у себя в домашнем каталоге директорию lib и в ней поддиректорию perl5 (cd ~;mkdir lib;cd lib;mkdir perl5).
  2. Распакуйте устанавливаемый модуль (tar -xzf модуль.tar.gz).
  3. Запустите "perl Makefile.pl prefix=$HOME;make;make test;make install".
В дальнейшем в скриптах, использующих установленный модуль, необходимо прописать:

  use lib "HOME/lib/perl5";
  use lib "HOME/lib/perl5/site_perl";
где, HOME - путь к вашей домашней директории (как правило /home/аккаунт/)

Небольшой FAQ.


Как преобразовать дату/время из одного формата в другой ?


    perldoc Date::Calc
Напрмер, для вычисления дня недели по дате, нужно использовать следующую конструкцию:

use Date::Calc qw(Day_of_Week);
@weekday=('Вс','Пн','Вт','Ср','Чт','Пт','Сб','Вс');

$weekday = Day_of_Week($year,$month,$day);
$week_day = $weekday[$n_wday];

Как получить значение cookie и выдать cookie браузеру ?

Для получения значения cookie предлагаю использовать функцию fetch_cookie (имя_cookie). Вот пример кода:



use CGI qw/:standard/;
use CGI::Cookie;
..............

sub fetch_cookie {
	my($name) = @_;
    foreach (keys %cookies){
	if ($_ eq $name){
	    return $cookies{$_}->value;
	}
    }
    return "";
}
...............

%cookies = fetch CGI::Cookie; # $cookies{"name"}->value;
................

$shopbm = fetch_cookie("shopbm") || 0;

Отправить cookie еще проще:


На perl:

use CGI qw/:standard/;
use CGI::Cookie;
..............

$cookie .= new CGI::Cookie(-name => "ИМЯ cookie",
	                   -value => "Значение",
                           -expires => '+5y',
                           -path => '/');

print "Set-Cookie: $cookie\n";
print "Content-type: text/html\n\n";
...............

Javascript:

<script language="JavaScript">
    function set_cookie(){
	document.cookie='lastvisit=<!--#include virtual="/cgi-bin/vsluhru/cur_date.cgi?epoch=1"-->; path=/; expires=Mon, 21-Mar-2005 22:46:30 GMT';
    }
</script>


Как закодировать и раскодировать последовательность %xx%xx поступающую из форм ?

Кодируем последовательность символов:


sub cgi_escape {
  my $toencode = shift;
  $toencode=~s/([^a-zA-Z0-9_.-])/uc sprintf("%%%02x",ord($1))/eg;
  return $toencode;
}

Раскодируем:


sub cgi_unescape {
  my $fromencode = shift;
  $fromencode =~ /%(..)/pack("c",hex($1))/ge;
  return $fromencode;
}

Для преобразования в UNICODE формат (например, для вставки русского текста в JavaScript блок) можно использовать функцию:


sub koi2utf{
    my($str)=@_;
	$_=$str;
	s/ё/&#1105;/g;
	s/Ё/&#1025;/g;
	s/ю/&#1102;/g;
	s/а/&#1072;/g;
	s/б/&#1073;/g;
	s/ц/&#1094;/g;
	s/д/&#1076;/g;
	s/е/&#1077;/g;
	s/ф/&#1092;/g;
	s/г/&#1075;/g;
	s/х/&#1093;/g;
	s/и/&#1080;/g;
	s/й/&#1081;/g;
	s/к/&#1082;/g;
	s/л/&#1083;/g;
	s/м/&#1084;/g;
	s/н/&#1085;/g;
	s/о/&#1086;/g;
	s/п/&#1087;/g;
	s/я/&#1103;/g;
	s/р/&#1088;/g;
	s/с/&#1089;/g;
	s/т/&#1090;/g;
	s/у/&#1091;/g;
	s/ж/&#1078;/g;
	s/в/&#1074;/g;
	s/ь/&#1100;/g;
	s/ы/&#1099;/g;
	s/з/&#1079;/g;
	s/ш/&#1096;/g;
	s/э/&#1101;/g;
	s/щ/&#1097;/g;
	s/ч/&#1095;/g;
	s/ъ/&#1098;/g;
	s/Ю/&#1070;/g;
	s/А/&#1040;/g;
	s/Б/&#1041;/g;
	s/Ц/&#1062;/g;
	s/Д/&#1044;/g;
	s/Е/&#1045;/g;
	s/Ф/&#1060;/g;
	s/Г/&#1043;/g;
	s/Х/&#1061;/g;
	s/И/&#1048;/g;
	s/Й/&#1049;/g;
	s/К/&#1050;/g;
	s/Л/&#1051;/g;
	s/М/&#1052;/g;
	s/Н/&#1053;/g;
	s/О/&#1054;/g;
	s/П/&#1055;/g;
	s/Я/&#1071;/g;
	s/Р/&#1056;/g;
	s/С/&#1057;/g;
	s/Т/&#1058;/g;
	s/У/&#1059;/g;
	s/Ж/&#1046;/g;
	s/В/&#1042;/g;
	s/Ь/&#1068;/g;
	s/Ы/&#1067;/g;
	s/З/&#1047;/g;
	s/Ш/&#1064;/g;
	s/Э/&#1069;/g;
	s/Щ/&#1065;/g;
	s/Ч/&#1063;/g;
	s/Ъ/&#1066;/g;
    return $_;
}

Как из скрипта перекинуть пользователя на другую страницу ?


    print "Status: 302\n";
    print "Location: http://www.test.com/somefile.html\n\n";

Приведите пожалуйста пример использования mod_rewrite ?

Вот пример одного из файлов .htaccess на www.opennet.ru:



# Перенаправим пользователей пришедших на http://man.opennet.ru
# на https://www.opennet.ru/man.shtml

RewriteEngine On
RewriteCond %{HTTP_HOST}  ^man.opennet.ru$ [NC]
RewriteRule .* https://www.opennet.ru/man.shtml [R]

# Перенаправим пользователей пришедших на индексную страницу
# http://www.tyumen.ru/~mc/linux/ на https://www.opennet.ru/map.shtml

RewriteCond %{HTTP_HOST}  ^www.tyumen.ru$ [NC]
RewriteCond %{REQUEST_URI}  ^/~mc/linux/$ [NC]
RewriteRule .* https://www.opennet.ru/map.shtml [L]

# Перенаправим пользователей с поисковиков пришедших на 
# http://www.tyumen.ru/~mc/linux/ на аналогичную страницу https://www.opennet.ru
RewriteCond %{HTTP_HOST}  ^www.tyumen.ru$ [NC]
RewriteCond %{REQUEST_URI}  ^/~mc/linux/(.*)$ [NC]
RewriteRule (.*) https://www.opennet.ru/$1 [R]

# Для IE запрашивающих favicon.ico выдадим Forbidden
RewriteCond %{REQUEST_URI} favicon.ico [NC]
RewriteRule .* / [F]

# Перенапривим программу зеркалирования FlashGet на http://chat.opennet.ru/stop.txt
RewriteCond %{HTTP_USER_AGENT} FlashGet [NC]
RewriteRule .* http://chat.opennet.ru/stop.txt [R]

# Запретим доступ (будет выдано Forbidden) для IP 192.168.1.13
RewriteCond %{REMOTE_ADDR} 192\.168\.1\.13
RewriteRule .* / [F]

# Незаметно подсунем роботу "AgentName/0.1" приходящему с IP 212.24.43.60 
# и запрашивающему скрипт navigator.cgi c параметром template=7
# документ /opennews/opennews_3.inc
RewriteCond %{REMOTE_ADDR} 212\.24\.43\.60
RewriteCond %{HTTP_USER_AGENT} AgentName/0.1
RewriteCond %{REQUEST_URI} navigator\.cgi
RewriteCond %{QUERY_STRING} template=7
RewriteRule .* /opennews/opennews_3.inc [L]



Как подключить свой обработчик ошибок 404, 403, и т.д. ?

Добавте .htaccess (missing.html - документ не найден, access.html - в доступе отказано):


	ErrorDocument 404 /missing.html
	ErrorDocument 403 /access.html

Как организовать в определенные директории вход по паролю ?

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



AuthName        "Welcome to Vsluh Banner Network HQ"
AuthType        Basic
AuthUserfile    /home/user/.htpasswd
require 	valid-user

Для ограничения доступа к отдельному документу private.html для пользователей master и robot, в .htaccess требуется прописать:




AuthName        "Welcome to Vsluh Banner Network HQ"
AuthType        Basic
AuthUserfile    /home/user/.htpasswd
require user 	master robot


Для создания файла паролей и занесения первого пользователя test наберите htpasswd -c /home/user/.htpasswd test, для добавления последующих пользователей используйте htpasswd /home/user/.htpasswd user

Для открытия доступа к директории только для сетей 192.168.4.0/24 и 192.168.3.0/24, пишем в .htaccess:



order allow,deny
allow from 192.168.4.0/24 192.168.3.0/24

Чтобы разрешить вход в директорию только пользователю greg с IP 192.168.4.11, пишем в .htaccess:



order 		allow,deny
allow 		from 192.168.4.11
AuthType 	Basic
AuthName 	"WEMBAIL HQ"
AuthUserFile 	/home/user/.htpasswd
require 	valid-user


Как перекодировать текст из cp1251 в koi8-r ?


#!/usr/bin/perl

sub wintokoi {
    my $pvdcoderwin=shift;
    $pvdcoderwin=~ tr/\xB8\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF\x91\x92\x93\x94\x96\x97\x9B\x8B\xBB\xAB\xB9\xAD\xA7\xA0\x82\x84\x85/\ё\xE1\xE2\xF7\xE7\xE4\xE5\xF6\xFA\xE9\xEA\xEB\xEC\xED\xEE\xEF\xF0\xF2\xF3\xF4\xF5\xE6\xE8\xE3\xFE\xFB\xFD\xFF\xF9\xF8\xFC\xE0\xF1\xC1\xC2\xD7\xC7\xC4\xC5\xD6\xDA\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD2\xD3\xD4\xD5\xC6\xC8\xC3\xDE\xDB\xDD\xDF\xD9\xD8\xDC\xC0\xD1\'\'\"\"\-\-\>\<\"\"\╧\-\ \ \,\,\./;
    return $pvdcoderwin;
}

while (<>){
    print wintokoi($_);
}

Как отправить письмо из скрипта ?


    $mail_prog="/usr/sbin/sendmail -t ";
    open (SENDMAIL, "|$mail_prog") || die "Can not run sendmail";
    print SENDMAIL "MIME-Version: 1.0\n";
    print SENDMAIL "Content-Type: text/plain; charset=\"koi8-r\"\n";
    print SENDMAIL "Content-Transfer-Encoding: 8bit\n";
    print SENDMAIL "To: $email\n";
    print SENDMAIL "From: $support_email\n";
    print SENDMAIL "Subject: $subj\n\n";
    print SENDMAIL "$body";
    close (SENDMAIL);

Приведите пожалуйста пример работающего куска SSI


<!--#if expr="\"$QUERY_STRING\" != /section\=00/ && \"$QUERY_STRING\" = /section\=/ " -->
    <!--#include virtual="/cgi-bin/groups.cgi?template=2&show=level1&$QUERY_STRING"-->
<!--#endif -->
<br>
<!--#include virtual="/cgi-bin/groups.cgi?template=2&show=level0&$QUERY_STRING"-->
<br>
<!-- поиск. начало -->
<!--#include file="search.inc"-->
<!-- поиск. конец -->
<!--#if expr="\"$HTTP_COOKIE\" = /shopkey/" -->
<!--#if expr="\"$QUERY_STRING\" = /mask\=/" -->
    <!-- сводные новости. начало -->
    <!--#include virtual="/cgi-bin/goods.cgi?template=1&sub_section=on&$QUERY_STRING"-->
    <!-- сводные новости. конец -->
<!--#else -->
<!--#if expr="\"$QUERY_STRING\" = /section\=00/" -->
<!--#else -->
<!--#if expr="\"$QUERY_STRING\" = /subgroup\=/" -->
    <!--#include virtual="/cgi-bin/groups.cgi?template=0&show=header&$QUERY_STRING"-->
    <!--#include virtual="/cgi-bin/goods.cgi?template=0&sub_section=on&$QUERY_STRING"-->
<!--#else -->
    <!--#include virtual="/cgi-bin/goods.cgi?template=0&$QUERY_STRING"-->
<!--#endif -->
<!--#endif -->
<!--#endif -->
<!--#else -->
    <!--#include virtual="/cgi-bin/goods.cgi?template=5&sub_section=on&$QUERY_STRING"-->
<!--#endif -->

Автор: Maxim Chirkov mc@tyumen.ru, https://www.opennet.ru
Публичное размещение документа разрешается только после согласия автора.


Спонсоры:
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2021 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру