Как стать автором
Обновить

О проблемах информационной безопасности и IT образования на примере HTML Academy

Время на прочтение17 мин
Количество просмотров22K
Всего голосов 58: ↑50 и ↓8+51
Комментарии154

Комментарии 154

Отчасти это объяснимо — РНР считается таким простачком, и каждый считает себя экспертом в этом языке

Рискну предположить, что на этом всё и базируется. "- Я с третьей версии пишу, я все знаю, не надо меня учить"

Да, это часто встречается. Причём, как говорится, "старую собаку научить новым трюкам" зачастую сложнее, чем совсем новичка. Вот у меня как раз недавно вышел разговор с одним из самых опытных наставников, который впервые столкнулся с тем, что начиная с последней версии, РНР начал сам выбрасывать исключения при работе с mysqli, не дожидаясь, пока это сделает программист. И в итоге вместо тёплого лампового print("Ошибка подключения: " . mysqli_connect_error()); выводится какой-то непонятный Stack trace!


И мне потребовалось довольно времени чтобы объяснить, что по сути это то же самое, только более информативное, и — главное — адаптивное сообщение об ошибке. Ключевая информация, которую оно доносит, остаётся той же самой — причина ошибки подключения. Меняется только формат, и плюс вывод ошибки становится не безусловным, а настраиваемым. Причём, благодаря тому, что выборс исключения останавливает выполнение текущего кода, весь этот ужас с print() уже не выполняется вовсе — то есть код становится правильным вопреки желанию программиста! Но вот сама непривычность такого поведения поначалу ставит в тупик. И сразу появляются идеи, "а давайте вернём всё назад, принудительно сбросим настройки на предыдущий вариант"...

И сразу появляются идеи, "а давайте вернём всё назад, принудительно сбросим настройки на предыдущий вариант"...

Потому что вариантов реально два:
- старый сайт работает на старом коде
- старый сайт со старым кодом умер

Варианта "все бросились переделывать старые сайты под новые заморочки авторов PHP" нет.

По мне так пусть лучше "старая собака" хорошо освоившая свои фокусы продолжает поддерживать нужный мне информационный ресурс, чем я лишусь доступа к нужной мне информации.

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

Я бросился. А также переписал внутрениие сервисы с silex на sf4, когда это стало актуально

Если делать все своеверенно, то проблем не составит.

У людей есть много других дел, кроме как соответствовать ожиданиям разработчиков PHP

Я бросился. А также переписал внутрениие сервисы с silex на sf4, когда это стало актуально

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

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

У людей есть много других дел, кроме как соответствовать ожиданиям разработчиков PHP

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

Не стоит говорить про то, в чем не уверены. У меня не так много времени, просто я заложил его в обновление и поддержку. Если требуется ремнот — это уже не работает, а обслуживание проивоздим регулярно.
Интересно, а вы машину или мотоцикл или сервер или еще что-то тоже обслуживаете также, когда окончательно сломается?
Как показывает реальность, полная сообщений об ошибках на сайтах — у мире много людей, находящих более интересные занятия.
Или также как и вы решают «работает — не трожь»? Не все могут себе позволить либо время, либо деньги, либо и то и то на обслуживание. Это не значит, что этого делать не надо. Изначальный вопрос-то вообще в другом, что некоторые не хотят изучать новое.

Можно делать медленно, и они не требуют много времени.

Давайте смоделируем ситуацию.

Вы когда-то сделали веб-сайт и наполнили его какой-то информацией.

А спустя время вам эта тема стала менее интересна и вы сайт подзабросили, но не убили.

Сейчас он просто есть и работает. Не знаю зачем он Вам, может жалко убить, а может вы на этом домене почту держите.

И в какой-то момент, Вы оказываетесь в ситуации, когда сайт перестал работать и там какая-то ошибка про устаревшую функцию.

Как Вы поступите и почему именно так?

Интересно, а вы машину или мотоцикл или сервер или еще что-то тоже обслуживаете также, когда окончательно сломается?

Это зависит от ситуации.

Что-то обслуживается по графику, а что-то живёт дополной неработоспособности и выбрасывается.

Автомобиль находится в первой группе.

Старые веб-сайты могут попасть во вторую.

Давайте смоделируем ситуацию

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

Автомобиль находится в первой группе.
Старые веб-сайты могут попасть во вторую

Соглашусь.

Кстати, вспомнил один момент, был к композере пакет у которого была совместимость с php7.2 и с 8.1, и он зависит от пакета с 8.1. При этом код написан под 8 версию и есть полифилы. Все приплыли, он как бы совместим со старой версией, но не установится. Если сделать форк и указать совместимость с 7.2, то можно ставить.

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

Ага, с одной стороны медали находятся люди рассуждающие о том как ловко они пилят форки на гитхабе, а с другой - человек десят лет назад сделавший веб-сайт с историей села Усть-Пиздюйское, куда залил какие-то фоточки, газетные вырезки и рассказы старожилов.

И если его веб-сайт умрёт из-за обновлений на хостинге, то он его чинить не будет, ибо уже другие интересы есть, да и не разберётся он в этих ваших конструкторах.

НЛО прилетело и опубликовало эту надпись здесь
Я писал не про ловкое создание форков

Это не значит, что этого делать не надо

Нет, как раз именно это и значит "не надо этого делать".

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

Прямо сейчас на хостинге крутится сайт со старым коммерческим движком. Давно не оплачен. Давно не обновляется. Я его админки по максимому закрыл http-авторизациями и он живёт.

Если он сломается из-за очередного обновления на хостинге, то я его просто удалю и всё.

Это не потому что я не хочу изучать новое - я этого нового изучаю столько, что многие с ума сойдут от объёма информации.

Я не хочу изучать ненужную мне хрень.

Как вы можете догадаться, МНЕ от этого хуже не станет и я просто спокойно вздохну,перестану оплачивать хостинг и отпущу домен.

Это исключительно вопрос взаимоотношений разработчиков PHP и людей зачем-то посещающий этот старый сайт.

Вот мы и пришли от обобщенного к частному. Вы не будете обновлять, я буду. Возможно вам этого и не надо, а вот, возьмем, Васю, у него бизнес ему и надо, он зовет опытного разраба, допустим Вовку, и тот ему говорит "- Да давай ща версию откатим и сойдет!".

у него бизнес ему и надо

А я хожу по интернету, по старым сайтам, которые люди сделали сколько-то лет назад про какие-то свои интересы, и вижу там сообщения deprecated функциях. А иногда error и контента нет.

Вам - интересно развлекаться копаясь в коде.

У Васи - бизнес.

"старые собаки" поднимают правую руку и опускают её с указанием направления, по которому отправляются пользователи их веб-сайта.

все бросились переделывать старые сайты под новые заморочки авторов PHP

Интересно, а вы машину или мотоцикл или сервер или еще что-то тоже обслуживаете также, когда окончательно сломается?

Обобщая вышенаписанное и образно говоря, Вам нет смысла ставить новые бампера только из за того, что они появились в продаже

Да, абсолютно незачем.

Вы об этом не знали?

Новые бампера это fn =>, можно обойтись и без них. А если что-то чуть серьезней — аналог отзывной компании

Если говорить об изменениях в языке, не поддерживающих обратную совместимость — то да, такая позиция существует, и одним из самых самых её горячих сторонников является Зеев Сураски, один из самых первых разработчиков языка. Поскольку его бизнес как раз и заключается в предоставлении услуг поддержки древних сайтов на РНР. И да, это вечная битва прогресса с обратной совместимостью. Здесь можно порекомендовать просто не обновляться. Да, у этого решения есть свои минусы, но стабильность работы в данном случае является приоритетом.

Здесь можно порекомендовать просто не обновляться.

Это проблематично, в условиях шаред-хостингов. :)

Ну, в данном случае речь идёт об учебном курсе, то есть никакого "рабочего сайта" у нас пока нет.


По поводу же рабочих сайтов — не забываем, что мы говорим об ошибке БД, то есть, в 99% случаев — о фатальной ошибке. То есть ситуации, когда сайт всё равно уже умер. Соответственно, умирает он и так и так, но данная настройка при этом улучшает ситуацию. Поставить display_errors=0, если оно ещё не стояло — это дело 1 минуты. И в итоге ошибки SQL перестанут выводиться пользователю. Добавить кастомный error handler — это ещё полчаса, и вместо корявого Ошибка подключения: Too many connections пользователю будет выводиться аккуратная страничка с извинениями и уверениями что "уже всё чиним!". И что самое приятное — без каких-либо правок кода!


