Comments 93
UFO just landed and posted this here
Знаете, как это случается? Везде проверяли, а здесь забыли. Просто взяли новенького, а он ещё плохо знаком с кодом.
-25
> Просто взяли новенького, а он ещё плохо знаком с кодом.
А что за конторы, в которых новенького сажают на финансы?
Огласите список — спасёте множество людей от раскрытия персональных данных.
И, да, +1 голос в оправдание инкрементальных айдишников: не виновны.
А что за конторы, в которых новенького сажают на финансы?
Огласите список — спасёте множество людей от раскрытия персональных данных.
И, да, +1 голос в оправдание инкрементальных айдишников: не виновны.
+45
Code review, тем более на таких важных участках кода, еще никто не отменял.
+11
Имею стойкое мнение, что «кто-то рано или поздно забудет проверить права» — архитектурная ошибка системы. Решается встраиванием обязательного шага проверки доступа на уровне объекта сразу после получения этого объекта. Интерфейс к данным у нас унифицирован, вот прямо в него и встраиваем логику безопасности. В итоге имеем всю логику защиты в одном месте, логику приложения — в другом месте. И люди, которые пишут логику приложения, просто не смогут влезть в логику безопасности и что-то там сломать. К сожалению, по моему личному опыту, такие вещи замечает и придумывает архитектор системы, а никак не программисты, которые её делают. А нанимать архитекторов в этой роли для enterprise-разработки компании не хотят. В итоге имеем повсеместные костыли, антипаттерны и оверинженернг. Что и приводит к вышеописанной ситуации.
+13
>> Решается встраиванием обязательного шага проверки доступа на уровне объекта сразу после получения этого объекта
Что у вас понимается под объектом? Модель? Если так, то это неверно. Модель не может знать, кто к нему имеет доступ. Безопасность — функция контроллера.
Что у вас понимается под объектом? Модель? Если так, то это неверно. Модель не может знать, кто к нему имеет доступ. Безопасность — функция контроллера.
0
Одноранговый MVC для таких вещей — недостаточно широкий подход, в том и дело. С точки зрения логики приложения данные получаются из модели, но и сама модель в свою очередь реализует MVC или другой подход, в который можно встроить контроль доступа без проблем. У нас принято называть такую схему «конвейер». Вход одной подсистемы это выход другой подсистемы. Каждая подсистема исполняет свою роль и не более того.
В данном случае конвейер начинается с интерфейса к данным, после этого проходит проверка доступа, после этого вывод пользователю. Хитрость в том, чтобы не давать делать пути в обход конвейера.
В данном случае конвейер начинается с интерфейса к данным, после этого проходит проверка доступа, после этого вывод пользователю. Хитрость в том, чтобы не давать делать пути в обход конвейера.
+1
Кстати на 2-х из этих сайтов проверка id была, но не везде
0
UFO just landed and posted this here
Сессия, очевидно.
+8
UFO just landed and posted this here
Не морочьте голову. Для определения сессии куки не обязательны, а отправить ссылку на страницу «спасибо за заказ» Вам наврядли понадобится.
+1
UFO just landed and posted this here
А по поводу ссылки на сделанный заказ, зря вы так, бывает удобно, например, при букинге номера в отеле отправить ссылку своим друзьям с данными брони
Всегда можно сделать такую страничку не привязанную к конкретному заказу, т.е. что-то вроде страницы-конструктора, где на вход подаются все данные, необходимые для ее отображения.
site/booking?hotel_id=5&room=34&guests=3&sum=5000
+2
вместо куки можно использовать local или sessionStorage
+1
А еще есть такая штука как тесты. Помогает!!!
+1
+100500!
Единственная причина, почему инкрементальные айдишники могут не использоваться явно — это скрыть реальное количество пользователей/счетов/заявок и т.п. Других причин просто нет, RBAC вам в помощь.
P.S.: ну и, само-собой, в русле autoincrement и mySQL могут быть и другие проблемы, но это не имеет отношения к тому, про что статья.
Единственная причина, почему инкрементальные айдишники могут не использоваться явно — это скрыть реальное количество пользователей/счетов/заявок и т.п. Других причин просто нет, RBAC вам в помощь.
P.S.: ну и, само-собой, в русле autoincrement и mySQL могут быть и другие проблемы, но это не имеет отношения к тому, про что статья.
0
Не вижу проблемы в этом, просто нормальные программисты проверяют права доступа к данным под этим ID у текущей учетки пользователя.
+23
Рано или поздно кто-то забудет проверить права.
-8
Как будто не нужно проверять права для ID'шников без последовательной генерации.
+16
А это свидетельство лапшеархетиктуры. Программист при реализации метода на сервере вообще не должен думать о правах. Всё должно быть проверено выше и автоматически.
+4
UFO just landed and posted this here
Выше, это до вызова соотв. метода.
На роутах, в базовом контроллере — от архитектуры зависит, но смысл как раз в том. что сначала проверка прав, затем — вызов метода.
На роутах, в базовом контроллере — от архитектуры зависит, но смысл как раз в том. что сначала проверка прав, затем — вызов метода.
+5
Как вы проверите вызов метода типа showRecord(recordId) на принадлежность пользователю, если запись из базы вы ещё не прочитали?
0
Не позову showRecord(recordId), а позову метод getDocumentInfo(uid, docId).
0
Опять же, от архитектуры зависит.
Я в базовом контроллере смогу проверить более глобальные вещи, например, имеет ли пользователь доступ к всей части сайта (авторизировался ли он), имеет ли права на просмотр записей (например если у него нет записей или он залогинился как редактор, который к данным записям вообще не должен доступ иметь).
Но да, вы правы, проверить принадлежит ли запись конкретному пользователю без выборки соотв. записи не получится.
Я в базовом контроллере смогу проверить более глобальные вещи, например, имеет ли пользователь доступ к всей части сайта (авторизировался ли он), имеет ли права на просмотр записей (например если у него нет записей или он залогинился как редактор, который к данным записям вообще не должен доступ иметь).
Но да, вы правы, проверить принадлежит ли запись конкретному пользователю без выборки соотв. записи не получится.
0
Выше — это выше по стеку вызовов. Как-то так:
+16
В общем случае это невозможно, когда дело касается доступа не на уровне таблицы или столбца (в терминологии РСУБД), а конкретных строк. Чтобы узнать есть ли у пользователя право доступа к той или иной записи нужно прочитать эту запись и узнать принадлежит ли она пользователю. Есть, конечно, варианты, но они ниже метода, на уровне системы хранения данных, а не выше.
+1
Я не думаю, что это прямо ошибки программистов, очень часто рабочий процесс поставлен так, что хороший программист работает быстро, а плохой медленно. Заботе же о безопасности и престиже компании внимания практически не уделяется.
Совсем недавно писал в один крупный российский интернет магазин, что у них купоны с автоикриментом, уже 2 месяца прошло, ничего не меняли.
Совсем недавно писал в один крупный российский интернет магазин, что у них купоны с автоикриментом, уже 2 месяца прошло, ничего не меняли.
+3
Можно вторым параметром захэшить ID…
Кстати, немного сбило столку предложение:
Ведь вы не можете защититься от ошибок программистов, а код, который построен на использовании инкрементальных идентификаторов, прийдется постоянно контролировать
Кстати, немного сбило столку предложение:
Ведь вы не можете защититься от ошибок программистов, а код, который построен на использовании инкрементальных идентификаторов, прийдется постоянно контролировать
-3
Я имел ввиду, что даже если есть проверка доступа по ID, её могут забыть заюзать, и нужен постоянный кодревью на такие ошибки
0
Вообще, моя идея была в том, чтобы в простом примере (без ролей, прав, рефереров, ip), была возможность простого отсева запросов, и предложенный вариант включал в себя 2 параметра: сам ID, и хэш от id.string, таким образом, не прибегая к большим правкам (срочно?), попытки перебора id становятся бесмысленными, т.к. нет возможности подобрать верный хэш.
+1
Я по инкрементальным айдишникам обычно оцениваю оборот магазинов :) Вообще, это достаточно ценная бизнес информация даже при закрытых вопросах с безопасностью и не стоит ее так явно выставлять наружу.
+25
UFO just landed and posted this here
Продиктуйте, пожалуйста, номер заказа по телефону
+10
Открываю почту, одно из первых сообщений:
Не вижу ничего криминального. Да и это они перестраховываются, реально достаточно шестизнака и перегенерирования в случае фиксирования коллизии.
Номер заказа типа A9GDM5 — сложно?
Your order FO3743C95A14 has been updated by elizza
Не вижу ничего криминального. Да и это они перестраховываются, реально достаточно шестизнака и перегенерирования в случае фиксирования коллизии.
Номер заказа типа A9GDM5 — сложно?
+2
*Подумалось*
Можно даже поизвращаться с человеко-запоминаемыми идентификаторами типа «HeeQui», «JooShu».
Ну, чтобы смешнее было.
Можно даже поизвращаться с человеко-запоминаемыми идентификаторами типа «HeeQui», «JooShu».
Ну, чтобы смешнее было.
+2
Угу, а потом кому-то из клиентов сгенерируется нецензурный идентификатор, и он раструбит на весь интернет, какой хамский у вас магазин.
0
Может быть еще веселее.
На корпоративном блогохостинге MS пару лет назад был забавный инцидент — работник-китаец никак не мог запостить анонс продукта в блог своей собственной команды.
Как выяснилось в результате разбора полетов, на хостинге был список нецензурных слов, который — поскольку блоги там на самых разных языках — покрывал все эти языки скопом. Включая всевозможные транслит-варианты.
Имя у китайца было — Hui (очень часто встречающееся среди китайцев, кстати)…
На корпоративном блогохостинге MS пару лет назад был забавный инцидент — работник-китаец никак не мог запостить анонс продукта в блог своей собственной команды.
Как выяснилось в результате разбора полетов, на хостинге был список нецензурных слов, который — поскольку блоги там на самых разных языках — покрывал все эти языки скопом. Включая всевозможные транслит-варианты.
Имя у китайца было — Hui (очень часто встречающееся среди китайцев, кстати)…
+4
Вообще, сложно…
А как их вообще генерировать?
Достаточно ли шестизнака?
Не будет в конце периода стабильного таймаута при проверке коллизий/перегенерировании.
Проанализировать законодательство — некоторые типы документов должны иметь непрерывную нумерацию.
Проанализировать бизнес-процесс — по внутренним регламентам должна быть непрерывная нумерация.
Нужно учесть возможные разночтения этого ID (о и нуль)
Возможно, этот ID где-то линкуется с другими ID, например ID склада, что вызовет другие разночтения.
Возможно, другие системы, с которыми осуществляется обмен данными не поддерживают буквенные символы, учитывают/не учитывают/преобразуют регистр и т.п.
А как их вообще генерировать?
Достаточно ли шестизнака?
Не будет в конце периода стабильного таймаута при проверке коллизий/перегенерировании.
Проанализировать законодательство — некоторые типы документов должны иметь непрерывную нумерацию.
Проанализировать бизнес-процесс — по внутренним регламентам должна быть непрерывная нумерация.
Нужно учесть возможные разночтения этого ID (о и нуль)
Возможно, этот ID где-то линкуется с другими ID, например ID склада, что вызовет другие разночтения.
Возможно, другие системы, с которыми осуществляется обмен данными не поддерживают буквенные символы, учитывают/не учитывают/преобразуют регистр и т.п.
-1
Вы сейчас описали абсолютно стандартные и разрешимые вопросы, которые перед каждым разработчиком или проектировщиком возникают ежедневно и которые он должен уметь решать.
Самая жесть с которой сталкивался я лично — настроенный инкрементальный ID сущности, который использовался в качестве первичного ключа. А потом ВНЕЗАПНО оказывалось, что тот же ID нужно присвоить какому-то еще документу (например, номера приказов начинаются заново с нового года). И все, финиш, перелопачивать структуру базы. А все потому, что голову нужно всегда включать.
Самая жесть с которой сталкивался я лично — настроенный инкрементальный ID сущности, который использовался в качестве первичного ключа. А потом ВНЕЗАПНО оказывалось, что тот же ID нужно присвоить какому-то еще документу (например, номера приказов начинаются заново с нового года). И все, финиш, перелопачивать структуру базы. А все потому, что голову нужно всегда включать.
+1
Мда, номер приказа использовать в качестве первичного ключа… это ж офигеть.
0
Называется «естественный первичный ключ». Для нормализованной базы это нормально. Суррогатные первичные ключи обычно избыточны.
0
Только это часть от него. Обычно у документов номера с нового года начинаются заново, и в разных подразделениях может быть своя независимая от других нумерация.
0
И я о том же.
В документообороте номера документов никак первичным ключом нельзя делать.
И табельный номер у сотрудников — тоже…
В документообороте номера документов никак первичным ключом нельзя делать.
И табельный номер у сотрудников — тоже…
0
Тогда естественный первичный ключ должен быть составным, например год+номер. Суррогатные просто удобнее на практике, пускай и увеличивают объёмы данных за счёт избыточности.
0
Я по инкрементальным айдишникам обычно оцениваю оборот магазинов
У меня один заказчик был, вот ему захотелось пресечь такие попытки. Поэтому мы к id-шникам добавляли 1635.
Правда там не магазин был, а сервис типа вопрос-ответ.
0
Мы однажды по заказу разрабатывали интернет-магазин. Одно из требований у заказчика было сделать номера заказов чтобы они начинались не с 1, а например с 1000. И тоже самое с артикулами. Очень он хотел чтобы было так, считал что артикул товара 1 и заказ номер 3 это адски несолидно.
+3
Мы в универе так 3 года тесты проходили в некоем Moodle. Там айдишки ответов сквозные и в открытом виде прямо внутри сорца страницы были. Ну а по логике вещей, наименьшая айдишка правильная )
+5
Я не согласен с автором статьи — нужно имплементировать security правильно, а не лепить костыли.
Выбор идентификаторов должен быть диктован ограничениями системы/ее архитектурой, а не попыткой что-то там заобфусцировать/захачить/прикрутить еще один клевый хак-о-костыль.
Если Security заимплементирована криво, то это проблема дизайна приложения/архитектуры/квалификации программистов.
Взгляд допустим на тот же Spring Security дает понимание того, как оно могло бы по правильному работать. И даже если вы не работаете с Java, больше чем уверен, что есть множество решений под разные языки/платформы готовые, удовлетворяющие нуждам.
Ну или хотя бы на их основании можно в правильном направлении начать двигаться, а не лепить что-то по типа «А давайте добавим еще один ID и слепим их вместе, а потом будем разбивать их пополоам, никто ведь не догадается».
Выбор идентификаторов должен быть диктован ограничениями системы/ее архитектурой, а не попыткой что-то там заобфусцировать/захачить/прикрутить еще один клевый хак-о-костыль.
Если Security заимплементирована криво, то это проблема дизайна приложения/архитектуры/квалификации программистов.
Взгляд допустим на тот же Spring Security дает понимание того, как оно могло бы по правильному работать. И даже если вы не работаете с Java, больше чем уверен, что есть множество решений под разные языки/платформы готовые, удовлетворяющие нуждам.
Ну или хотя бы на их основании можно в правильном направлении начать двигаться, а не лепить что-то по типа «А давайте добавим еще один ID и слепим их вместе, а потом будем разбивать их пополоам, никто ведь не догадается».
+10
Пример №2 и Пример №3
Думаю что роскомнадзор, следящий за выполнением ФЗ №152, будет очень рад провести проверку этих фирм :)
+5
Недавно тоже столкнулся с такой идеей как не дать перебрать все фотографии в системе. Ничего умнее соли не придумал. в итоге получалась ссылка: /media/640x480/abrakadabra_452
0
Нужно различать две проблемы:
— возможность доступа произвольному пользователю по известному ему id к записи конфиденциальной информации
— возможность (простота) подбора произвольным пользователем id
Как правило, проблема именно в первом пункте, а не во втором: доступ получает любой обладатель «секретной» ссылки, хотя как фича сервиса это не задумывалось. Пытаться «засекретить» ссылку путем использования менее очевидного алгоритма её формирования проблемы не решает.
— возможность доступа произвольному пользователю по известному ему id к записи конфиденциальной информации
— возможность (простота) подбора произвольным пользователем id
Как правило, проблема именно в первом пункте, а не во втором: доступ получает любой обладатель «секретной» ссылки, хотя как фича сервиса это не задумывалось. Пытаться «засекретить» ссылку путем использования менее очевидного алгоритма её формирования проблемы не решает.
+3
Как раз работаю в похожей системе, и у нас есть возможность посмотреть статус платежа по ID, который, можно сказать, инкрементируется, т.е. легко подбираем.
Но это диктуется удобством пользователя, если Вы положили деньги в терминале и хотите узнать статус платежа — то Вы можете просто зайти на сайт и по номеру чека получит эту инфу. Удобно. Никаких регистраций. Да и стали бы Вы регистрироваться на сайте владельца терминала только для того, чтобы узнать статус платежа.
С другой стороны есть проблемы с безопасностью(причем, с точки зрения менеджеров, незначительные). Не могу сказать как у нас принимали окончательное решение об этой фиче, какие варианты рассматривали, но работает оно так.
Но это диктуется удобством пользователя, если Вы положили деньги в терминале и хотите узнать статус платежа — то Вы можете просто зайти на сайт и по номеру чека получит эту инфу. Удобно. Никаких регистраций. Да и стали бы Вы регистрироваться на сайте владельца терминала только для того, чтобы узнать статус платежа.
С другой стороны есть проблемы с безопасностью(причем, с точки зрения менеджеров, незначительные). Не могу сказать как у нас принимали окончательное решение об этой фиче, какие варианты рассматривали, но работает оно так.
0
А почему бы не печатать на том же чеке код какой-нибудь, и не хранить его в той же базе где данные платежа, и выводить его при вводе правильного кода?
0
Да это все понятно, но сама система «растет» уже лет эдак 8, представляете какое это наследие? Да и работаем мы с кучей сторонних процессингов, терминалов. Вот так взять и запилить фичу это дороговато будет. Тут как в бойцовском клубе: пока сумма выплат по страховке меньше стоимости отзыва серии автомобилей — делать ничего не будем.
0
Ну тут разные мысли могут быть. Вообще главная проблема это авторизация и разграничение доступа. Взять пример мой баянистый: habrahabr.ru/company/dsec/blog/143921/.
Тут в Яндекс почте отсутствовала авторизация, и доступ по ID письма. Но именно тот факт, что ИД был обычным инструментируемым целым числом, можно было проводить целевые атаки на почтовый ящик. То есть шлешь письмо себе и врагу. У тебя ID = X, у врага X+1, и вот ты уже знаешь его пул сообщений и читаешь остальные письма из его ящика (при прочих удачных моментах).
+ верно заметили, что не рандомный идишник дает некоторую статистическую инфу о работе системы.
Зависит от конкретной реализации и бизнеса. Это нужно просто понять, проанализировать и построить правильную архитектуру. Проверка субъекта при ддоступе к объекту — это главная проблема. Не рандомный идшник — вторая, возможно не такая важная, но в совокупности с первой дающая больше векторов для атаки и позволяет сделать что-то иное.
Тут в Яндекс почте отсутствовала авторизация, и доступ по ID письма. Но именно тот факт, что ИД был обычным инструментируемым целым числом, можно было проводить целевые атаки на почтовый ящик. То есть шлешь письмо себе и врагу. У тебя ID = X, у врага X+1, и вот ты уже знаешь его пул сообщений и читаешь остальные письма из его ящика (при прочих удачных моментах).
+ верно заметили, что не рандомный идишник дает некоторую статистическую инфу о работе системы.
Зависит от конкретной реализации и бизнеса. Это нужно просто понять, проанализировать и построить правильную архитектуру. Проверка субъекта при ддоступе к объекту — это главная проблема. Не рандомный идшник — вторая, возможно не такая важная, но в совокупности с первой дающая больше векторов для атаки и позволяет сделать что-то иное.
+2
Ох, увидел вторую картинку и получил заряд бодрости на весь день. Совпадает практически вся незаблюреная инфа.
А ещё вчерашний платёж через один из мерчантов задержался на 20 часов (при том что нормальное время проводки — 5 минут).
В мозгу уже запускался поиск лестных эпитетов в пользу «тестировщиков», но потом дочитал, что инфа с сервиса с кредитами, коими я не пользуюсь.
Словом, статья — пример того, как важны проверки всей информации, которая поступает в приложение извне.
А ещё вчерашний платёж через один из мерчантов задержался на 20 часов (при том что нормальное время проводки — 5 минут).
В мозгу уже запускался поиск лестных эпитетов в пользу «тестировщиков», но потом дочитал, что инфа с сервиса с кредитами, коими я не пользуюсь.
Словом, статья — пример того, как важны проверки всей информации, которая поступает в приложение извне.
0
У нас в Латвии за перебор айдишников в URL устраивают маски-шоу и судят. Слава Богу, оправдали (пардон, не получается вставить ссылку на русскую википедию).
+3
Википедия: Пойканс, Илмар
0
Это было отверстие в системе безопасности, такое даже дырой не назовешь. Да и там скорее намеренный слив был по политическим причинам, так как в итоге вскрылось очень много неприглядного. Вообще такие проверки нормальными разработчиками делаются на полном автомате, как только пишешь свою систему сообщений или платформу блогов.
Встречал и более интересные ляпы — хранение файлов, к которым ограничен доступ, в одной папке под инкрементальными именами. Например, domainname/files/1.jpg, domainname/files/2.pdf и тд., даже без использования file_put_contents. Либо с использованием и передачей параметра file_id (опять же инкрементального), но без проверки того, кто и откуда за ним обращается.
Встречал и более интересные ляпы — хранение файлов, к которым ограничен доступ, в одной папке под инкрементальными именами. Например, domainname/files/1.jpg, domainname/files/2.pdf и тд., даже без использования file_put_contents. Либо с использованием и передачей параметра file_id (опять же инкрементального), но без проверки того, кто и откуда за ним обращается.
0
переименуйте статью в — Эти чертовы школьники
-7
UFO just landed and posted this here
Хорошо бы было в статьеисказать, что основная причина использовали последовательных id — простота обеспечения уникальности. И привести примеры, как другими идентификаторами добиться уникальности. Знаю про GUID, какие еще варианты есть?
0
Я бы сказал, основная мотивация для последовательных id — это всё же возможность использования кластерных индексов. Непоследовательный уникальный id всегда можно сгенерировать на основе последовательного, применив какую-нибудь обратимую функцию, но выгоды никакой — и кластеризацию поломает, и нижеописанные проблемы останутся.
Другие проблемы:
* Простота последовательных id может обернуться боком, когда захочется, например, смерджить данные из двух баз в одну, и целые диапазоны первичных ключей перекроются. Особенно весело, если эти значения уже расползлись по другим базам, и уже нельзя их просто так взять и поменять.
* Невозможность генерить уникальный id на клиентской стороне, что несколько усложняет создание объектов — приходится вместо простого результата «успех/неуспех» возвращать ещё и id свежесозданного объекта, затем апдейтить его у клиента, что не даёт использовать immutable object pattern и загрязняет код.
Другие проблемы:
* Простота последовательных id может обернуться боком, когда захочется, например, смерджить данные из двух баз в одну, и целые диапазоны первичных ключей перекроются. Особенно весело, если эти значения уже расползлись по другим базам, и уже нельзя их просто так взять и поменять.
* Невозможность генерить уникальный id на клиентской стороне, что несколько усложняет создание объектов — приходится вместо простого результата «успех/неуспех» возвращать ещё и id свежесозданного объекта, затем апдейтить его у клиента, что не даёт использовать immutable object pattern и загрязняет код.
0
Если на сайте не предусмотрена регистрация, но нужна ссылка на заказ, которую юзер бы мог открывать с разных компьютеров, то можно использовать следующее: если у вас «инкрементальные айдишники», чтобы кардинально не переделывать, просто добавляем к запросу параметр — результат хеширования id с солью: site.ru/shipment/2457?hash=1289ae093b… В коде просто сверяем результат хеширования и переданный хеш.
P.S. Также не забываем закрывать от индексации подобные страницы, а то вон сколько случаев было
P.S. Также не забываем закрывать от индексации подобные страницы, а то вон сколько случаев было
0
Описанная в статья уязвимость — это разновидность Сross Site Request Forgery Лечится добавлением токенов в каждый запрос. Скажем, в Phalcon для этого есть удобные встроенные механизмы.
0
Sign up to leave a comment.
Эти чертовы инкрементальные айдишники