Анализ пуленепробеваимости защиты от подмены данных

Тема в разделе "Защита и взлом", создана пользователем svfolder, 31 янв 2014.

  1. svfolder

    svfolder Постоялец

    Регистр.:
    31 июл 2013
    Сообщения:
    95
    Симпатии:
    39
    Доброго времени суток всем гуру темы, и интересующимся.

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

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

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

    Код:
    MESSAGE
        SET `PUBLISHED` = '0'
    WHERE
        `ID` = '555'
          AND `USER_ID` = '833'
    LIMIT 1
    В нем 2 защиты, первая это укзание в предикате юзера владельца, вторая LIMIT 1,
    на тот страшный случай чтобы если уж и выполниться неверный запрос, то попортит только 1 запись.

    Так как далеко не всегда можно сразу легко указать AND `USER_ID` = '833' (иногда попросту нету такого поля в таблице)
    Приходится сперва извращаться на предмет, а принадлежит ли запись `ID` = '555' юзеру 833
    И только убедившись в этом, обновить ее.

    Что делаю я.

    Беру ID смешиваю его с солью, упаковываю в md5 и в параметрах отправляемых на сервер передаю 2 значения,
    собственно 555 и зашифрованный хеш этого значения.
    На сервере провожу с оригинальным значением теже действия, и сравниваю два хеша, если они совпали, значит юзер
    ничего не поменял, и значению 555 можно верить, в противном случае "юзер плохой"

    Пример банален:

    PHP:
    $salt '?$DBw%4L$U';
    $param 555;
    $param_ck md5($salt $param);

    И на сервер отправляются оба параметра param и param_ck

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


    Чтобы уж так все просто не казалось с вопросом, так же надо рассмотреть такие варианты,
    (ну чтобы не казалось кулхацкерам что ту все легко ломается)

    вариант 2
    PHP:
    $salt1 '?$DBw%4L$U';
    $salt2 'u3~rE@hv6{';
    $param 555;
    $param_ck md5($salt1 $param $salt2);
    вариант 3
    PHP:
    $salt1 '?$DBw%4L$U';
    $salt2 'u3~rE@hv6{';
    $param 555;
    $param $param $param; (для чиселибо id как правило числа)
    $param_ck md5($salt1 $param $salt2);
     
  2. jDony

    jDony Создатель

    Регистр.:
    25 янв 2014
    Сообщения:
    41
    Симпатии:
    40
    Замечания:
    - Передавать ID юзера в параметрах запроса - моветон. ID авторизованного юзера надо хранить в сессии на сервере, а саму сессию привязывать к IP/UA.
    - Писать запросы руками ("SELECT/INSERT/UPDATE") следует только в очень крайнем случае, когда требуется какая-то специфическая выборка, или оптимизация запроса. Во всех остальных случаев используй ORM. Это позволит во-первых: избавиться от зависимости к конкретной БД, и во-вторых: упростит разработку и поддержку кода.

    По поводу манипуляций с солью:
    Это имеет смысл только если данные приходят из внешнего источника(например у вас имеется интерфейс API, к которому обращаются внешние независимые скрипты).
    В вашем случае достаточно, как сказанно выше - хранить ID юзера в сессии.
    Для защиты от подмены формы(CSRF) - используйте CSRF-токен для форм.
     
  3. svfolder

    svfolder Постоялец

    Регистр.:
    31 июл 2013
    Сообщения:
    95
    Симпатии:
    39
    При всем уважении, такое не стоит рекомендовать для сколь нибудь нагруженных проектов, рассматривать системы подобные "битрикс", являющиеся быдлокодом в отношении производительности и оптимизации БД...

    Запросы руками никто и не пишет. А за такие рекомендации
    надо с работы увольнять программиста по 33 статье...

    Он и так храниться в сессии, боюсь вы в корне не поняли суть вопроса.

    Вы опять же не поняли суть вопроса, защита от подмены формы и данных в форме это совершенно разные вещи.

    ORM для ленивых программистов не желающих разбираться в оптимизации производительности, правильном хранении реляционных данных, или попросту непонимающих эту тему, пишущих программы для офисного планктона...
     
    Последнее редактирование: 2 фев 2014
    latteo нравится это.
  4. jDony

    jDony Создатель

    Регистр.:
    25 янв 2014
    Сообщения:
    41
    Симпатии:
    40
    1) При чем тут битрикс? Я где-то упомянул про CMS? Этот ваш выпад вообще не в тему.
    Качественная ORM составляет запросы намного оптимальней, чем это могут сделать 90% "гуру пхп и мускула".
    2) Тогда к чему все эти манипуляции с ID? От какой подмены его защищать? Если пользователь админ, он автоматом может редактировать ВСЕ записи(посты\пользователей\настройки\etc,). Если же это обычный пользователь, то его ID хранится в сессии, и все ваши манипуляции с md5(..) не имеют никакого смысла.
    CSRF был упомянут как раз таки по этой причине, так как другой причины для соления полей запроса я просто не вижу.
    3) Вот честно, вы слова для этого абзаца взяли с первой страницы гугла по запросу "я дартаньян"? Каким боком ORM имеет отношение к нежеланию разбираться в ("подставить 3 рандомных слова")? Можеть быть вы расскажете про это разработчикам Doctrine(PHP), Eloquent(PHP), ARPHP, Entity(C#), AR(Rails)... для джанги там тоже что-то свое есть. Они то бедные и не знают, что они "ленивые программисты не желающие разбираться в оптимизации производительности, правильном хранении реляционных данных, или попросту непонимающие эту тему".

    ORM нужен как раз и нужен, чтоб не задумываться о таких вещать, про которые вы спрашиваете:
    Чтобы не писать каждый раз свои велосипеды, и SQL запросы на 20 строк.

    Так что конкретно я не понял?

    Вы хотите ответ который вас устроит?
    - Да, ваш метод непробиваем, вы идете верным путем. Так держать!
    Только вот смысла в подобных манипуляциях нету никакого. Почему? Читайте выше.
     
    latteo и Maybe нравится это.
  5. svfolder

    svfolder Постоялец

    Регистр.:
    31 июл 2013
    Сообщения:
    95
    Симпатии:
    39
    Итак приступим:

    Прежде всего мой выпад появился в следствии вашего Оффтопа.
    В чем оффтоп, а в следующем.

    1) В моем первом посте, нет подобного рода предложений.
    О боже как я устал использовать Joomla Platform и писать руками SQL, мне так не хватает волшебной палочки чтобы все было скрыто от уставшего программиста, подскажите мне программисту собирающемуся отправить свои мозги на пенсию какую нибудь волшебную ORM.
    2) Давайте же забудем про рефакторинг, и просто прийдем на работу и скажем, нам очень умный дядя посоветовал бросить весь проект и написать его с ноля, на волшебной ORM, так как оказывается, что мы все устарели с `USER_ID` = '833'

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



    Качественная или некачественная ORM никогда не будет заниматься оптимизацией запросов, как это делает планировщик MySQL а после оптимизатор, в 90% случаев эту работу выполнит именно оптимизатор MySQL дня некачественно cгенерированного запроса любой ORM, а вы подумаете что это сделала ORM.

    Если не было бы на свете таких изобретателей велосипедов как я, то не появилось бы подобных систем, все бы сидели на FOX PRO


    Теперь о ситуации:

    Например имеем такую структуру

    [​IMG]

    И у нас идет редактирование таблицы телефонов.
    Лично у меня нет начальника, я сам себе начальник, но есть ТЗ которое составляет заказчик, и которому следует строго придерживаться.
    Не стоит отвечать что ТЗ надуманное, как минимум по 2м причинам, 1) Клиент всегда прав, 2) Задача программиста выполнять указания начальства а не спорить что это неправильно, потому что его ORM такое не умеет (например).

    В ТЗ сказано что заказчик не желает видеть денормализацию в таблицах ни при каких обстоятельствах.

    А это значит что в таблицы jos_md_company_phone и jos_md_company_fil нельзя для каждой записи прописать user_id владельца записи.

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

    Возникает вопрос, чем ваш user_id поможет при редактировании таблицы филлиалов и телефонов?

    Мы можем обновить записи в обоих таблицах только используя WHERE `ID` = '555'

    Вы предлагаете использовать CSRF, как это защитит от подмены данных в форме, у нас есть в форме скрытое поле с ID = 555, пользователь (не админ, или даже админ, или кто то с правами админа, это неважно) берет и в браузере меняет скрытое поле через инспектор элементов страницы, и вписывает вместо 555, 4546 и оправляет форму.

    Откуда при обновлении записи брать ID из реквеста? или вы тут же возгласите что надо при открытии формы спрятать 555 в сессию, и привязать его к токену формы...

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

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

    Он заполнил 15 полей из 16 и тут его прервали важным звонком, он отправил комп в спящий режим и уехал в офис.
    Вечером после работы он приехал, запустил комп, дозаполнил 16тое поле и жмакнул сохранить, и естественно... так как сессия сдохла за это время, его объявление улетело в никуда...

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

    Ну а сама суть вопроса банально проста была, зачем, лезть в таблицу jos_md_company_fil а потом jos_md_company чтобы узнать user_id владельца телефона с id = 555 и потом их сравнивать, чтобы убедиться что телефон который редактирует юзер, действительно его а не соседней компании. Когда можно просто открыто хранить ID записи и быть уверенным что его не сменит злоумышленник, и в умершей сессии с токеном он не затеряется.
     
    gvozd и latteo нравится это.