Единственный случай, когда эта функциональность действительно поломает рабочий сайт — это для тех мест, где проверка if ($con == false) { ... использовалась не для того, чтобы тупо выплюнуть ошибку в пользователя, а для того чтобы как-то обработать нештатную ситуацию. Вот в таких местах if надо будет заменить на try..catch.

В данном случае, ветка ушла в тему "старых собак" и не_учебных ситуаций в виде "а давайте вернём всё назад, принудительно сбросим настройки на предыдущий вариант".

Добавить кастомный error handler — это ещё полчаса

Во первых, полчаса - это уже много.

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

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

И мы это уже видели на практике. Был момент, когда на старых сайтах массово посыпались сообщения о deprecated , а потом на хостингах появилась возможность включить php 5.x

"старые собаки" не горят желанием прыгать через обруч по полчаса на каждый каприз разработчиков PHP - они просто забивают болт на старые проекты и всё.

Угадайте, кому становится хуже от того, что пропадают веб-сайты с информацией?

Ну я всё-таки повторюсь — в данном конкретном случае ничего принципиально не меняется.


Во-первых, здесь речь идёт только об ошибках SQL — то есть ситуации, когда сайт и так лежит. Если всё работает, то новый функционал никак себя не проявляет. А если база лежит, то и при старом сайт всё равно не работал.


Но вот при желании сделать пользовательский экспириенс более позитивным — с новым функционалом будет проще.

Во-первых, здесь речь идёт только об ошибках SQL — то есть ситуации, когда сайт и так лежит.

Остаётся добавить, что база легла не сама, а из-за того, что функция mysql_*() больше не работает, и при этом её нельзя просто механически заменить на mysqli_*()

Эк вы что вспомнили! Это ж когда было. Лет 5 назад, или больше.


Но если вы хотите поговорить об этом, то во-первых, здесь лежит не БД, а РНР. Во-вторых, сайт не "ложится вдруг сам", а только в том случае, если его перенесли на другой сервер или по крайней мере обновили версию РНР на текущем. А это редко случается с сайтами, которые "просто поддерживаются".


А в-третьих, "просто механически заменить" — без проблем. Всего-то лишь надо в скрипт с коннектом к БД приинклюдить один файлик. И если кому-то хватило квалификации обновить версию РНР, то уж добавить один инклюд в код и подавно хватит.


Ну то есть я честно не вижу здесь проблемы. Если сайт "просто лежит", то и версия РНР у него "вдруг" не поменяется, а только волей конкретного человека. А если есть такой человек, то и подцепить средства обратной совместимости он сможет.

Ох, чую я сейчас устраиваю Вам экскурсию в реальный мир, который находится за границами тусовочки айтишников хвастающихся друг перед дружкой размером стэка :)

И если кому-то хватило квалификации обновить версию РНР, то уж добавить один инклюд в код и подавно хватит.

Версию PHP обновил сотрудник шаредхостинга.

А разве не клиент выбирает версию PHP в панели управления?

Сейчас может и да, хотя я не уверен что это у всех хостингов есть.

Но так было не всегда.

Полагаю, эта возможность появилась именно из-за того, что далеко не все люди стали переписывать свои веб-сайты под фантази разработчиков PHP.

Интересно, а сколько всего ушло в небытиё в тот период, когда этой возможности не было?

Я уже лет 10 не пользуюсь шаред хостингами, но даже в 2000-х годах помню, что любой приличный хостинг предлагал на выбор php ветки 4.x и 5.x.

фантази разработчиков PHP

Слишком толсто

Если вспоминать то что было 10 лет назад, то у меня даже цитаты есть, из уведомлений.

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

То есть, выбрать может и можно было, но это ничего не значило - решение оставалось за хостингом.

Если Вы захотите объяснить сторонним наблюдателям то зачем хостинги это сделали, то не забудьте добавить "эта цель стоила того, чтобы навсегда уничтожить некоторое количество веб-сайтов, вместе с содержащейся на них информацией".

Именно "уничтожить", потому что эти веб-сайты не сами сломались, а были сломаны посредством изменения настроек.

Ранее директива register_globals была включена только для поддержки старых версий CMS. После большинство клиентов произвели обновление, и необходимость в поддержке директивы отпала. Кроме того, ее включенное состояние снижает безопасность каждого конкретного сайта, использующего PHP скрипты.

Если после отключения register_globals Вы увидите, что сайт перестал работать, то добавьте в файле .htaccess строчку:

php_flag register_globals on

Если у вас не будет возможности сделать это самостоятельно, дайте ответ на это письмо.

После этого мы настоятельно рекомендуем произвести обновление кода PHP, чтобы сайт мог работать при выключенном register_globals.


Но вот при желании сделать пользовательский экспириенс более позитивным — с новым функционалом будет проще.

Желания нет.

Сайт просто поддерживается и если умрёт, то и чёрт с ним.

Ну так если хотите, чтоб "старая собака" исполняла свои фокусы, пусть она и живет в "старой будке" (читай, версии PHP). Зачем обновлять и ожидать старого поведения?

пусть она и живет в "старой будке" (читай, версии PHP)

Всеми конечностями ЗА.

Зачем обновлять и ожидать старого поведения?

Так я не обновлял - меня принудительно обновили, причём так, что могла сломаться система защиты.

И там не только Пыха, но и вся остальная ЛАМПа обновлялась с потерей обратной совместимости.

В связи с технической необходимостью на сервере где расположена Ваша площадка u*****, u***** будет произведено обновление версии web-сервера
Apache до 2.4 (текущая версия 2.2).

Работы будут проводиться в ночь с 04 на 05 мая 2015 года. Общее время недоступности сервисов может составить около 30 минут. IP-адреса сайтов изменяться не будут.

Важно заменить, что в новой версии полностью изменен способ описания правил в файле .htaccess для контроля доступа к разделам Ваших сайтов по IP клиента.

Далее будут рассмотрены наиболее распространенные примеры управления доступом для старой и новой версий.

=== Полный запрет доступа ===

Apache 2.2
Order deny,allow
Deny from all

Apache 2.4
Require all denied

Да уж. Ну тут могу вам только посочувствовать.

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

Типа прибежал новичок, показал код и сказал "хнык-хнык, не работает". Мастер закурил то что принёс новичок, закашлялся, сказал "близко к жопе рвёшь, салага" и рассказал как правильно.

А потом, мастер с удовлетворением наблюдает за тем, как новичок получает первую зарплату и приходит пропить её вместе с мастером, открывшим ему секреты мастерства.

Только вот проблема у меня не в том, что не работает мой код - там где мне надо, мой код работает.

Проблема у меня в том, что я перехожу по какой-нибудь старой ссылке, а там, в лучшем случае, сообщение о deprecated наверху страницы, а в худшем - сообщение о том, что этой функции больше нет и пустота.

И эта проблема не только у меня, а и у многих других людей, только эти люди не понимают на что именно они смотрят. Они не в курсе, из-за чего им не показывают информацию. Я в курсе, ибо сам из этой отрасли, а вот миряне не понимают что происходит.

Кстати, у моих визави по данному обсуждению эта проблема тоже есть, ведь гугл не показывает им в выдаче эти умершие сайты.

Обожаю этот анекдот :)


Но всё-таки, мне кажется вы немного смешиваете понятия. Исходно мы здесь говорили не о философской проблеме прогресс vs. стабильность (которая сама по себе невероятно интересная), и не про поддержку легаси. А, всё-таки, про обучение салаг тому, как делать с нуля.


То есть озвученная вами проблема конечно есть, и она очень серьёзная. Но она здесь не совсем в тему.


Но если вы хотите поговорить об этом, то я не считаю, что у РНР какая-то особая роль в процессе умирания старых серверов. Это ведь целый комплекс проблем — где-то сама железяка сдохла, где-то — как у вас, поменяли версию Апача. А сколько сайтов убил один GDPR.


Я вот в последнее время часто думаю о смерти. Вот задушит меня ковид — и что станет с моими сайтами? Хостинг через месяц отключится, а максимум через год и домен спамеры перекупят. И будет там "смотреть без регистрации и смс"… Вот это я понимаю, проблема. Не чета несчастной mysql_query.

К сожалению соглашусь. Сейчас есть пара новичков, которых пытаюсь чему-то научить, идет со скрипом. Стараюсь объяснять что и зачем, а не тупое заучивание.
Видел ситуацию и наоборот, когда попсовую технологию тащать везде, где можно и где нельзя без включения головы. Результат тоже плохой, только «с другой стороны»

Что это за самый опытный наставник, которого Stack trace ставит в тупик? Эдак слово "опытный" можно вконец обесценить, будет синоним слова "старый".

Ну, надо сказать что наставник говорил от лица студента. А я виноват, неверно расставил акценты. Речь, конечно же, не про stack trace. У нас с ним спор скорее вышел о том же, о чем мы как раз только что говорили здесь с muxa_ru — наставник сначала решил, что такое поведение критически поломает обратную совместимость, а я ему доказывал, что нет — принципиально поведение остаётся прежним, меняется только формат. А идея "вернуть всё назад" появилась потому, что иначе придется переписывать весь подход к обработке ошибок в учебнике. А это как раз и представляет проблему. Поэтому наставник и предложил, в качестве простого варианта, отменять эту новую настройку, заставляя mysqli работать по-старому.

Если учебник по 8.0, то и код запускать нужно на 8.0. В данном случае учебник обновлять не хотят, а код запускают на свежей версии - это очередной раз подтверждает низкое качество курсов.

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

Контекст глубже и сложнее. Вот вам вводные:

  • Этот курс для новичков, которые видят PHP в первый раз.

  • Объём курса ограничен.

  • И этот объём уже исчерпан текущими материалами.

  • Курс не единственный в линейке, за ним следуют продвинутые курсы.

    Учитывая вводные данные, можно сказать, что внутрь курса уже сложно добавить что-то объёмное.

Так а какие проблемы с добавлением исключений? Проблема в том, что для этого нужно затащить в курс всю концепцию ООП, потому что без этого нормально не рассказать про исключения их работу. Но концепция ООП и так разбирается в последующих курсах, и там же вводится новый принцип обработки ошибок — исключения.

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

И делать вывод о том, что "раз не затащили исключения в курс для новичков, то качество плохое" — неверно.

Но кто ж из разработчиков задумывается о таких вещах, как методика обучения.

Непойманное исключение — это всего лишь банальная фатальная ошибка. Которая ничем не отличается от любой другой ошибки, например, "Failed opening required file" (которая, кстати сказать, в шаблонизаторе подавляется, вопреки собственным же требованиям). И никакое ООП, чтобы просто прочитать сообщение об ошибке, здесь не нужно.


Если пользователь сделал опечатку в имени подключаемого файла, то он увидит


PHP Fatal error: Uncaught Error: Failed opening required 'bogus' (include_path='.;C:\php\pear')

