Вы все еще пользуетесь WebloginPE? Тогда школохакеры идут к вам!

Недавно меня попросили настроить и отладить систему авторизации на ModxEvo, на котором, в этом качестве был установлен WebloginPE 1.3.1. Так состоялось наше знакомство и оно, увы, не было приятным.

Первое, что мне попалось на глаза, это кука с одноименным названием (WebLoginPE), которая не была HttpOnly и следовательно легко перехватывалась простым javascript. Что же в ней хранится, подумал я?
Отправился в метод SessionHandler и обнаружил, что хранятся в ней md5 хеши логина и пароля. Две константы. В доступной куке. И ни одной переменной! Все еще на что-то надеясь я скопировал эту куку в другой браузер и мгновенно авторизовался через него сайте. Чтооааа?! Потом поредактировал профиль пользователя из двух браузеров одновременно. Чтооааа?!!!
Затем, используя хеш вместо пароля легко авторизовался на сайте через форму логина. Это просто праздник какой-то! День открытых дверей)
На этом сюрпризы не закончились.
Продолжаю изучать метод SessionHandler, и вижу, что в куку и в сессию пишутся разные переменные пароля: в куку $this->User['password'] — т.е. md5 хеш взятый из базы, а в сессию, обернутый в base64_encode $this->Password — взятый откуда? Правильно! Из метода Login. Т.е. это пароль, введенный пользователем при авторизации на сайте В ОТКРЫТОМ, не зашифрованном виде! FacePalm! Для чего это вообще понадобилось?! При любом debag'e сессии он просто вывалится на публику as is!
А для чего в таблицу базы web_user_attributes пишется ID сессии? Для отчетности?
После таких открытий прямой путь к загрузке картинок — метод CreateUserImage.
Приятная новость, проверка размера картинки есть!
Неприятная новость — больше никаких проверок нет. Т.е. ни проверки расширения файла, ни mime-type — ничего. Загружай что хочешь.
Про хранение аватарок в папке сниппета можно даже не упоминать. Ну нету в Modx папки assets/images. Нету.
В итоге, минимальные правки сниппета, просто чтобы спать спокойно:
1) Куки только HttpOnly
2) Никаких паролей или их хешей в куке и в сессии
3) В куке md5 хеш username и ID сессии
4) Проверка ID сессии из куки на соответствие ID в базе при каждом действии пользователя
5) Обновление ID сессии каждый час с помощью session_regenerate_id
6) Ограничение длины пароля в методе Login до 30 символов (md5 использует 32 символа), чтобы нельзя было ввести хеш пароля вместо пароля при логине.
7) Проверка загрузки картинок на расширение файла и mime-type и хранение в специально отведенном для них месте

27 комментариев

avatar
А если только для регистрации использую этот сниппет?
avatar
Тогда удалите из параметра сессии $_SESSION['webValid'] пароль и в метод логин поставьте ограничение на длину пароля меньше 30 символов (md5 хеш состоит из 32-ух символов). Если длину пароля не ограничить, то в форме авторизации можно просто использовать похищенный из куки хеш.
avatar
Всегда недолюбливал системы авторизации…
avatar
И что конкретно можно сделать, зная, что у кого-то в куке пароль в md5?
Придти к нему домой, побить ногами и скопировать куку? Проще пароль узнать сразу.
  • 1px
  • 0
avatar
Пользователь вешает в свой профиль javascript (alert( document.cookie );) и собирает куки других пользователей. И да, вы будете смеяться, но md5 хеш пароля в WebLoginPE можно прямо использовать в форме авторизации вместо самого пароля. Можете проверить на досуге.
avatar
Так это уже по другому ведомству — от xss надо защищаться.
Вообще толковая статья, спору нет. Но прям так чтобы уж критичный баг…
avatar
Возможность загружать любые файлы и беспрепятственно собирать куки с хешами паролей пользователей — не критично? Хм… А что же тогда критично?
avatar
К сожалению, в MODX сплошь и рядом xss если вдруг кто-то начинает работать с пользовательскими данными. Обработка данных отсутствует как вид и именно поэтому в DocLister добавлен экстендер е. Кто знает — тот при необходимости пользуется. Кто не знает — тот и дальше продолжает использовать не экранированные данные. Тут проблема в том, что разработчики сниппетов как правило отдают сырые данные — и это правильно, поскольку никогда нельзя заранее сказать как эти данные будут дальше использоваться. А экранировать уже должны конечные разработчики сайтов.

Разве сложно создать сниппет
$charset = isset($charset) ? $charset : 'UTF-8';
return (isset($input) && is_scalar($input)) ? htmlspecialchars($input, ENT_QUOTES, $charset, false) : '';

И пользоваться им в стиле
[[escape? &text=`<script>alert(1);</script>`]]
[[escape? &text=`[+username+]`]]

либо даже так, если установлен PHX:
[+username:escape+]


