Требуется помощь
Feb. 1st, 2006 10:24 amЭтот вопрос для меня настолько важен, что даже пишу в этом журнале.
Вопрос, естетственно, только для тех, кто на этих галерах.
Столкнулся я с большой проблемой. Это всё связано с факом про кавычки, слеши, PHP и Mysql.
Проблема - с определением субъекта прослешивания и окавычивания.
Поясню, почему проблема большая.
Сначала в факе я писал, что достаточно таким образом обработать данные - и всё будет зашибись.
Gотом до меня дошло, что это только строковые литералы можно защитить таким образом, а остальные части запроса надо защищать по-другому.
Сейчас собрался сесть таки переписывать, и столкнулся с вопросом:
Как обобщить тип данных, который требуется прослешивать и окавычивать?
Желательно, определение должно занимать не больше одной строки. Но не в ущерб точности.
Пусть больше. Но лишь бы это было ЧЁТКОЕ, всеобъемлющее определение!
Иначе у меня и вовсе почва уходит из-под ног.
Я-то хотел разделить рекоменации по защите запросов на две части - чёткую и нечёткую.
Чёткая - прослешивание литералов. Нечёткая - всё остальное.
но если нет точного определения для первой части, то и она становится нечёткой!
А выражение "данные", как и "строковый литерал" само по себе никакого смысла не несёт.
Хотел написать "всё, связанное со значением поля", но во-перваых, это криво, а во-вторых, как быть с литералами, не имеющими отношения к полям - SELECT 'aaa';?
http://community.livejournal.com/ru_php/552359.html
Вопрос, естетственно, только для тех, кто на этих галерах.
Столкнулся я с большой проблемой. Это всё связано с факом про кавычки, слеши, PHP и Mysql.
Проблема - с определением субъекта прослешивания и окавычивания.
Поясню, почему проблема большая.
Сначала в факе я писал, что достаточно таким образом обработать данные - и всё будет зашибись.
Gотом до меня дошло, что это только строковые литералы можно защитить таким образом, а остальные части запроса надо защищать по-другому.
Сейчас собрался сесть таки переписывать, и столкнулся с вопросом:
Как обобщить тип данных, который требуется прослешивать и окавычивать?
Желательно, определение должно занимать не больше одной строки. Но не в ущерб точности.
Пусть больше. Но лишь бы это было ЧЁТКОЕ, всеобъемлющее определение!
Иначе у меня и вовсе почва уходит из-под ног.
Я-то хотел разделить рекоменации по защите запросов на две части - чёткую и нечёткую.
Чёткая - прослешивание литералов. Нечёткая - всё остальное.
но если нет точного определения для первой части, то и она становится нечёткой!
А выражение "данные", как и "строковый литерал" само по себе никакого смысла не несёт.
Хотел написать "всё, связанное со значением поля", но во-перваых, это криво, а во-вторых, как быть с литералами, не имеющими отношения к полям - SELECT 'aaa';?
http://community.livejournal.com/ru_php/552359.html
Ой :)
Date: 2006-02-01 08:10 am (UTC)Или я что-то не так понимаю?
А так всё, введённое юзером, надо обрабатывать :) addslashes, quotemeta и пр
Re: Ой :)
Date: 2006-02-01 08:40 am (UTC)А КАК, плейсхолдерами или чем то еще - это уже дело техники
Re: Ой :)
Date: 2006-02-01 09:16 am (UTC)равно, как и параметру limit-а
в том-то всё и дело.
что понятие размывается прямо на глазах.
Это как с порнографией.
все мы чётко знаем, ЧТО именно надо обрабатывать через addslashes
а вот сформулировать - проблема.
Re: Ой :)
Date: 2006-02-01 02:19 pm (UTC)no subject
Date: 2006-02-01 02:28 pm (UTC)10 в LIMIT 10,5 - это параметр?
а имя поля в функции concat('Hello ',name) - параметр?
no subject
Date: 2006-02-01 03:41 pm (UTC)Оговорюсь сначала, что, по-моему, в любом случае слешение не вредит. Если у тебя число, то в нем кавычек быть не может, если в названии поля у тебя кавычка, то весь запрос пойдет лесом.
Теперь про параметры.
Я вижу это так:
1. Есть некий литерал, который представляет собой SQL-запрос или его часть. Это - константа. Ее слешить не надо. Если тот, кто писал эту часть, вбил туда лишние кавычки, то это уже проблема безопасности несколько другого порядка.
2. Параметры можно определять по-разному, в зависимости от семантики SQL или нет - это уже другой вопрос. Чтобы ответить на твой вопрос, я бы определил "параметры для слешения" - это те данные, которые приехали из внешнего источника, например, через переменные _GET или _POST, или через строки, выбранные из базы данных, прочитанные из файла и т.п. В некоторых языках (perl, ruby) этим данным в самом начале даже прилепляется ярлык "порченых" (tainted). Этот ярлык прилепляется и ко всем данным, в формировании которых поучаствовали эти порченые данные. При этом, при определенных настройках паранойи языка, порченые данные нельзя засунуть в драйвер базы данных в виде запроса. Поэтому любые параметры, приехавшие снаружи, надо "отпорчивать".
Т.о., если у тебя 10 родилось внутри программы, и ты не брал его из значения $_GET['offset'], то это - не порченный параметр, можно не слешить. То же самое и с name.
Ну, и если ты не можешь достаточно достоверно определить источник параметра, то его надо слешить.
no subject
Date: 2006-02-01 04:37 pm (UTC)Это просто нелогично.
Мы должны составить синтаксически верный запрос, а уж откуда данные пришли - дело десятое.
Я бы тогда уж обозначил весь этот зоопарк, как "всё, что не было hardcoded программистом".
Но здесь, как я уже говорил, другая засада. среди этого "всего" попадаются вещи, которые НЕ НУЖНО прослешивать. Которым это не поможет!
SELECT * FROM table WHERE $field='$value'.
ыц?
пришло извне? пришло
обкавысить можно? НИЗЯ!
как грамотно объяснить юзеру, что первое должно быть результатом выбора из пре-кодед переменных, а второе - подлежит прослеш-обкавыч?
no subject
Date: 2006-02-01 04:56 pm (UTC)Объяснить просто. Имена полей, таблиц, инструкций (ключевые слова), знаки препинания в SQL не являются параметрами. Параметрами могут быть только данные. Например, если ты компилируешь запрос в prepare, ты не можешь оставить плейсхолдеры для полей - только для их значений. Вот и все. Все остальное - параметры (не уверен до конца насчет параметров LIMIT, т.к. это - нестандартная SQL-конструкция, но это частный случай).
Ну а насчет обкавычивания именно параметров, это тоже не очень хорошая идея. Если она в данное время работает на MySQL с любым типом данных, это не гарантирует, что оно будет работать где-то еще, даже, возможно, в будущих версиях MySQL. SQL, все же, строго типизированный язык сам по себе, и неявные преобразования типов в большинстве случаев - скорее прихоть разработчиков.
no subject
Date: 2006-02-01 05:11 pm (UTC)Про остальное я должен подумать.
То есть, у тебя получилось объяснение от противного - ты перечислил всё, что не данные. Остальное, следовательно, надо обрабатывать...
>Ну а насчет обкавычивания именно параметров, это тоже не очень хорошая идея.
то есть, ты предлагаешь мне поностью сменить текущую парадигму фака, в котором написано, что обкавычиваем/слешим мы всё подряд?
Хм.
Надо, блин, пааадумать...
no subject
Date: 2006-02-01 06:00 pm (UTC)пляшем не от категории "данные-не данные", а строго от типа.
если у нас ожидается инт - кастим в инт.
если ожидается строка - кавычим.
всё остальное - ...
опять закавыка получается с определением...
no subject
Date: 2006-02-02 11:09 am (UTC)1. Есть конструкции языка SQL - наименования объектов, ключевые слова, операторы. Эти нельзя ни кавычить, ни слешить, эти - как ёжики, с ними надо осторожно.
2. Все остальное - параметры (данные). По возможности нужно использовать механизм передачи параметров через плейсхолдеры, если это поддерживается базой. Тогда ничего слешить и кавычить не надо, об этом позаботится библиотека доступа к базе, в соответствие с ожидаемым типом параметра (она знает, какому типу принадлежит какой-то параметр, даже если ты сам этого не знаешь, т.к. у нее есть метаданные). Если такого механизма нет, то надо кавычить и слешить все параметры в расчете на то, что она (как MySQL, например) сама разберется с типами и сделает неявное приведение типа, если понадобится.
no subject
Date: 2006-02-01 10:56 am (UTC)no subject
Date: 2006-02-01 07:36 pm (UTC)http://ilia.ws/archives/103-mysql_real_escape_string-versus-Prepared-Statements.html
no subject
Date: 2006-02-02 11:15 am (UTC)no subject
Date: 2006-02-02 11:18 am (UTC)>Или Деррик до сих пор не знает, what the fuck is BOM? :))
вот зе фак из БОМ и при чем тут ОН?
no subject
Date: 2006-02-02 12:22 pm (UTC)А BOM - вот он какой. История вопроса: как-то в баги запостили, что PHP неправильно обрабатывает файлы в UTF8 (создаваемые в Unicode-enabled редакторах) и отправляет BOM на вывод, вследствие чего проблемы с headers already sent. После чего пришел DR и сказал - какого хрена PHP вообще должен иметь дело с чем-то, что не ASCII? What the fuck is BOM? Как дети.
no subject
Date: 2006-02-02 12:31 pm (UTC)я думаю, что не открою большого секрета, если скажу, что большинство функций PHP - это врапперы к функциям внешних библиотек.
это - тот самый случай.
низлежащая функция libmysqlclient обладает некоторыми недостатками, но к PHP это имеет очень косвенное отношение.
>как-то в баги запостили, что PHP неправильно обрабатывает файлы в UTF8
>(создаваемые в Unicode-enabled редакторах) и отправляет BOM на вывод, вследствие чего проблемы с headers already sent.
было, помню.
bogus однозначно.
>После чего пришел DR и сказал - какого хрена PHP вообще должен иметь дело с чем-то, что не ASCII?
>What the fuck is BOM? Как дети.
да всё просто: если ваш тупой редактор молча добавляет лишние символы в начало кода - это проблема редактора.
сегодня BOM, завтра BOOM, послезавтра BADABOOM, все это не проблемы интерпретатора.
жалуйтесь в Mikeysoft, что их Нотепад - кривой. пускай фиксят.
no subject
Date: 2006-02-02 12:40 pm (UTC)А про BOM - это не тупой редактор, это стандарт такой. UTF-кодированная строка может приехать и не от редактора.
И если PHP не в состоянии с этим разобраться, то он этот стандарт не поддерживает, вот о чем и речь. О чем спорить?
no subject
Date: 2006-02-02 12:52 pm (UTC)а addslashes() и не могла знать о юникоде, т.к. поддержка юникода - в PHP6.
>А про BOM - это не тупой редактор, это стандарт такой.
мм? у меня, например, ни один редактор не добавляет BOM.
хотя локаль юникодная. что я делаю не так?
плюс, насколько мне известно, Нотепад - единственный виндовый редактор, который добавляет BOM во все файлы, создатели всех остальных думали головой.
no subject
Date: 2006-02-02 01:03 pm (UTC)Кстати, известно когда будет ли возможность узнать имя класса изнутри статического вызова (типа get_class(self))? Ну и другие вкусности с разыменованием имени класса перед вызовом статического метода/переменной? Костыли писать замучался.
no subject
Date: 2006-02-02 01:10 pm (UTC)это статический вызов, неоткуда брать такую информацию.
>Ну и другие вкусности с разыменованием имени класса перед вызовом статического метода/переменной?
не понял.
$class::method(), что-ли?
используй Reflection API.
>Костыли писать замучался.
ну так пришли патч.
no subject
Date: 2006-02-02 01:56 pm (UTC)Ах, вот даже как. Супер.
А если self::method(), то откуда оно такую информацию берет? :)
> не понял.
> $class::method(), что-ли?
Да хоть $class::getAnythingBySomething($somethng)::method(). Какая разница?
Конечно, для методов у нас есть call_user_function, и вызвав ее положенное количество раз, мы что-нибудь поимеем.
$anything = call_user_func($class, 'getAnythingBySomething', $something);
$whatWeNeed = call_user_func($anything, 'method');
А как быть с членами класса?
> используй Reflection API.
Так ...
$prop = new ReflectionProperty($class, 'aProperty');
print $prop->getValue(new $class());
Это всё, конечно, гораздо удобнее и красивее, чем $class::method() и $class::$var. Не говоря уже о том, что:
(new ReflectionProperty($class, 'aProperty'))->getValue(new $class())
просто не работает,
а new $class кроме всего прочего вызывает еще и конструктор.
Ну, в-общем, очень удобный Reflection API, что и говорить.