А если в пароле для подключения к БД, то (в современном РНР, если ему не выкручивать руки)


Fatal error: Uncaught mysqli_sql_exception: Access denied for user 'user'@'localhost' (using password: YES)

Ну покажите мне здесь то самое Очень Принципиальное Отличие, которое не помешает пользователю разобраться в первом случае, и поставит его в тупик во втором?

И если у вас проблемы с объёмом курса, то я легко подскажу, где можно его подсократить. Например, вместо трёх глав, посвящённых отправке запросов в БД, сделать одну. Лучше, конечно, две — но в любом случае, убрав весь этот ужас про "значение в итоге преобразуется к безопасному виду" и "бекслеш с кавычкой сохранится в базе данных", вполне можно сэкономить.


И в процессе заодно внезапно обнаружить ответ на свой


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

И выяснить, что это, оказывается, не я такой революционер и ниспровергатель. А на курсе уже сейчас студенту "забивают голову" именно этим. А я предлагаю всего лишь сократить объём информации, сделав её более последовательной. Но главное тут конечно то, что студенты перестанут писать код с инъекциями.

На самом деле отличный ответ. Отличный в плане подтверждения слов автора поста о некомпетентности авторов курса по php на "HTML Academy". В тред пришел представитель HTML Academy и попытался привести аргументы против (на мой взгляд совершенно несостоятельные и нелогичные, чего только стоит фраза "а зачем забивать студенту голову тонкостями мегабезопасного составления строчек для баз данных на курсе начального уровня ") на что получил ответные аргументы и после этого как это принято говорить - банально слился.

Вы знаете, я не автор курса по пхп, а тут выражаю своё личное мнение. Имею я право на личное отношение к какому-то человеку?

Что касается сообщения выше, оно исключительно для автора поста. Дело в том, что все его предложения методически несостоятельны, а мы себе такие вещи позволить не можем. А тон и стиль его общения не позволяет вести продуктивную дискуссию. При этом видно, что в техническом плане уровень автора достаточно высок.

Что касается вашего вопроса про "а зачем забивать студенту голову тонкостями мегабезопасного составления строчек для баз данных на курсе начального уровня". То собственно, в чём проблема. Наша задача подготовить для рынка джунов, которые будут писать вменяемый код. В конечном счёте, после прохождения всех курсов, они будут писать код с использованием фреймворков и библиотек, то есть проблем с безопасностью их кода не будет. И при этом у них будет достаточное понимание и база, чтобы углубляться в профессиональном мастерстве в нужном им направлении, хоть в вопросе безопасности, хоть в вопросе производительности и так далее.

Проблема с джунами ведь какая? Чтобы трудоустроиться они должны давать какой-то результат бизнесу, то есть уметь достаточно быстро решать определённый класс задач с использованием определённого набора инструментов. И никакой бизнес не будет требовать от джуна глубоких познаний в безопасности. Так чем наш подход по подготовке прикладных специалистов плох?

Мой акцент был про совпадение версий, а не про исключения. Исключения новичок в любом случае увидит, они там везде. Давать глубокую концепцию исключений в самом первом курсе действительно не надо, вы правы.

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

Кстати, вы отредактировали исходный комментарий? Там вроде было про исключения. Контекст обсуждения потерялся просто.

Я понял, в чём проблема. Судя по всему, вы имеете очень отдалённое представление о программе курса. Сейчас я вам объясню. Дело в том, что "самый базовый синтаксис языка, простейшие конструкции типа циклов, условий функциий, а также приёмы решения задач с использованием этих конструкций" — это первые три пункта программы обучения. А всего их на базовом курсе — девять. В три раза больше. Причём сложность, как раз после этих первых трёх базовых разделов, взлетает экспоненциально. И следующие три раздела сложнее всего остального курса на порядок.


И хотя в последних трёх главах сложность выходит на плато, сами темы, которые в них поднимаются, несколько противоречат вашим представлениям о курсе. В частности, в последней главе появляются и объектный синтаксис, и автозагрузка классов, и пакетный менеджер Composer — хотя вы неоднократно здесь писали, что ООП студенты начинают осваивать только на следующих уровнях.


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

А причем тут PHP?
Все эти "трюки" за исключением заливки шелла можно провернуть и на python и на go. Вернее, приложение, которое будет подвержено этим уязвимостям.
А джунов на питоне сейчас едва ли не больше чем джунов на PHP в силу его популярности.
Т.е. если мы берем сырой пользовательский ввод и прямо пихаем его в неподготовленный SQL запрос, то одному богу известно чего туда реально может прилететь. Аналогично с XSS.
Есть золотое правило: "Мы никогда не доверяем пользовательскому вводу". Вот этому и надо учить.

А причем тут PHP?

Контекст?
add
«Мы никогда не доверяем пользовательскому вводу»

Где границы пользовательского ввода? Вы этими словами повторяете ошибки Академии

Согласен, формулировка "пользовательский ввод" вводит в заблуждение. Правильнее будет сказать "любые сторонние данные". Т.е. вообще любой инпут, который поступает в приложение.

вообще любой инпут, который поступает в приложение

Снова мимо. Эти данные могут попасть в БД (например с (очень грубо) инъекцией: "Василий '; drop table users where '1'='1"), вы подготовили через prepare/bind, и у вас в базе так и сохранилось. А затем так как эти данные уже в БД, вы им заранее доверяете, и в каком-то месте, где вам нужно вставить лог с именем этого юзера - вы вставляете без фильтрации (т.к. данные получены с сервера БД, а не с юзера), и оп!

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

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

А затем так как эти данные уже в БД

… то они по-прежнему являются "внешними" для приложения. Внутренние для приложения данные — это, разве что, какая-нибудь константа, магическое число, кусок скрипта, или что-то подобное — то, что можно явно увидеть прямо в коду. То есть, всё, что поступает в приложения снаружи его бинарников — это внешнее, включая и содержимое базы данных. Проще всего такой подход защитить тем, что база данных — это, всё-таки, отдельное приложение по отношению к appserver'у, и нахождение её на той же физической машине — не более чем случайность, и так бывает не всегда даже если с базой данных по текущему дизайну общается только один appserver.
(да, здесь тоже бывают исключения, и в бинарнике тоже можно подменить константы на другие, но это уже будет свой собственный, особый уровень паранойи, и от него уже не экранированием защищаются).

НЛО прилетело и опубликовало эту надпись здесь

IO String, полученный из подключения к БД - это пользовательский ввод? Если да - то почему? Если нет - то как его отличить от IO String, полученного из запроса?

НЛО прилетело и опубликовало эту надпись здесь

Ну вот мне кажется, что понятие "очистки" тоже лишнее. Оно недетерминировано, у нас нет чёткого определения, что такое "очищенные" данные. То есть это какое-то абстрактное понятие, которое непонятно, как применять на практике. Я всегда стараюсь оперировать материальными понятиями, не допускающим двоякого толкования. Вот подготовленные выражения — это как раз практическая рекомендация, которой не важны никакие свойства данных, такие как "очистка". Причём даже "подготовленные выражения" я стараюсь заменять на "знаки подстановки", потому что находится ненулевое количество людей, выполняющих свой запрос через подготовленное выражение — но без подстановок, и считает, что всё делает правильно! Чем меньше различных толкований у термина, тем меньше вероятность ошибки.


Но главное — это понятие и не нужно. Зачем нам вообще нужна какая-то очистка? Не в плане валидации, которая относится к бизнес-логике, а в контексте безопасности? Ведь в любом случае мы должны уметь работать с любыми данными, и "чистыми", и "нечистыми". Ну и зачем тогда умножать сущности?


Я считаю, что надо не заглубляться в тему пользовательского ввода, вводя какие-то дополнительные определения, а наоборот — просто отсечь её. Потому в контексте безопасности она нам и не нужна, а только мешает. А если кого-то интересуют нюансы пользовательского ввода, то сначала я бы выяснил контекст.

НЛО прилетело и опубликовало эту надпись здесь

Нет, не имеет. Вот как раз чуть ниже psycho-coder очень правильную вещь пишет: самый нижний слой, который, собственно, и отправляет запрос в базу, вообще ничего не знает про природу данных. Про их источник, содержимое, опасность, чистоту — и так далее.


Мне кажется, что вы здесь следуете традиционному заблуждению, путая два понятия — валидацию и форматирование. И имеете в виду первое. И при этом абсолютно правы: модель или домен — логическая единица приложения — в своём полном праве требовать провалидированные данные для себя. Но мы здесь говорим о другом — об уровне физического взаимодействия с БД. И об огромной, принципиальной разнице между двумя этими понятиями:


  • валидация, диктуемая бизнес-логикой — это недетерминированная область. она может пропускать кавычки, а может не пропускать. Может пропускать HTML, а может не пропускать. Может применяться, а может не применяться — полная свобода творчества. Которая диктуется только бизнес-логикой
  • форматирование же, в свою очередь — это строго детерминированная и обязательная функция, которая применяется всегда. И зависит только от пункта назначения, контекста, в котором данные будут использованы. Ну согласитесь же, что слой для работы с БД, который не пропускает несчастную кавычку — как вы предлагаете — это какая-то бессмыслица! Да вот прямо в этой дискуссии половины комментариев бы не было, если Хабр, следуя вашей рекомендации, не пропускал "всякие ', чтобы SQL injection'ы не делать". Не говоря уже про всякую XSS, которая вообще никакого отношения к базе данных не имеет.

Я думаю, что мы говорим об одном и том же, и путаница только в терминологии. Мне кажется, что говоря про "очищенные" данные, вы имеете в виду валидацию. И здесь я с вами на 100% согласен. Вот только защита, и от инъекций, и от XSS, не является обязанностью валидации. Для каких-то задач валидация может не пропускать кавычку, а для каких-то может. Это не тот рубеж, где мы защищаемся от инъекций.


