Модераторы: korob2001, ginnie
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> вопрос по quotemeta() 
V
    Опции темы
XeLpeR
Дата 10.10.2008, 11:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 11
Регистрация: 22.9.2008

Репутация: нет
Всего: нет



Здравствуйте, помогите пожалуйста разобраться.

Скрипт принемает переменную и экранирует метасимволы, чтоб в дальнейшем выпольнить "SELECT" запрос:
Код

my $var = quotemeta($cgi->url_param('var'));

...code..

my $sth = $dbh->prepare("SELECT * FROM table WHERE var=".$var."");
my $rv = $sth->execute();
if( !defined($rv) ) {
   print $dbh->errstr;
   exit(0);
}

my $hr = $sth->fetchall_arrayref( { } );


и теперь если в переменной не было метасимволов, то все будет работать нормлаьно, но если вдруг появляется какой либо метасимвол(. ' &* $  @ и т.д) запрос завершается с ошибкой - "Unknow message type: 'a'" !
Тип поля в базе - "character varying(15)".
А если quotemeta() при "INSERT" запросах - то все нормально.

Из-за чего может быть ошибка ?

PM MAIL   Вверх
KSURi
Дата 10.10.2008, 11:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 887
Регистрация: 8.6.2006
Где: Russia

Репутация: 2
Всего: 27



В данном случае вам надо использовать вовсе не quotemeta, а placeholder'ы DBI (потенциально опасные символы будут обработаны прозрачно для вас):
Код

my $var = param('var');
my $sth = $dbh->prepare('SELECT * FROM table WHERE var = ?');
$sth->execute($var);


Это сообщение отредактировал(а) KSURi - 10.10.2008, 11:25


--------------------
Died at Life.pl line 21
PM Jabber   Вверх
unicross
Дата 10.10.2008, 13:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 422
Регистрация: 15.6.2008

Репутация: 2
Всего: 53



или так

Код

my $var = param('var');

...code..

$var = $dbh->quote($var);
my $sth = $dbh->prepare("SELECT * FROM table WHERE var=$var");
my $rv = $sth->execute();
if( !defined($rv) ) {
   print $dbh->errstr;
   exit(0);
}

my $hr = $sth->fetchall_arrayref();

PM MAIL WWW   Вверх
shamber
Дата 10.10.2008, 13:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1422
Регистрация: 5.9.2006
Где: Россия

Репутация: нет
Всего: 18



Код

prepare("SELECT * FROM table WHERE var=$var");

не самый лучший вариант
PM MAIL Jabber   Вверх
KSURi
Дата 10.10.2008, 13:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 887
Регистрация: 8.6.2006
Где: Russia

Репутация: 2
Всего: 27



UPD: невнимательно прочитал пост unicross, сори

Это сообщение отредактировал(а) KSURi - 10.10.2008, 13:56


--------------------
Died at Life.pl line 21
PM Jabber   Вверх
ginnie
Дата 10.10.2008, 14:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 4
Всего: 49



XeLpeR, покажите строку запроса к БД, при которой выдается ошибка. Текст ошибки нестандартный, интересно smile 


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
unicross
Дата 10.10.2008, 16:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 422
Регистрация: 15.6.2008

Репутация: 2
Всего: 53



Цитата(shamber @  10.10.2008,  13:27 Найти цитируемый пост)

Код

prepare("SELECT * FROM table WHERE var=$var");

не самый лучший вариант


Чем он плох? Если вы о кавычках... То:

Метод quote() экранирует все специальные символы в строке и заключает строку в апострофы. Результат метода зависит от используемого драйвера базы данных.

Код

#!/usr/bin/perl -w
use CGI::Carp qw(fatalsToBrowser);
use DBI;
print "Content-type: text/html\n\n";

my $ds = 'DBI:mysql:tests:localhost';
my $user = 'root';
my $passw = '';
my $db = DBI->connect($ds, $user, $passw) or die("Ошибка");
my $str = "Д'Артаньян и три мушкетера";
print $db->quote($str);
$db->disconnect(); # Закрываем соединение  



Выведет

Код

'Д\'Артаньян и три мушкетера'  


PM MAIL WWW   Вверх
ginnie
Дата 10.10.2008, 16:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 4
Всего: 49



unicross, существенное отличие использования quote() от placeholders в том, что подстановка осуществляется до синтаксического разбора строки:

Код

$var = '0; DROP TABLE table';
 


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
unicross
Дата 10.10.2008, 18:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 422
Регистрация: 15.6.2008

Репутация: 2
Всего: 53



Цитата(ginnie @ 10.10.2008,  16:38)
unicross, существенное отличие использования quote() от placeholders в том, что подстановка осуществляется до синтаксического разбора строки:

Код

$var = '0; DROP TABLE table';

Вы хотите сказать, что данное значение должно удалить таблицу table?


Код

#!/usr/bin/perl -w
use CGI::Carp qw(fatalsToBrowser);
use DBI;
print "Content-type: text/html\n\n";

my $ds = 'DBI:mysql:tests:localhost';
my $user = 'root';
my $passw = '';
my $dbh = DBI->connect($ds, $user, $passw);
if (!$dbh) {
   print "Не удалось установить подключение к базе данных.";
   exit();
}
# Исходная строка
$var = '0; DROP TABLE table';
$var = $dbh->quote($var);
$q = "CREATE TABLE `table` (tovar char(50)) ENGINE=MyISAM";
$dbh->do($q) or die("Ошибка. Таблица существует!");
# Добавляем запись
$dbh->do("INSERT INTO `table` VALUES($var)");
# Получаем результат
my $sth = $dbh->prepare("SELECT * FROM `table` WHERE tovar=$var");
$sth->execute();
if ($sth->err) {
   # Если возникла ошибка
   print "Ошибка " . $sth->errstr;
}
else {
   while (my $row = $sth->fetchrow_arrayref()) {
      print $row->[0], "<BR>\n";
   }
}

# Получаем результат второй раз чтобы убедиться, что таблица не удалена
my $sth2 = $dbh->prepare("SELECT * FROM `table` WHERE tovar=$var");
$sth2->execute();
if ($sth2->err) {
   # Если возникла ошибка
   print "Ошибка " . $sth2->errstr;
}
else {
   while (my $row = $sth2->fetchrow_arrayref()) {
      print $row->[0], "<BR>\n";
   }
}

$dbh->disconnect(); # Закрываем соединение 


Выведет

Код

0; DROP TABLE table
0; DROP TABLE table


Почему тогда таблица не была удалена? Ведь я не только вставил значение в поле, но и дважды его получил!

Даже строка

Код

$var = "''; DROP TABLE `table`;";


не является проблемой. После использования метода quote() строка

Код

"SELECT * FROM `table` WHERE tovar=$var"


будет преобразована в 

Код

"SELECT * FROM `table` WHERE tovar='0; DROP TABLE table'"


а не в

Код

"SELECT * FROM `table` WHERE tovar=0; DROP TABLE table"


в этом случае конечно придется туго  smile 

ginnie, я не спорю, применение placeholders является хорошим решением. Особенно если добавляется или изменяется много записей, то этот способ очень эффективен, т.к. запрос готовится один раз.

Код

my $result = $db->prepare("INSERT INTO city VALUES (NULL, ?)");
$result->execute("Саратов");
$result->execute("Омск");
$result->execute("Тверь");
$result->execute("Иркутск");



XeLpeR, покажите строку запроса к БД. Мне тоже интересно...
PM MAIL WWW   Вверх
shamber
Дата 10.10.2008, 18:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1422
Регистрация: 5.9.2006
Где: Россия

Репутация: нет
Всего: 18



не самый лучший вариант потому что placeholders все-таки лучше использовать.

Это сообщение отредактировал(а) shamber - 10.10.2008, 18:38
PM MAIL Jabber   Вверх
unicross
Дата 10.10.2008, 19:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 422
Регистрация: 15.6.2008

Репутация: 2
Всего: 53



shamber, спорить на эту тему не буду.


В случае с XeLpeR первая ошибка в строке

Код

my $sth = $dbh->prepare("SELECT * FROM table WHERE var=".$var."");

отсутствие апострофов
Код

my $sth = $dbh->prepare("SELECT * FROM table WHERE var='".$var."'");


Потом, насколько я понял, функция quotemeta() экранирует не только метасимволы, но и все, что не подпадает под условие /[A-Za-z_0-9]/

Код

#!/usr/bin/perl -w
use CGI::Carp qw(fatalsToBrowser);
print "Content-type: text/html\n\n";

my $str = "Строка с ' & символами string123";
print quotemeta($str);


выведет

Код

\С\т\р\о\к\а\ \с\ \'\ \&\ \с\и\м\в\о\л\а\м\и\ string123


Получаем ужастный SQL-запрос

Код

SELECT * FROM table WHERE var=\С\т\р\о\к\а\ \с\ \'\ \&\ \с\и\м\в\о\л\а\м\и\ string123


Ничего странного в ошибке нет. Это закономерность.

PM MAIL WWW   Вверх
ginnie
Дата 10.10.2008, 20:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Комодератор
Сообщений: 1287
Регистрация: 6.1.2008
Где: Москва

Репутация: 4
Всего: 49



unicross, по поводу SQL-injection я был не прав! smile 

Это сообщение отредактировал(а) ginnie - 10.10.2008, 20:01


--------------------
Написать код, понятный компьютеру, может каждый, но только хорошие программисты пишут код, понятный людям. (Мартин Фаулер. Рефакторинг)
PM MAIL Skype Jabber   Вверх
XeLpeR
Дата 10.10.2008, 22:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 11
Регистрация: 22.9.2008

Репутация: нет
Всего: нет



Цитата(unicross @ 10.10.2008,  19:11)
В случае с XeLpeR первая ошибка в строке

Код

my $sth = $dbh->prepare("SELECT * FROM table WHERE var=".$var."");

отсутствие апострофов
Код

my $sth = $dbh->prepare("SELECT * FROM table WHERE var='".$var."'");


Потом, насколько я понял, функция quotemeta() экранирует не только метасимволы, но и все, что не подпадает под условие /[A-Za-z_0-9]/


Извиняюсь, но в запросе есть кавычки, просто я писал по памяти и забыл тут их поставить  smile 

Я подозреваю,что эта ошибка вылазит, потому что на 2-ом ноуте у меня винда и стоит PgPP - может из-за него.( пишет что ошибка в файле PgPP.pm line 730)

Добавлено @ 22:42
И еще заметил,что эта ошибка возникает когда в запросе появляются 2 или больше обратных слеша 

ошибка
Код

$dbh->prepare("SELECT * FROM table WHERE var='str\\' dfdfdf');

 
все нормально работает 

Код

$dbh->prepare("SELECT * FROM table WHERE var='str\.dfgdfgd'");


но так не экранируется кавычка
Код

$dbh->prepare("SELECT * FROM table WHERE var='str\'dfgdfgd'");




Это сообщение отредактировал(а) XeLpeR - 10.10.2008, 22:42
PM MAIL   Вверх
XeLpeR
Дата 10.10.2008, 22:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 11
Регистрация: 22.9.2008

Репутация: нет
Всего: нет



Цитата(ginnie @ 10.10.2008,  14:33)
XeLpeR, покажите строку запроса к БД, при которой выдается ошибка. Текст ошибки нестандартный, интересно smile

$profile = IP или '0.0.0.0'(если что-то не верно)
Код

my $login = quotemeta($cgi->url_param('login'));
if( $login ne '' ) {
    $login = " OR login='".$login."'";
}

my $users = $db->hashsref("SELECT uid, login, ip, puid FROM users WHERE ip LIKE '%".$profile."%'".$login, { } );
$users = 0 if scalar(@$users) == 0 ;


функциия hashsref():
Код

sub hashsref
{
    my ($self,$sql,$h) = @_;
    
    my $sth = $dbh->prepare($sql);
    my $rv = $sth->execute();
    if( !defined($rv) ) {
        print "Query ERROR : ".$dbh->errstr."\n";
        exit(0);
    }

    my $hr = $sth->fetchall_arrayref($h);
    $sth->finish();
    
    return $hr;
}


п.с. ошибка в файле PgPP.pm line 730 , для работы с PgSQL :
Код

sub execute {
    my $self = shift;
    my $pgsql = $self->{postgres};
    my $handle = $pgsql->get_handle();

    my $query_packet = 'Q'. $self->{statement}. "\0";
    DBD::PgPP::Protocol::_dump_packet($query_packet);
    $handle->send($query_packet, 0);
    $self->{finisy}        = undef;
    $self->{affected_rows} = 0;
    $self->{last_oid}      = undef;

    my $stream = $pgsql->get_stream();
    my $packet = $stream->each();
    printf "Recieve %s\n", ref($packet) if $DBD::PgPP::Protocol::DEBUG;
    if ($packet->is_error()) {
        $self->_to_end_of_response($stream);
        die $packet->get_message();
    }
    elsif ($packet->is_end_of_response()) {
        $self->{finish} = 1;
        return;
    }
    if ($packet->is_empty) {
        $self->{finish} = 1;
        $self->_to_end_of_response($stream);
        return;
    }
    if ($packet->is_cursor_response) {
        $packet->compute($pgsql);
        my $row_info = $stream->each();
        if ($row_info->is_error()) {
            $self->_to_end_of_response($stream);
            croak $row_info->get_message();
        }
        $row_info->compute($pgsql);
        $self->{stream} = DBD::PgPP::ReadOnlyPacketStream->new($handle);
        $self->{stream}->set_buffer($stream->get_buffer);
        while (1) {
            my $tmp_packet = $self->{stream}->each();
            printf "-Recieve %s\n", ref($tmp_packet) if $DBD::PgPP::Protocol::DEBUG;
            if ($tmp_packet->is_error()) {
                $self->_to_end_of_response($stream);
                croak $tmp_packet->get_message();
            }
            $tmp_packet->compute($pgsql);
            last if $tmp_packet->is_end_of_response;
        }
        $self->{stream}->rewind();
        $stream->set_buffer('');
        return;
    }
    else {
        $packet->compute($pgsql);
        $self->{finish} = 1;
        while (1) {
            my $end = $stream->each(); # тут ошибка - line 730 ))))
            printf "-Recieve %s\n", ref($end) if $DBD::PgPP::Protocol::DEBUG;
            if ($end->is_error()) {
                $self->_to_end_of_response($stream);
                croak $end->get_message();
            }
            last if $end->is_end_of_response();
        }
        return;
    }
}




Это сообщение отредактировал(а) XeLpeR - 10.10.2008, 22:59
PM MAIL   Вверх
XeLpeR
Дата 22.10.2008, 22:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 11
Регистрация: 22.9.2008

Репутация: нет
Всего: нет



Я был прав, ошибка возникает только если используется  модуль PgPP.pm, а при использовании Pg.pm все работает корректно.

Всем спасибо и звиняюсь за ложную тревогу )
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Perl: CGI программирование"
korob2001
sharq
  • В этом разделе обсуждаются вопросы относящиеся только к CGI программированию
  • Если ваш вопрос не относится к системному или CGI программированию, задавайте его в общем разделе
  • Если ваш вопрос относится к системному программированию, задавайте его здесь
  • Интерпретатор Perl можно скачать здесь ActiveState, O'REILLY, The source for Perl
  • Справочное руководство "Установка perl-модулей", качать здесь


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, korob2001, sharq.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Perl: разработка для Web | Следующая тема »


 




[ Время генерации скрипта: 0.0856 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.