Нет, не сложно. Правильно ли будет, если в плейсхолдере [+username+] будут сразу экранированные данные? Нет, не правильно. Потому как может возникнуть ситуация, когда нужно этот [+username+] подставить в запрос, а там необходима совсем другая обработка:
$modx->db->escape()
При этом необходимость в сырых данных может возникнуть, когда сам разработчик сайта разрешил записывать html теги в какое-то поле пользователя. И тут нужно уже подключить strip_tags_smart, Jevix, Qevix, HTML Purifier и т.д. Да, это удобно, когда сниппет уже умеет как-то предварительно обрабатывать данные в зависимости от ситуации (допустим, [+title+] и [+e.title+] в DocLister). Но всех вариантов не предусмотреть. Поэтому я считаю, что XSS нужно фиксить не внутри сниппета, а при выводе данных добавляя обработку в зависимости от ситуации.
avatar
Забыл еще добавить, что зачастую одних только htmlspecialchars или $modx->db->escape может быть не достаточно. Для MODX нужно ввести еще такое понятие как активная MODX-XSS, это когда вместо пользователь вводит MODX тег с параметрами которые могут привести к уязвимости. Возьмем очень популярный сниппет IF — там есть параметр через который можно выполнить eval функцию. Да даже базовый breadcrumbs может привести к слепой SQL-injection через параметр hideUnder. И очень странно, что в MODX до сих пор нет такого метода, который бы предлагал функцию для экранизации MODX тегов
avatar
Зачастую пользователи пользуются одним паролем на всех сайтах (не 100% пользователей, но своя доля есть).
Получив на одном из сайтов пароль, можно расшифровать и авторизоваться в соцсетях.
avatar
Расшифровать, имел в виду подобрать хеш.
Так как есть пользователи что используют пароль 1q2w3e или 12345
avatar
Спасибо за интересную статью. Я решил проверить, как обстоят дела в modUsers, который как бы предполагался совместимым с WebLoginPE.

Халявы с хэшем вместо пароля там не было изначально. Паролей в открытом виде тоже нет.

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

По итогу в modUsers я исправил создание куки, добавив параметры secure и httponly — вот исправленная версия.

Создание куки вынес в отдельный метод, что позволяет расширить модель в соответствие со степенью личной паранойи и использовать ее в FormLister — с валидацией-то там проблем точно нет (:
avatar
а если проверять id сессии, то автологин будет работать пока сессия не умрет, то есть теряется в нем смысл
Не совсем так. Проверка соответствия id сессии в куке и базе, нужна, чтобы удостоверится, что именно кука актуальна, а не сессия ( см. п.5) Обновление ID сессии каждый час с помощью session_regenerate_id ). И если да, тогда можно проверить текущую session_id на сервере и при необходимости обновить данные в базе и куке. Я это вынес в отдельный метод isSessionValid к которому обращается AutoLogin
avatar
Теперь понял, добавлю попозже и это.
avatar
Теперь в modUsers sessionid также сохраняется в куку, значение в базе изменяется каждый раз при сохранении пользователя и при автологине. Обновление каждый час я делать не стал, думаю, что не сложно написать плагин, который периодически будет пересохранять данные авторизованного пользователя.
avatar
Ок, руководство для хакеров есть :). Осталось сделать правильный WebloginPE, чтобы его могли использовать владельцы сайтов :).
  • lex
  • 0
avatar
Если вы не готовы исправить недостатки WebloginPE самостоятельно, то это не особенно и нужно. Можно воспользоваться более свежими и качественными разработками. Например, вышеупомянутый modUsers лишен всех этих недостатков, за исключением хеша пароля. Но это уже легко исправить самому и если быть до конца честным, хеш все же не константа. Пользователи хоть и не часто, но меняют пароли. К тому же это не единственный вариант — есть еще modxAccount.
avatar
Признаться честно, сейчас нет времени ни на самостоятельное исправление недостатков WebloginPE ни на переход на modUsers (тем более, что мне не удалось с первого раза найти документацию по нему) или modxAccount было бы гораздо удобнее просто обновить WebloginPE. Однако встает вопрос, КТО будет это делать?
avatar
Свою доработку я выложить не могу, потому, что делал ее платно и права на нее мне уже не принадлежат (поэтому, написал статью, а не выложил код).
Переход на современные разработки для «непрограммиста» будет лучшим выбором сразу по двум причинам: Первая — в статье упомянуты далеко не все баги с которыми я столкнулся, а Вторая — разработчики modUsers и modxAccount присутствуют на этом сайте и с ними можно общаться напрямую.
avatar
WebLoginPE устарел во всех смыслах, поэтому его бессмысленно обновлять. Хотя я уже не удивлюсь, если это сделают в очередной версии Evo, да еще и положат в коробку (:
avatar
Как по мне было бы хорошо потому, что можно будет просто обновиться. А то, что WebloginPE устарел — не аргумент, на сколько я понимаю сам MODx EVO уже давно не современный, однако и я и вы продолжаем его использовать.
avatar
С Evo тоже все упирается в вопрос «кто будет делать» (:
avatar
Согласен с Вами. :)
Получается, что теперь все уперлось в цену вопроса. Господа программисты скажите пожалуйста сколько может стоить допилить WebloginPE с учетом того, что его можно будет выложить в паблик?
avatar
и тишина :)
avatar
Прочитайте что я выше писал
avatar
на фрилансе запостите )))
avatar
в коробку его никто класть не будет) В коробку лучше положить твой FormLister, и убрать веблогины и сингапы. Куда более адекватное решение и «чистое» (:
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.