А вот уровень прямого взаимодействия контекстом использования данных — будь то БД или рендер HTML — как раз и является тем местом, где мы "защищаемся", но точнее будет сказать — форматируем данные перед использованием. Для БД это будут подстановки, а для HTML — ну, я в статье подробно описал, повторяться не буду. И главное — этому слою пофиг на валидацию. Он схавает любые данные.


Ведь это гениальный принцип, он позволяет значительно упростить как архитектуру приложения, так и сам код — когда каждый слой занимается своим делом и ему не нужно знать ничего про природу обрабатываемых данных! А если добавлять в него какие-то проверки и хотелки, то мы очень быстро обрастём таким количеством исключений, то как та многоножка — скоро не сможем сделать ни шагу, не споткнувшись о собственные многочисленные конечности.

НЛО прилетело и опубликовало эту надпись здесь
Кавычки — это особенность движка хранения данных, который их, скажем так, не любит.

Извините, то это полная ЧУШЬ. Движок хранения данных, который "не любит" какие-то данные — это бессмыслица. И таких в природе не существует.


Кавычки "не любит" не движок хранения, а транспорт — SQL запрос. И нигде, кроме этого запроса, ваши пресловутые кавычки не играют вообще никакой роли. И любая БД их совершенно спокойно хранит. И именно поэтому мы озабачиваемся кавычками на уровне выполнения запроса, и больше нигде. И поэтому любую санитизацию должна выполнять функция, выполняющая запрос.


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


А теперь вы пишете какую-нибудь социалочку

Ради бога. Я нигде не говорил, что валидация не должна выкидывать лишнее. Я написал прямо противоположное — что слой валидации вполне может не пропускать HTML. И слою вывода будет нечего заменять. Но то, что защита в любом случае должна стоять — это аксиома. Выводим в HTML? Форматируем. Аргументацию я приводил в статье, не буду повторяться. Миллиону просмотров поможет кэширование, оно всё равно тут понадобится.

НЛО прилетело и опубликовало эту надпись здесь

Как это — недостаточно? Мне кажется, что вы уже просто троллите. Если это функция, которая предназначена для выполнения запросов конкретно в эту БД, то именно она и знает, как это делать. А вот на автора запроса-то как раз полагаться и нельзя. Его дело — предоставить сам запрос, и данные для него. Всё остальное сделает функция. Вы ещё скажите, что автор запроса должен знать тонкости физического протокола, по которому запрос отправляется в БД.

НЛО прилетело и опубликовало эту надпись здесь

Не надо. Я как раз тут ниже приводил код, который именно это и делает.


Наличие или отсутствие кавычек во входящих данных нас не интересует от слова "совсем".

НЛО прилетело и опубликовало эту надпись здесь

Неправда. Покажите, какая переменная в этом коде имеет выдуманный вами тип "Sanitized"?


Смотрите, если вернуться к вашей идее про "очищенные данные", то в ней нет никакой логики. Вы рассуждаете, исходя из предположения, что "в БД лежат уже очищенные данные", то есть с "не сырыми" кавычками. То есть вы изначально исходили из идеи хранения видоизменённых данных. А она не выдерживает никакой критики. Данные в БД хранятся как есть. То есть ваша исходная идея про "очищенные данные" превращается в тыкву. Вам бы уже принять тот факт, что данные всегда хранятся как есть, и идея про обеспечение безопасности путём хранения "очищенных" была не очень удачной.

НЛО прилетело и опубликовало эту надпись здесь

Ваша ошибка в том, что вы пытаетесь решить не ту проблему.

Ограничения, вводимые типом, имеют смысл, когда тип - это подмножество String. Например, валидный email.

При построении же sql-запроса решается иная задача - формирование, собственно, SQL-запроса с соблюдением синтаксиса SQL. Достаточно посмотреть внутренний парсер и структуру AST в исходниках Postgresql, чтобы понять, что строковый литерал - один из сотни возможных кейсов. И задача в том, чтобы корректно SQL-запрос, а "безопасность" является лишь побочным эффектом. А уж сформированный запрос, да, вполне себе может иметь тип SQLStatement. Да, там внутри может быть где-то дерево, и где-то внутри может оказаться SQLStringLiteral, но сам по себе этот подтип не имеет никакого смысла, поскольку он имеет смысл только в конкретном дереве, а не для конкатенации с произвольным String!

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

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

Все то же самое относится и к генерации HTML и вообще чего угодно. По сути это задача кодогенерации

НЛО прилетело и опубликовало эту надпись здесь

Сложно придумать что-то, что бы не ложилось на типы, разве что конкретная система типов может оказаться недостаточно мощной :-) Главное - правильно выбрать набор типов под конкретную задачу.
Вот по ссылке всё разумно. А некий тип Sanitized - вообще не к месту тут.

Я правильно понимаю, что по ссылке — это что-то вроде флюентного квери-билдера?

НЛО прилетело и опубликовало эту надпись здесь

А как этот тип использовать?

В случае, если разрешается конкатенация с произвольным String, очевидно, теряется весь смысл. А если только в рамках AST, там, где имеется ввиду строковый литерал - ну так в итоге и получим то, что по той вашей ссылке на haskell-либу.

Давайте немного по-фантазируем:
Начитавшийсь умных книг мы строим архитектуру приложения похожую на DDD. При такой архитектуре у нас получается довольно много абстракций и сервисов. Это всё между собой слабо связано, разделение по слоям, напрвяления зависимостей и все как завещал Дядюшка Боб. В таком случае некоторый сервис может просто не понимать откуда у него на входе данные. Это тестовые данные, это из БД, это из cli или черт еще знает откуда. Связанность слабая и код также «не знает» очищены они или нет. Даже если и будет некоторый флаг отмечающий это, как определить что он установлен верно?
НЛО прилетело и опубликовало эту надпись здесь

Самое смешное, что в РНР раньше был такой механизм. Данные действительно поступали в функцию для работы с БД уже с понтом "sanitized". Назывался "волшебные кавычки". Это одно из самых позорных пятен в биографии РНР, с выпиливания которого можно начинать отсчёт превращения языка из гадкого утёнка в пусть не прекрасного — но вполне себе юзабельного лебедя. Процесса, который в итоге привел к посттравматическому синдрому у камрада muxa_ru (:

НЛО прилетело и опубликовало эту надпись здесь

посттравматическому синдрому

Обожаю наблюдать за тем, как люди накачанные эмоциями "какое счастье" воспринимают спокойствие за эмоции "какой ужас".

Хотя, нет смысла отрицать, у меня действительно есть эмоции по этому поводу - удовлетворение от того, что мир оказывается именно таким как я его вижу.

люди накачанные эмоциями "какое счастье"

По-английски эти люди называются Straw man ;)

А рассуждения о посттравматическом синдроме у собеседника, по русски называется "переход на личность"

Это была беззлобная шутка, если что :)

Так у меня тоже.

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

Связность, сервисы и прочие DDD скорее о том, как не терять продуктивности с ростом масштабов проекта, когда над ним работает много команд, и добавляются разные источники требований, а не для того чтобы сделать отдельный кусок кода более понятным

Вопрос вы, действительно, не поняли
Вы прочитали какие-то книги, под влиянием которых написали кучу кода, где ничего не понятно, но зато всё очень сервисно и абстрактно, и спрашиваете, что теперь с этим делать? Ну, не знаю, попробуйте не обмазываться абстракциями и сервисами в таком количестве

Прочитал какие-то книги и не пишу код, где ничего не понятно. Лично мне книги приносят знания, которые я не знал или помогают их структурировать. И книги это не инструкция к применению.
Зачем ему это не знать?

Как раз ему и не надо знать это.

Упрощая, функции, принимающие ввод от пользователя (будь то CLI, фронтенд или ещё что), дают вам обычный сырой невалидированный тип строки String...

Записали в базу Sanitized, потом выводим в html еще раз Sanitized, что произодет с данными? Если нам надо обработать сырые данные для другой задачи, а они уже Sanitized, тогда что делать, преобразовывать обратно? Это все добавляет сложности — теже абстракции только в профиль.
К тому же, одними строгими типами проблема не решается. Если бы это решалось, в C# не добавляли бы var и auto в плюсах.
Автор поста пытается донести мысль, что данные считаем недоверенными всегда, кроме случая, когда нам это надо, и вот тут санитайзер как раз нужен будет. Другими словами «Запрещено все, кроме того что явно разрешено».

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

Тогда почему, когда я написал слабосвязный сервис, еще до знакомства с умными книгами, то сделал с некоторым кол-вом абстракций и интерфейсов, которые и регламентрировали работу сервиса. При этом результат получился такой, что можно выкинуть ненужное, или добавить нужное без проблем. Другой разработчик только добавляет класс со своей логикой и указывает где его выполнять. Если бездумно применять технологии, то конечно ничего хорошего не получится. Погружение в проблему и в тероию важная вещь в обучении и разработке. Симптомное решение задач приносит говнокод.
НЛО прилетело и опубликовало эту надпись здесь
Почему? Функция, которая непосредственно отправляет данные базе данных, должна про это знать. Точно так же, как она должна знать, как сериализовать эти данные, и так далее

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

Если санитизация идемпотентна, то ничего

Хорошо

Да.

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

Только ошибки в этих абстракциях ловит компилятор

Как и тайп-хинтинг с интерфейсами.

Во-вторых, ой, расскажите, пожалуйста, как же auto меняет дело? :]

Можно не указывать тип :]

Наверное, вы очень хороший дизайнер. Когда какое-нибудь место, где я буду работать, будет искать людей, я вас первым делом зареферю

Да нет, средней руки бэк.
НЛО прилетело и опубликовало эту надпись здесь
И какое отношение это имеет к строгости типов?

Заранее можно не знать тип данных. Могу ошибаться, на плюсах писал только курсовые когда учился.
НЛО прилетело и опубликовало эту надпись здесь
auto позволяет его не писать, только и всего.

Давайте поясню что имел ввиду. Это грубый аналог
$n = 41 + 1;

Олсо, интересно, что бы вы сказали, глядя на какой-нибудь код на хаскеле или чём позабористее, учитывая, что там аннотации типов зачастую только у объявлений топ-левел-функций

Думаю я бы сломал себе мозг. Из функциональных только lisp (clojure) трогал и то не дальше учебника.
НЛО прилетело и опубликовало эту надпись здесь
К тому же, одними строгими типами проблема не решается. Если бы это решалось, в C# не добавляли бы var и auto в плюсах

Вы не совсем верно представляете себе, что такое, как минимум, var; про auto утверждать не буду. var позволяет компилятору вывести тип переменной без явного указания разработчиком, он никакого отношения к строгости не имеет.
Заранее можно не знать тип данных

Кому знать? Компилятору его как раз обязательно для вывода.
Кому знать? Компилятору его как раз обязательно для вывода.

Разработчику.
Имел ввиду, что полностью строго типизированную систему либо невозможно сделать, либо очень сложно. Да и не нужна она, строгость типов это еще один инструмент решения задач. Иногда он нужен иногда нет
НЛО прилетело и опубликовало эту надпись здесь

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


Вообще, это всё ненужная софистика, которой я и предлагаю избегать. Само понятие "пользовательский ввод" в контексте защиты является лишним и даже вредным. Важно не то, откуда получены данные (из БД, из запроса) — а то, куда они идут.

Примеры с БД выше и ниже уже привели. Как отличить одно от другого? А если админ ошибся или опчетался, то это инфа сохранится в БД и может что-то сломать, а она ведь не «пользовательского ввода»

Согласен. Я об этом упомянул вскользь, но вы правы, надо сделать меньше упор на РНР, и больше на универсальность этих правил. К примеру, на Тостере я постоянно вижу вопросы — да чего уж греха таить — и ответы, где в Питоне в cursor.execute() передаётся запрос с уже интерполированными в него переменными! Я посмотрю, как можно подредактировать статью, чтобы она была полезнее для более широкого круга читателей.


Только одна маленькая поправка: всё-таки, "пользовательский ввод" — это такая отравленная формулировка, её лучше избегать. На Stack Overflow есть очень известный вопрос, где чувак спрашивал — "а является ли пользовательским вводом содержимое тега <select>? Его ведь не пользователь вводит руками, а сервер формирует!" Популярность этого вопроса говорит о том, что у многих разработчиков отсутствует чёткое понимание, что является пользовательским вводом, а что — нет. А данные из БД — они ещё пользовательские, или ещё нет? А если у нас даже в 100% не в пользовательском вводе будет кавычка или другой спецсимвол?


Поэтому, если мы говорим о данных, то я предлагаю вообще не употреблять такое понятие, как "пользовательский ввод". А просто принять по умолчанию, что у нас все данные недоверенные, любым данным нельзя доверять. Такой подход сразу сделает работу с данными универсальным и сэкономит нам кучу времени и нервов. И волос, на голове и в разных других местах (:

На PHP всё так же принято перемежать PHP-код вставками на HTML? Шаблонизаторы так и не прижились?

P.S. Серьёзно писал на PHP лет 10 назад.

В современном php как правило не принято. Однако есть рудименты в виде Wordpress, Joomla, modx и прочего, куда это вотнуть трудно (где-то лечге, где-то сложнее). Все кто пишет на Laravel, Symfony и др. фреймах, там уже есть шаблонизаторы и их наличие не оспаривается

Наоборот, очень даже прижились, нет ни одного профессионального сайта, где не использовался бы специальный шаблонизатор — в основном это Twig или Blade, реже Smarty, Ещё реже — какие-нибудь диковины типа Blitz. Вот кстати даже интересно узнать у коллег из Badoo, используется ли он до сих пор? :)


Сам курс РНР в Академии в этом отношении построен очень правильно — он подводит студента к идее шаблонизаторов, но пока — на чистом РНР. Шаблон для вывода отделяется от бизнес-логики и кладётся в отдельный РНР файл. И вот в нём уже как раз HTML код перемежается вставками РНР, причём используются только базовые команды, чтобы только обеспечить логику отображения. При этом используется примитивная функция-шаблонизатор, в которую передаётся имя файла шаблона и массив с данными для него. То сделать следующий шаг к настоящему шаблонизатору будет совсем нетрудно. А уже в них никакого РНР нет* (не будем показывать пальцем в сторону Blade), а используются только команды самого шаблонизатора.

Я, наверное, что то не понимаю, но при динамической типизации число никакой sql иньекции не несёт, а строка будет экранирована?

"Функция mysqli_real_escape_string(), как следует из её названия, работает только со строками, и применять её для числовых значений бесполезно чуть более чем полностью."

Тут надо уточнить, что в данном случае имеется в виду под динамической типизацией?


Строгая типизация — да, предотвращает инъекцию через числовые параметры, и некоторые студенты этим пользуются, технически инъекция у них не проходит:


function getInfo(int $id) {
    $sql = "SELECT * FROM table WHERE id = ". $id;
}

Но у своих студентов я такой код не принимаю, расценивая его как читинг. Это вносит разнобой в защиту от инъекций, и в конечном итоге в этом бардаке какая-нибудь гадость да пролезет. Я добиваюсь единого подхода к исполнению запросов, когда никакие посторонние детали на порядок выполнения запроса не влияют. Я уже сталкивался с ситуацией, когда вместо числового параметра переходили к цифробуквенному, меняли при этом типизацию, а вот про SQL — забывали.


А в примере, приведённом в статье, вообще никакой типизации нет — ни строгой, ни динамической. Мы тупо берем входной параметр, экранируем в нём несуществующие кавычки, и подставляем прямо в запрос.


Так что прощу уточнить, что вы имели в виду.

Приведите, пожалуйста, пример id который содержит sql иньекцию, которую указанный выше код пропускает. Я не понимаю, почему указанный пример нельзя считать нормальным (не хорошим, но приемлемым) вариантом защиты.

А вы вообще читали, что написано в сообщении на которое отвечаете?

Я уже сталкивался с ситуацией, когда вместо числового параметра переходили к цифробуквенному, меняли при этом типизацию, а вот про SQL — забывали.

Во-первых, я уже ответил на ваш вопрос:


технически инъекция у них не проходит

Во-вторых, речь не о коде, а о подходе. Приведенный пример можно считать безопасным, но нельзя считать нормальным. Мне часто приходится вступать в подобные дискуссии на Stack Overflow, и всегда приходится отдельно оговариваться — "приведённый вами вырожденный и изолированный пример является безопасным. но подход, который вы при этом используете, таковым не является".


Вот же, я пишу: "Это вносит разнобой в защиту от инъекций". У семи нянек — дитя без глазу, говорит нам народная пословица. И здесь как раз такой случай. Когда мы используем целый зоопарк различных методик защиты, то повышается вероятность пропустить инъекцию. Защита от инъекций должна происходить в момент выполнения, и нигде больше. Взятый целиком, приведённый выше код не содержит инъекции. Но если кто-то скопипастит из него только код выполнения запроса, то тут же получит инъекцию. Если захочет поменять тип обрабатываемой переменной, то тоже получит инъекцию. Если же изначально код выполнения запроса будет корректным, безотносительно любых внешних по отношению к нему проверок, то во всех этих случаях он и останется безопасным. Обеспечение безопасности должно быть атомарным, строго по месту. А не быть развешенным по всем приложению, как подштанники на бельевой верёвке.

Во-первых, про строгую типизацию вы сами придумали, ее не было в исходном запросе. Тут и без типизации проблем с безопасностью и кодом как бы нет.

Во-вторых, ваш подход к обеспечению безопасности - это вкусовщина. Если код не пропускает инъекции, то характер этого кода (для бизнеса) имеет достаточно мало значения.

В-третьих, вы сами, скорее всего (это не понятно из вашего профиля и материала, здесь могу ошибиться) не являетесь методистом, который бы разработал курс "Основы PHP для новичков", но при этом хаяте большое количество других материалов. Попробуйте с нуля объяснить основы веб-разработки для хотя бы 100 человек. Которые ничего сложнее Excel не видели. Через год вернетесь и расскажите про ощущения.

Лично я считаю приведенный пример, практически, идеальным для студентов на том уровне, на котором студенты находятся (основы есть, лишнего нет, есть задел на будущее для углубления навыков). И категорически поддерживаю образовательную программу, которая смогла обеспечить такой подход обучения

Тут и без типизации проблем с безопасностью и кодом как бы нет.

Стоп, как это нет? Убираем типизацию


function getInfo($id) {
    $sql = "SELECT * FROM table WHERE id = ". $id;
    // ну дальше понятное дело выполнение запроса
}

и получаем инъекцию!

Проверьте, пожалуйста, отличия вашего кода и кода в статье. Там ещё вызов функции есть

Я не понимаю, к чему вы клоните, но инъекция здесь будет в любом случае, с функцией, или без:


function getInfo($con, $id) {
    $id = mysqli_real_escape_string($con, $id);
    $query = "select * from lots where id = ".$id;
    $result = mysqli_query($con, $query);
}
getInfo($con, $_GET['id']);

— и мы тут получим ту же самую инъекцию, которая подробно разбирается в статье.


Хотя постойте. Я кажется понял, о чём вы. Вы же ведь про функцию mysqli_real_escape_string? Дело в том что строки, о которых говорится в статье, относятся к SQL, а не к РНР. То есть типизация в РНР нас здесь вообще никак не касается. Вся речь о том, работаем ли мы со строковым литералом в SQL, или нет. Это моя недоработка, я поправлю. Смотрите:


SELECT * FROM table WHERE id='1'

— здесь у нас строка, '1' — это строковый литерал. Вот с ними-то как раз и работает mysqli_real_escape_string.


SELECT * FROM table WHERE id=1

— а тут у нас числовой SQL литерал, а не строка. И применять к нему mysqli_real_escape_string абсолютно бессмысленно, независимо от того, какой тип имеет исходная переменная в РНР.


Если же дело не в этом, то очень прошу объяснить суть своих претензий подробнее, желательно с примерами.

Есть еще вариант:

$sql = "SELECT * FROM table WHERE id = '". mysqli_real_escape_string($conn,$id)."'";

mysql выполнит, причем еще и заботливо сам оставит числовое значение из id (если в таблице поле числовое) и выкинет остальное.

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

Этот вариант будет работать, о чем, кстати, прямо говорится в статье: " Если бы переменная $id была взята в кавычки, то да — этот код был бы безопасным."


Но применять, а тем более — учить ему всё-таки не следует. И в первую очередь потому что он льёт воду на мельницу того самого заблуждения, про волшебную палочку. Слишком много разработчиков верили, и до сих пор верят, что mysqli_real_escape_string "делает данные безопасными". И не надо поддерживать их в этом убеждении.


Не говоря уже о том, что если вместо WHERE id у нас будет LIMIT, то возможность поставить вокруг переменной кавычки превратится в тыкву. И опять репу чесать, искать какие-то обходы? поймите, это все уже обсуждалось миллионы раз. Да, как отдельный изолированный пример оно работает. Как универсальный подход к защите — специалисты смотрят на этот код в ужасе, столько реальных проблем он принёс.

Кстати, да, динамическая типизация может быть важной частью обсуждаемой культуры - "фигач всё в кавычках, а LAMP сам узнает числа".

Потом пересаживаешься на что-то другое, там лишние кавычки в SQL-запрос ставить нельзя, а привычки экранировать - нет :(

Ваша статья была бы в тему, если бы курс назывался "Информационная безопасность при разработке на PHP". Но курс называется "PHP. Профессиональная веб-разработка".

Если посмотрите на страницу курса, то становится понятно, что этот курс для новичков. Основная его цель — научить нулевиков решать типовые задачи веб-разработки с помощью PHP. Так чтобы они это делали на хорошем профессиональном уровне и могли развиваться дальше.

Можно было бы сказать, что вопросы безопасности тоже должны здесь рассматриваться в полном объёме. Но это не так. Проблема в том, что курс ограничен по объёму материалов и по времени. И за это ограниченное время нужно успеть дать новичку очень много концепций, с которыми он ни разу не сталкивался, от шаблонизации, до работы с базами данных.

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

Можно ли поправить материалы таким образом, чтобы по умолчанию там давались самые безопасные приёмы? В принципе, можно. Но какой от этого толк, если не объяснять, почему нужно использовать именно эти приёмы, а не какие-то другие, которыми кишат все примеры в интернете? Если студент не будет знать про все тонкости, связанные с безопасностью тех или иных конструкций и их альтернатив, то и осознанно про безопасность думать не будет.

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

Спасибо за ваш комментарий. Я довольно часто слышу такое мнение, но категорически с ним не согласен. Но хорошо, что вы его высказали. И тем не менее, извините, но ваши аргументы не выдерживают никакой критики.


Я не предлагаю "рассматривать вопросы безопасности в полном объёме". я всего лишь предлагаю давать на курсе корректную информацию. Какая проблема написать, "при выводе данных в HTML любые данные в обязательном порядке экранируются, если явно не указано обратное, как это принято во всех современных шаблонизаторах"? Какой такой запредельно неподъёмный объём информации в ней содержится? При том что корректные и непротиворечивые формулировки как раз-таки упростят восприятие материала. То же самое касается SQL инъекций. Вместо чехарды методов даётся только один.


Я нигде не предлагаю как-то "погружаться" в вопросы безопасности. Я всего лишь предлагаю сразу обучать правильным подходам, и не давать заведомо ложной информации. И всё. Это не добавляет никакой нагрузки. А наборот — её уменьшает. Вместо 100500 способов защиты от инъекций даётся только один. Где здесь повышенная нагрузка?


Но какой от этого толк, если не объяснять

Извините, но это совсем ни в какие ворота не лезет. По-вашему, лучше показывать как сделать плохо, и тоже ничего не объяснять? Но это же бессмыслица. Если мы в любом случае не объясняем, то всё равно ведь лучше показать правильный подход? И в том и в другом случае студент механически заучивает какие-то движения, но во втором случае он будет хотя бы заучивать правильные. Я никак не вижу, как отсутствие объяснений мешает сразу хотя бы показывать правильные подходы. Я считаю, что такой риторикой можно только оправдывать некачественные учебные материалы, но никак не отсутствие качественных.


Только насчёт осознанности применения полученных знаний вы правы. Но во-первых, любознательный студент и так все выяснит у наставника, а во-вторых, повторюсь — при прочих равных — отсутствии осознанности — всё же лучше если выпускник будет применять правильные подходы, а не устаревшую кривизну. Хотя бы в самых базовых вопросах.

Давайте перейдём на шажок дальше.

Вот есть начальный курс, цель которого — показать то, как решаются типовые задачи на чистом php. Думаю, тут вы со мной согласитесь, что понимание того, как задачи решаются без фреймворков для новичка важно? Одна из таких задач — составление запросов в базу. Студент должен понимать, что по сути запрос — это строчка, которую он и сам при желании может собрать. Причём собрать любым способом.

Дальше за этим курсом следует ещё несколько курсов, в которых студенты уже учатся пользоваться различными библиотеками и фреймворками. То есть решают привычные задачи, которые они встречали на первом курсе, уже на более высоком уровне. Быстрее, эффективнее и безопаснее.

И в конце профессии выходит студент, который знает, как задачи решаются на самом "низовом" уровне (на чистом php). Но при этом такие задачи он уже решает с помощью фреймворков и библиотек. Ну ведь по факту в поточной или продуктовой разработке все пишут на фреймворках.

И вот главный вопрос: а зачем забивать студенту голову тонкостями мегабезопасного составления строчек для баз данных на курсе начального уровня, если он всё равно в итоге будет для этого пользоваться инструментами, зашитыми во фреймворки? Типа, чтобы он такой грамотный был и если когда-то в жизни придётся писать на чистом пхп, он бы написал безопасно? Чтобы самолюбие своё потешить? Или всё-таки можно эти тонкости опустить и дать человеку тот объём тех знаний, которые ему нунжы для решения задач, чтобы его на работу взяли?



Вопрос "зачем забивать студенту голову тонкостями мегабезопасного составления строчек для баз данных" следует адресовать не мне. А автору курса. У которого целая глава в учебнике посвящена (впрочем, как всегда некачественно и бессистемно) именно этому вопросу. Но при этом учебник не даёт ответа на вопрос, а как, собственно, делать-то, какой метод выбрать? И в итоге мы получаем разброд и шатание, плачевные результаты которых можно видеть в работах студентов.


Если использовать вашу же (весьма спорную) риторику, то зачем давать студенту три разных способа? Это-то как раз и увеличит на него ту нагрузку, о которой вы так печётесь.


И поймите, "мегабезопасным" такое составление запросов является только в ваших, извините, замшелых представлениях. Во всем мире это уже стандарт, подход по умолчанию. В том-то и дело, что если человека учить в стиле "это играть, это не играть, тут селёдку заворачиваем", "делай так, нет на самом деле не так, но пока можешь так" — то да — у него действительно голова кругом пойдёт. А если сразу показать один нормальный пример, то он сразу и будет делать нормально, и никаких проблем со "сложностью" у него не возникнет.

За сим предпочту эту "приятную" дискуссию с вами завершить. Слишком я замшелый для вас, видимо. Не хочу вас позорить тем, что приходится мои спорные аргументы опровергать.

Опозорили вы здесь пока что только сами себя.

Эээ… Я только сейчас догадался заглянуть к вам в профиль. Это многое объясняет. В любом случае — спасибо за дискуссию.

Обычная ублюдочная контора для выкачивания бабла из лохов на голубом глазу, что тут рассуждать.

Удивительно, как они сопротивляются улучшению курса, которое никак не повлияет на «выкачивания бабла».

Но какой от этого толк, если не объяснять

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

Ещё раз. Тут цель примера не в том, чтобы показать, как "ручками собирать мегабезопасные запросы". Цель проще — показать принцип, "запрос — это строка, её можно собрать ручками, при этом нужно задумываться о безопасности".

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

Ну и если мы говорим про крутого спеца, который знает тонкости безопасности, и осознанно их применяет, то я за таких специалистов. Просто это рост до такого уровня должен происходить не на этапе "нулевик-джун", а на этапе после трудоустройства, во время профессионального развития. Там человек сможет вспомнить наше "запрос можно и ручками собрать, но надо задумываться о безопасности", и пойдёт копать вглубь. Ведь на это будут и время, и ресурсы, и интерес.

Зачем устраивать тайну на ровном месте?
Цель проще — показать принцип, «запрос — это строка

Все придумано до нас — консоль субд.
Но курс называется "PHP. Профессиональная веб-разработка".



Основная его цель — научить нулевиков решать типовые задачи веб-разработки с помощью PHP.

Так вы сами же и противоречите себе. Переименуйте в "PHP: Основы для джунов". Студент, который не знает таких элементарных вещей — не может являться профессионалом. Любителем максимум.

@FanatPHP, если данные в запрос передаем через знаки подстановки, то как писать классическую "фильтрацию строк по произвольному набору фильтров", не используя конструкций типа `WHERE ($1 IS NULL OR <fieldName> = $1) AND ($2 IS NULL OR ...)`?
А то эта конструкция больно уж плохо оптимизируется планировщиком СУБД (по крайней мере, в случае с PostgreSQL).

Спасибо за хороший вопрос! Насчёт оптимизации ничего не могу сказать, но в использовании подстановок тут нет ничего сложного — просто надо собирать попадающие в запрос переменные в отдельный массив. В самом простом, "сермяжном" варианте это будет выглядеть например так:


$conditions = [];
$parameters = [];

if (!empty($_GET['name']))
{
    $conditions[] = 'name LIKE ?';
    $parameters[] = '%'.$_GET['name']."%";
}
if (!empty($_GET['sex']))
{
    $conditions[] = 'sex = ?';
    $parameters[] = $_GET['sex'];
}
if (!empty($_GET['car']))
{
    $conditions[] = 'car != ?';
    $parameters[] = $_GET['car'];
}
if (!empty($_GET['date_start']) && !empty($_GET['date_end']))
{
    $conditions[] = 'date BETWEEN ? AND ?';
    $parameters[] = $_GET['date_start'];
    $parameters[] = $_GET['date_end'];
}

$sql = "SELECT * FROM users";
if ($conditions)
{
    $sql .= " WHERE ".implode(" AND ", $conditions);
}
$sql .= " LIMIT ?,?";
$parameters[] = $offset;
$parameters[] = $limit;

$stmt = $mysqli->prepare($sql);
$stmt->bind_param(str_repeat("s", count($parameters)), ...$parameters);
$stmt->execute();
$data = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);

В более продвинутом варианте можно использовать Query Builder, будет покрасивше, но в целом подход тот же самый, набор if-ов:


if ($request->name)
{
    $query->andWere("name", "like",  "%" . $request->name . "%");
}
// etc...

Спасибо за развернутый ответ!

Раз зашла тема про php, то воспользуюсь случаем для ряда вопросов) Вообще интересны мнения всех людей, и фанатов php, и не фанатов тоже)

1) В коммерческой разработке программист на php это в большинстве случаев фуллстек ?
Если нет, то это разработка апи или используются родные шаблонизаторы фреймворков ?

2) Правильно ли я понимаю, что php в веб-разработке имеет куда больший спрос среди работодателей, чем тот же python ?

3) Заменит ли хайповый Go php или удобство php-шных фреймворков не даст этому случиться ?

Спасибо за интересные вопросы.


1) Зависит от профиля конторы. Если это студия, которая делает сайты на заказ — то обычно да, это фуллстек. Но если это "команда одного продукта" — екоммерс, какой-то SaaS, внутрикорпоративная система — то чаще всего есть разделение специализаций, и РНР — это чисто бэк.


2) На данный момент — да. В качестве конкурента в области веб-разработки я бы скорее рассматривал Ноду. У Питона есть один недостаток в этом плане — нет дворовых команд. Футбол ведь силён в тех странах, где гоняют в каждом дворе, где растёт своя смена. А там где сразу покупают топовых игроков, толку не выходит. Так и здесь: в отличие от РНР, в питоне нет возможности учить одновременно азы и программирования, и веб-разработки. Если питон и веб — то Джанго, а это совсем другая ступенька, с улицы на неё не зайдёшь. Но с другой стороны, в силу неуклонно снижающейся популярности РНР (не связанной с объективными качествами языка) и растущей — питона, то можно ожидать эффекта перевернувшегося айсберга.


3) Не заменит однозначно, у него есть своя узкая ниша, которую он занимает прочно, но за пределы которой он выйдет не сильно. Тут я опять же смотрел бы не на Го, а на Питон с Нодой.

1. Нет, но обычно основы фронтенда знать нужно. Из личного опыта — на работе не лезу во фронт, но могу подсказать начинающему коллеге, что пихать блочные элементы в инлайновые не стОит. Ну или могу компонент написать для какого-нибудь Knockout JS, но это далеко не полноценная разработка SPA, например.

2. Не знаю, никогда не интересовался, что там у Python. Как php-разработчик никогда (за 12 лет) не испытывал проблем с работой и зарплатой.

3. Go в веб-разработке скорее занимает нишу микросервисов. Если приложение имеет другую архитектуру — не думаю, что на Go будут писать весь бекенд. Лично я на Go писал тулзы для синхронизации данных между дев-стейдж-продакшеном, а сами приложения были на php.

Меня всегда очень интересовала довольно грустная ситуация с языком РНР

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

На мой взгляд в мире php ничего не изменится. Какие средние зарплаты - такой и средний уровень кода.

Мне кажется, это какое-то заблуждение. Вот только что Суперджоб считал, что программисты PHP в среднем зарабатывают в Москве 250 тыс. Чем плоха такая зарплата? Ну и насчет кругозора я бы поспорил. РНР — это как футбол. Да, большинство гоняет во дворе с воротами из двух кирпичей. Но есть и сильные региональные команды, и высшая лига. И мощная экосистема. Давайте вы сначала предметно покритикуете авторов Temporal за отсутствие кругозора, а потом мы продолжим?

Вот только что Суперджоб считал, что программисты PHP в среднем зарабатывают в Москве 250 тыс. Чем плоха такая зарплата? 

Без контекста, какие по мнению Суперджоб зарплаты в других языках - это ни о чем.

Вот вам пример другой статистики:

Но есть и сильные региональные команды, и высшая лига

Высшая лига есть в любом языке.

Не вижу проблем, на сеньорском графике разница 10%. Если кто-то настолько жадный, что выбирает технологию не по душе, а по зарплате — то ради бога, можно и поскакать. Но как по мне, "самый простой путь дальнейшего роста зарплаты" — это какой-то wishful thinking.

Я вот никогда не понимал такого подхода — сначала заведомо учиться
делать неправильно, а потом переучиваться. Какой в этом смысл?

Я могу объяснить. Может быть конкретно в этом случае это неприменимо, но суть подхода такова: нельзя научить водить формулу один человека, который только пришел в автошколу. Если человек испытывает проблемы с синтаксисом языка - проблемы безопасности как влетели в его голову, так и вылетят.

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

В данном случае база - нужно экранировать входные данные перед тем, как отправлять их в базу. Как это делать - это детали. Первое же ревью на реальном проекте под присмотром матёрого разраба научит вчерашнего студента, что он сделал не так.

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

Ну тут скорее другая аналогия. Нет смысла в автошколе преподавать вождение кобылы. Под тем предлогом, что "первое же ревью на реальном проекте под присмотром матёрого разраба научит вчерашнего студента" водить автомобиль. Ну устарел подход с экранированием, уже минимум лет 10, как устарел. Преподавать его просто глупо. Ну поймите же, что подготовленные выражения — это не бином Ньютона, не "формула один". Это банальнейший механизм. Тем более, что он всё равно даётся в курсе — но только ещё больше запутывая студента.


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


Сейчас тема составления SQL запросов состоит из трёх глав: сначала студенту объясняют, как поместить переменную в запрос вообще без всякой обработки — хотя это полная бессмыслица, работа со строками рассматривается совсем в другом разделе. Затем рассказывается, как отдельно защищать числа и строки. И потом даются подготовленные выражения. Но при этом не даётся никакой итоговой рекомендации — что использовать. Если следовать вашей логике, то это и есть "вдавание в детали" и усложнение. Куда проще сразу показать подготовленные выражения, одним абзацем оговорившись, что всякое экранирование признано негодными, устаревшим, и не рекомендуется к использованию.


Вообще, мне не хотелось бы сводить проблему к одним только инъекциям. Исходная проблема ведь шире — сам подход к продукту. Собственно, подходов, условно говоря, два — либо сделать и забыть, либо постоянно дорабатывать продукт по итогам реальной эксплуатации. И мне, как программисту — просто дико видеть первый. Потому что я всеми печёнками знаю, что не бывает идеала, что любой программный продукт — это не изваяние из камня, а живой организм. Который растёт, развивается. Неудачные решения отмирают, новые появляются. Существующие улучшаются. Почему нельзя применять этот же подход к учебному курсу-то? Почему, проявляя упорство, достойное лучшего применения, доказывать, что существующие материалы представляют собой идеал? Почему настолько свирепо сопротивляться улучшениям, придумывая какие-то витиеватые аналогии в оправдание?


В конце концов, в учебнике куча другой ереси, не такой фатальной. Тот же несчастный явскрипт, который не даёт выполнить задание. Почему его-то не убирают? Как к этой проблеме притянуть за уши "формулу один"? Подскажите.

Но главное — правильные подходы не являются усложнением. Правильная обработка ошибок проще неправильной — не надо писать лишний код. Правильная работа с SQL проще неправильной — не надо учить 10 методов, достаточно выучить один. Правильная защита от XSS проще неправильной — следовать правилу "экранируем ВСЁ" легче, чем сидеть, размышлять над каждой переменной. Это всё не "формула один". Это совершенно элементарные вещи. Сложными они начинают казаться только тем, кто ими не пользовался. Кто, как правильно было замечено в комментарии выше, научился говнокодить 15 лет назад, и всё новое воспринимает со скрипом. А если давать человеку эти вещи с нуля, то он и будет их воспринимать естественно, как сами собой разумеющиеся.

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

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

Такой код выбивается из названия курса и никак не подходит под профессиональную разработку, но откровенно говоря, если бы подставленный айдишник привели к типу инт, было бы сильно лучше? Да инъекции бы не было, но у начинающего программиста и так в голове плохо все складывается, а тут еще приведение типов.

Во-первых, мои замечания простираются несколько шире, чем сами уязвимости. Основная моя претензия здесь — к инфоцыганству.
Во-вторых, вы даже не видите иронии в прямой параллели с мультиком, скрин из которого стоит в КПДВ — ваш "фреймворк с надстройками" — это те самые старательные, но туповатые "Двое из ларца", которые за Вовку "даже пальцы загибать будут". Посмотрите мультик, если не видели. Там хорошо показано, что будет, если использовать мощный и полезный инструмент, не понимая смысла своих действий, по принципу "и так сойдёт!".


В третьих, по поводу приведения к int. Я как раз и пишу в статье, что приведение — это тоже не вариант. И у своих студентов я не принимаю такое решение. По причинам, которые я также подробно описал.

Я вас понял, а вот вы меня нет. Смотрите, я в свое время учился в университете на специальности "Прикладная информатика в экономике", так вот девочки из моей группы на лабах брали "купленные" исходники из блокнота перепечатывали текст в IDE, на замечание профессора - что же вы делаете? можно же копировать вставить, они отвечали что так надежнее, после чего он пошел молча сел за свой стол и в его глазах я увидел боль, это был 4й курс технического вуза.

Я могу очень ошибаться, но мне кажется что примерно такое студенты и приходят на курсы, не хочу никого задеть или обидеть. И вот таким студентам в тот самый момент когда PHP начинает получать данные из параметров, собирать из них SQL запрос, отправлять это на сервер БД и потом еще надо распарсить ответ и вывести, вы туда еще хотите нагрузить информацию о том что есть страшные SQL инъекции, так код писать нельзя, надо писать вот так, но и так не надо, надо только знать как а в большинстве своем будете работать с ORM, но знать надо потому что если вы будете писать сложный запрос требующий оптимизации, то сможете дров наломать или не сможете его профессионально оформить. Тут я тоже хочу привести картинку с мемом "они же всего лишь дети".

Этот момент может подтолкнуть учеников дропнуть обучение, особенно если у них наставник будет не такой болеющий душой за правое дело, но в теории, с вашими изменениями и с учителями разделяющими ваши взгляды, на много больше шансов вырастить настоящего специалиста. А вообще у вас и продавцов курсов разные задачи, вы хотите стать учителем хорошему специалисту(что похвально), а продавцы курсов хотят чтобы их курс прошел до конца и никто не запросил возврата средств.

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

Спасибо. Да, теперь ваша позиция гораздо яснее.


Сразу скажу, что вы исходите из неверных посылок. Вы сейчас описываете не мои предложения, а то, что СЕЙЧАС есть в учебнике, причем именно в таком виде: "вы туда еще хотите нагрузить информацию о том что есть страшные SQL инъекции, так код писать нельзя, надо писать вот так, но и так не надо". Там есть отдельная глава о том, как писать переменные в запрос без всякой обработки. Ещё одна — отдельная — глава про "страшные SQL инъекции", в которой рассказывается про кастинг и искейпинг. И ещё одна глава, про "надо писать вот так" АКА подготовленные выражения.


А я как раз и предлагаю весь этот шалтай-болтай сократить, оставив только один вариант.


Судя по всему, у многих читающих сложилось ощущение, что курс вообще не даёт никаких основ безопасности, а я — такой мятежный — агитирую за то чтобы их добавить. В который раз повторю, что это не так. Даются, даются основы безопасности на курсе. По всем тем вопросам, которые я так подробно разобрал. И мне кажется, что это должно быть ясно из текста — что я разбираю существующие материалы. Моё предложение заключается в не в том, чтобы нагрузить бедных студентов дополнительной ношей. А в том чтобы существующая ноша во-первых, не была мусором, а во-вторых — была упрощена. То есть вы все почему-то критикуете меня за то, что сами же в итоге и предлагаете — за упрощение.

У них скорее всего есть какой-то текущий KPI по курсам, возможно этот курс показал себя удовлетворительно в отличии от других, поэтому трогать не хотят, а может они просто ленивы. Вообще проработав несколько лет в сфере A/B тестов, могу сказать, что довольно часто улучшения, сказываются в худшую сторону, поэтому их можно понять. Удачи вам =)

В данном случае речь идёт не о каких-то абстрактных "улучшениях" или "A/B тестах" с непредсказуемым результатом. А о банальном исправлении багов.

Все верно пишете. Очень важна плавность и последовательность материалов. Причём последовательность даже важнее. Если мы даём на первом курсе базовые конструкции языка, то и закрепляем эти конструкции решением типовых задач, в которых эти же конструкции используются. Да, код студента на первом курсе будет не идеальным, не будет полностью соответствовать подходам, которые используют мидлы и сеньоры, пишущие на последней версии языка. Но ведь это всего лишь промежуточный результат. А нам (и вам, если вы нанимаете) важен конечный результат, который достигается после прохождения всех курсов. И там уже ученик знает, что такое ООП, использует продвинутые возможности языка и инструменты.

А что касается учебника, то да, все материалы не идеальны, все материалы могут постепенно устаревать. Но эти вещи некритичны для итогового результата. Наша задача — выпустить толкового джуна, который сможет дальше профессионально расти. И если у него будут какие-то пробелы в глубоких вопросах безопасности, это нормально, на то он и джун. Просто здесь эти некритичные проблемы почему-то чрезмерно раздуты.

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


Вот честно, я не понимаю, какой смысл так упорно называть чёрное белым? В учебнике нет целой отдельной главы "Безопасность в шаблонах"? Есть. То есть попытка дать информацию по этой теме делается? Делается. Конечный результат? В 80% взятых наугад студенческих работ XSS присутствует в полный рост. Является ли эта проблема критичной? Внезапно — нет. Если практически поголовно студенты не в состоянии применить на практике даваемый им материал, то "это нормально". This is fine! :)

Я сам немного подрабатываю наставником на курсах PHP уровень 1/2, о которых вы пишите.

Не могу не согласиться с вашими замечаниями, с одной стороны. Сам требую в обязательном порядке использовать prepared statement или явное приведение к int в случае `$id = (int) $_GET['id'];` и подобных.

С другой стороны, на курсе "Уровень 2" (громко названным "Архитектура сложных веб-приложений", а фактически знакомящего студентов с основами использования фреймворка Yii2, эти проблемы уже исчезают по большей части.

Задача курса, на мой взгляд, познакомить студентов с основными принципами написания кода вообще, многие из них не имеют в целом алгоритмического мышления, какой-то базы, чтобы просто понять какие действия нужно совершить, чтобы из А получить Б, грузить их дополнительно принципами безопасности при построении веб-приложения на учебном проекте, имхо, не нужно. Это как в школе, достаточно сказать "нельзя делить на 0", а уже потом спустя пару лет объяснить почему и когда на самом деле можно и что из этого получится (предел или неопределенность и т.п.)

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

Различные тонкости они быстро узнают после пары-тройки код-ревью от старшего разработчика после того, как устроятся стажером-junior'ом в какой-нибудь аутсорс-компании, или в той же HTML Academy пройдут все ступени обучения (уровень 1, 2, 3, а ещё желательно акселлератор), или самостоятельно, при наличии наставника в будущем.

Послушайте, ну почитайте хотя бы последние два комментария первого уровня над вашим. Они ровно об этом же. Я опять должен повторять всё то же самое. Ну где у меня написано, что студентов надо "грузить дополнительно"? Нигде я этого не говорил. Зачем мне это опять, в который раз предъявлять? Давайте я тоже, в который раз, попытаюсь донести свою простую мысль:


  • во-первых, я нигде не предлагаю никакого усложнения. Я предлагаю ровно то же самое, что есть сейчас — показывать "действия, которые нужно совершить, чтобы из А получить Б". Но только показывать правильные действия, а не ту ересь, которая сейчас. Что с этим предложением не так? Где здесь эти ваши "дополнительные" действия-то?
  • во-вторых, я предлагаю не усложнить, а упростить материал. Сделать его непротиворечивым, логичным, более коротким и — как следствие — более простым для понимания. Сейчас отправке запросов в БД посвящено три главы в учебнике. А я предлагаю оставить одну. Ну объясните мне ради бога, где вы все видите в этом усложнение-то?

Я не знаю, специально вы передёргиваете или у вас так "случайно" получается, но эти ваши реплики выглядят так, как будто на курсе вообще не даются основы безопасности, чтобы не травмировать бедных студентов, а я заставляю эту информацию добавлять. Не надо, пожалуйста, так делать. Потому что это выглядит прямым подлогом. Разумеется, даже на этом, "профессиональном" курсе даются основы безопасности. Что про XSS, что про инъекции, что про валидацию форм. Потому что без них курс превратится совсем в мусор.


Ну и напоследок, я не понимаю, как вы все не видите этой логической ловушки, когда хором за своим основателем повторяете "ачотакова? ну и пусть сейчас учат ересь, на следующем потоке переучатся". Это что вообще? Как это может служить оправданием нежелания исправлять очевидные косяки? Почему вместо выдумывания этих нелепых оправданий "потом переучатся" нельзя просто взять и исправить?


Кроме безопасности в учебнике есть и куча другого бреда. Что вы придумаете, чтобы его оправдать? "Ну потом в мануале сам посмотрит, разберётся со временем"? А зачем тогда этот учебник-то? Ну пусть сразу в мануал и смотрит. Тем более что там постоянно работают над улучшениями, принимают пулл-реквесты.

Как то давно проходил данный курс, с автором статьи полностью согласен! И хочу выразить уважение, за то что подняли такую тему.

Хочется надеяться, что курс измениться к лучшему.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории