Тестируем регистрацию на сайте Люксор | Жизнь – это движение! А тестирование – это жизнь :)

Игнорирование 2FA при восстановлении пароля

Многие сервисы выполняют автоматический вход в аккаунт после завершения процедуры восстановления пароля. Так как доступ к аккаунту предоставляется мгновенно, при входе в аккаунт 2FA может миноваться и полностью игнорироваться.

Impact аналогичного репорта на hackerone, который я прислал недавно:

Если злоумышленник получит доступ к электронной почте жертвы (он может взломать учетную запись с помощью фишинга, brute-force атаки, credentials stuffing и тд), он может обойти 2FA, хотя в этом случае 2FA должен защищать учетную запись. На данный момент для 2FA есть проверка кода Google Authenticator или резервного кода, но не кода из электронного письма, поэтому данный Bypass имеет смысл.

Ограничение скорости потоков с отсутствием блокировки после достижения определенной скорости

Зачастую исследователи безопасности пытаются подобрать код с использованием 5-и или более количества потоков, чтобы быстрее выполнить атаку (в Burp Intruder количество потоков по умолчанию- 5 без задержки). Но иногда система безопасности от перебора или обычный Load Balancer может реагировать только на этот единственный фактор.

Если вы пытаетесь брутфорсить с 5-ю потоками, стоит уменьшить количество до 1-го, а потом до 1-го с задержкой в одну секунду. Ранее мне посчастливилось наблюдать за таким поведением и именно с помощью таких манипуляций произошел успешный подбор кода, что привело к Account Takeover.

Если у 2FA кода нет определенного срока действия, то у нас есть много времени на перебор. Если же срок действия присутствует, то успешность атаки уменьшена, но потенциальная опасность уязвимости все равно присутствует, так как шанс попадания в нужный код все же есть.

Безопасность

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

Похожее:  «Восточный мобайл» мобильное приложение от банка «Восточный»

Отсутствие Rate-лимита

Алгоритм Rate-лимита используется для проверки возможности пользовательского сеанса (или IP-адреса) быть ограниченым в попытках или скорости, и при каких обстоятельствах это происходит. Если пользователь выполнил слишком много запросов в течение определенного промежутка времени, веб приложение может ответить 429 кодом (много запросов) или применить Rate-лимит, не показав при этом ошибок.

. Манипуляция версиями API

Если вы видите в запросе web приложения что-то вроде /v*/, где *  —  это цифра, то есть вероятность, что можно переключиться на более старую версию API. В старой версии API может быть слабая защита или таковой может вовсе не быть. Это довольно редкое явление и возникает в том случае, если разработчики забыли удалить старую версию API в production/staging среде.

Генерируемый OTP код не изменяется

Это касается не постоянно изменяющихся кодов как в Google Authenticator, а только статичных, которые приходят в SMS, email или личным сообщением в мессенджере.

Суть данного обхода состоит в том, что постоянно или в течении некоторого времени, например, 5 минут, в SMS отправляется один и тот же OTP код, который в течении всего этого времени является валидным. Так же стоить следить за тем, чтобы не произошел silent rate-limit.

Если 2FA крепится к IP-адресу, то можно попытаться его подменить

Чтобы идентифицировать данный метод, войдите в свой аккаунт с помощью функции запоминания 2FA, потом перейдите в другой браузер или incognito режим текущего браузера и попробуйте войти снова. Если 2FA не запрашивается вовсе, значит произошло крепление 2FA к IP-адресу.

Игнорирование 2FA при входе через соцсеть

К аккаунту пользователя можно прикрепить социальную сеть для быстрого входа в аккаунт и одновременно настроить 2FA. При входе в аккаунт через соцсеть, 2FA может игнорироваться. Если email жертвы будет взломан, то можно будет восстановить пароль к аккаунту соцсети (если она позволяет это сделать) и войти на сервис без ввода 2FA.

Impact одного из репортов:

Rate лимит существует, но его можно обойти

Кейсы, которые раньше приходилось встречать:

Стабильность

Когда пользователь вводит данные, которые не могут быть обработаны приложением, оно может среагировать неожиданным образом — например, упасть.

Сброс rate-limit-a при обновления кода.

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


Примеры репортов:

Корректное поведение UI и единообразие

Очень важно, чтобы все формы в приложении были единообразны (и по внешнему виду, и по поведению).

Обход 2фа с помощью подстановки части запроса из сессии другого аккаунта

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

Например, при отправке OTP-кода проверяется ID формы, ID пользователя или cookie, которое связано с отправкой кода. Если применить данные с параметров аккаунта, на котором нужно обойти code-верификацию (Account 1), на сессию совсем другого аккаунта(Account 2), получим код и введем его на втором аккаунте, то сможем обойти защиту на первом аккаунте. После перезагрузки страницы 2FA должна исчезнуть.

Игнорирование 2FA в случае кроссплатформенности

Имплементации 2FA в мобильной или десктопной версии могут отличаться от web версии приложения. 2FA может быть слабее, чем в web версии или вовсе отсутствовать.

7. При отключении 2FA не запрашивается текущий код.

Если при отключении 2FA не запрашивается дополнительное подтверждение, такое как текущий код с google authenticator приложения, код с email/телефона, то в таком случае имеются определенные риски. При чистом запросе существует вероятность CSRF атаки. Если будет найден вектор обхода CSRF защиты (если она есть)

, то 2FA можно будет отключить. Также может использоваться clickjacking уязвимость, — после пары кликов от ничего не подозревающего пользователя 2FA будет отключена. Подтверждение предыдущего кода добавит дополнительную защиту 2FA, учитывая потенциальные CSRF/XSS/Clickjacking атаки, а также CORS misconfigurations.

Обход rate-лимита путем смены IP адреса

Множество блокировок основаны на ограничении приема запросов с IP, который достиг порога определенного количества попыток при выполнении запроса. Если IP-адрес сменить, то есть возможность обойти это ограничение. Для того, чтобы проверить данный способ, просто смените свой IP с помощью Proxy-сервера/VPN и увидите, зависит ли блокировка от IP.

Способы смены IP:

Так как IP rotate тулза отправляет запросы с помощью AWS IP-адресов, все запросы будут блокироваться, если веб приложение находится за CloudFlare фаерволом.

В данном случае нужно дополнительно обнаружить IP оригинального веб сервера или найти способ, не касающийся AWS IP-адресов.

Обход 2FA с помощью «функционала запомининания»

На многих сайтах, поддерживающих 2FA авторизацию, есть функционал «запомнить меня». Он полезен в том случае, когда пользователь не желает вводить 2FA код при последующих входах в аккаунт. Важно идентифицировать способ, с помощью которого 2FA «запоминается». Это может быть cookie, значение в session/local storage или просто крепление 2FA к IP адресу.

Чистота базы данных

Форма — место, которое наполняет базу данных. Если есть проблемы с валидацией, появляется угроза того, что некорректные данные попадут в БД. Это ведет к проблемам с поведением приложения и потенциальным багам.

На сайте включена поддержка X-Forwarded-For

Встроенный header X-Forwarded-For может использоваться для смены IP. Если в приложение встроена обработка данного хедера, просто отправьте X-Forwarded-For: desired_IP для подмены IP, чтобы обойти ограничение без использования дополнительных прокси. Каждый раз, когда будет отправлен запрос с X-Forwarded-For, веб-сервер будет думать, что наш IP адрес соответствует значению, переданному через хедер.


Материалы на эту тему:

Improper access control баг на странице ввода 2FA

Иногда страница-диалог для ввода 2FA представлена в виде URL с параметрами. Доступ к такой странице с параметрами в URL с cookies, которые не соответствуют тем, которые использовались при генерации страницы или вообще без cookies, —  это не безопасно. Но если разработчики решили принять риски, то нужно пройтись по нескольким важным пунктам:

  1. истекает ли ссылка для ввода 2FA;
  2. индексируется ли ссылка в поисковиках.

Игнорирование 2FA при определенных обстоятельствах

При выполнении некоторых действий, которые приводят к автоматическому входу в аккаунту, 2FA может не запрашиваться.

Отсутствие Rate-limit-а в личном кабинете

2FA может внедряться в различные функционалы личного кабинета пользователя для большей безопасности. Это может быть изменение email адреса, пароля, подтверждение изменения кода для осуществления финансовых операций, etc. Наличие rate-limit-a в личном кабинете может отличаться от наличия rate-limit-a в 2FA при входе в аккаунт.

Если разработчики изначально добавили защиту против несанкционированного изменения данных, то данную защиту нужно поддерживать и исправлять все возможные bypass-ы. Если bypass найден, то это расценивается как уязвимость обхода «security feature», которая была имплементирована разработчиками.

Анализ граничных значений

Кроме классов эквивалентности, нужно протестировать граничные значения. Граничные значения это:

  • Минимальное значение
  • Максимальное значение
  • Выборочные значения из промежутка

Вот пример:

Граничные значения проверяются, потому что ни один разработчик не застрахован от так называемой ошибки на единицу.

Бонус: bugmagnet

Для тестирования форм есть отличный плагин для Chrome и Firefox — BugMagnet. После установки кликните правой кнопкой мыши по любому полю формы и у вас появится возможность выбора значений для заполнения из огромного списка данных. Вот видео, на котором показано, как работаем BugMagnet:

Дополнение

Вместе со всем вышеперечисленным нужно попробовать:

Как правильно создавать тест-кейсы для формы регистрации?

Если форма заполнена не полностью, то кнопка отправить должна быть неактивна.

Если форма заполнена невалидными данными и/или неполностью – кнопка “Отправить” должна быть неактивна и неверно заполненые поля должны показывать подсказку.

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

Если есть необязательные поля, нужно проверить, что их заполнение, незаполнение или неверное заполнение не влияет на результат. Если есть кнопки переключатели (radio buttons) можно проверить выставляется ли значение по умолчанию если должно или не выставляется если не должно. Бывает что выставляется хотя не должно.

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

Не думайте о количестве тесткейсов, думайте о том, в чем вы хотите убедиться.

Как протестировать метод авторизации?

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

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

Примерная реализация авторизации для понимания что я тестирую, на самом деле ее не существует.

class UserManager implements UserManagerInterface
{
    public function makePasswordHash($password)
    {
        return md5($password); // какое-то хеширование
    }
}

class AuthorizationManager implements AuthorizationManagerInterface
{
    public function authorizeUserByLogin($login, $password)
    {
        $user = $this->userManager->getUserByLogin($login);
        $passwordHash = $this->userManager->makePasswordHash($password);
        if ($passwordHash === $user->getPasswordHash()) {
            // авторизуем пользователя
            return true;
        }
    }
}

Тест этой авторизации

class AuthorizationManagerTest extends TestCase
{
    /**
     * Не должно авторизовывать пользователя по правильному логину но по неправильному паролю
     * @test
     */
    public function dontAuthorizeUserByLoginAndWrongPassword()
    {
        $userManagerMock = $this->getUserManagerMock();
        $authorizationManager = new AuthorizationManager($tokenManagerMock, $userManagerMock);

        $login = 'login';
        $password = 'wrongPassword';

        $userId = 15;
        $passwordHash = md5('password'); // Логика хеширования пароля в тесте, мне кажется это не правильно

        $userManagerMock->method('getUsersByLogin')
            ->willReturn([$this->getUserMock($userId, $login, $passwordHash)]);

        $result = $authorizationManager->authorizeUserByLogin($login, $password);

        $this->assertEquals(false, $result, 'Пользователь был авторизован по верному логину и неверному паролю');
    }
}

Разделение эквивалентности

Разделение эквивалентности — это разделение набора возможных данных для ввода на классы. Каждый член класса считается идентичным всем остальным.

Давайте разберем это на примере. Предположим, что есть поле для ввода, которое может принимать только числовые значения в промежутке от 1 до 200 000. Вот классы эквивалентности, которые нужно будет проверить:

  • Числа меньше минимального значения промежутка (меньше 1)
  • Числа внутри промежутка (1-200 000)
  • Числа больше максимального значения промежутка (больше 200 000)

Таблица верификации полей

Вот пример таблицы для верификации полей ввода. Вы можете составить такую же для вашей формы.

Тип данныхКорректный вводНекорректный ввод
Положительные целые числа— только числа
— максимально возможное значение (N)
— числа внутри промежутка (N 1) / 2
— число больше максимально возможного (N 1)
— дробные числа
— отрицательные числа
— строковые значения
— числа строковые значения
— числа специальные символы
— Unicode (например U 0000, U 0001)
Строки— только символы
— только числа
— только специальные символы
— числа символы
— числа спецсимволы
— символы спецсимволы
Даты— проверить, что при выборе появляется datepicker
— проверить, что поле нельзя изменить с клавиатуры
— проверить, что значение поля можно скопировать, но вставить нельзя
— проверить, что при выборе значения в datepicker, оно появляется в поле
— проверить, что в феврале 29 дней в високосных годах
— проверить, что в феврале 28 дней не в високосных годах

Тестируем регистрацию на сайте люксор

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

Smile :)

Давайте рассмотрим простой пример, например, регистрацию на сайте довольно известного кинотеатра – Люксор.

Итак, открываем сайт – http://www.luxorfilm.ru/cinema/center/
Нажимаем справа сверху кнопку “Войти”, а потом – регистрация.

И вот перед нами более-менее стандартная форма регистрации. Как будем тестировать?

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

То есть, ничего не трогая, сразу нажимаем на “Сохранить”. Наверняка у нас на более сложные формочки будет спецификация, в которой четко прописано, какие поля обязательны для заполнения, а какие – нет.

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

Тут мы замечаем одну интересную вещь – около полей “подтвердите пароль” и “введите код из картинки” не появилось сообщений об ошибке. Хммм…

Но, прежде чем бежать регистрировать баг, давайте убедимся, что эти поля действительно необязательны для заполнения. Бывает и такое, что, если не заполнены “основные” поля, сообщения об ошибках появляются только около них. А заполнишь их – сообщения появятся и около других полей. Так у нас и происходит с полем кода картинки. Заполняем строго те поля, около которых появились сообщения об ошибках и видим следующую картину:

Окей! Заполняем код из картинки и нажимаем сохранить – ага, пароль сбросился, это, в принципе, правильно. Заполняем пароль и код из картинки… И регистрация проходит успешно!

Тут в нашу голову наверняка закралось сомнение – а зачем нам вообще нужно поле “Подтвердите пароль”, если его необязательно заполнять?

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

На данном сайте такой проверки нет. Но ведь тогда и поле не имеет смысла. Итак, теперь можно с чистой совестью писать баг:

——————————————————————————————————————-

Шаги для воспроизведения:

  1. Открываем сайт
  2. Нажимаем на кнопку “Войти”
  3. Нажимаем на кнопку “Регистрация” (можно было изначально дать линк на http://www.luxorfilm.ru/Users/Registration.aspx, но ведь название странички может и измениться, поэтому такую ссылку вставить можно, но как дополнение к шагам. Да да, шаги тоже могут изменяться, но их суть часто остается прежней)
  4. Заполняем все поля, кроме “Подтвердите пароль”.
  5. Нажимаем “Регистрация”.

Результат

Пользователь успешно создан.

Ожидаемый результат
Видим сообщение об ошибке, что введенный пароль не совпадает с паролем, введенным в поле “Подтвердите пароль”.

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

——————————————————————————————————————-

Отлично. обязательность полей проверили, позитивный тест-кейс на успешную регистрацию тоже проверили. Параллельно нашли usability багу – когда ставишь курсор в какое-либо поле, ты не видишь его там. То есть, если пользователь переключается между полями с помощью кнопки Tab, он не видит, срабатывает такой переход или нет… Это некритично, но неудобно – заводим минорную багу, когда поправят, тогда поправят.

Кстати, насчет заведенной нами баги про обязательность поля. Казалось бы, ну кто будет так делать, да? Оставлять поле пустым? По крайней мере, специально… А как вы думаете, я на это наткнулась – занималась в праздники тестированием рандомных сайтов? Smile :)

Итак, user-story, как я дошла до жизни такой, а точнее, до такого блог-поста:

Собрались мы “назавтра” в кино. Разумеется, чтобы места были хорошими, их лучше забронировать заранее, например, вечером предыдущего дня. Открываю сайт Люксора – не открывается Sad :(

Мда, бывает с ним такое… Ладно, тогда пытаюсь забронировать билеты на следующий день, уже перед выходом. Ура, сайт работает! Выбираем сеанс, места, подтверждаем, что согласны с условиями бронирования и-и-и-и… А где кнопка “забронировать”???

Да что ж такое-то… Ладно, вон там есть кнопка “Войти”, может, если войти в систему, то будет бронь работать? Сомнительно, конечно, но вдруг? Итак, регистрируемся, email, ФИО, пол… А хотя зачем им моя дата рождения? Нажимаем сразу “Регистрация”!

Упс, логин и пароль не заполнила, и правда, куда без них. Заполняем, нажимаем “регистрация”, и… Взгляд утыкается в строку “подтвердите пароль”, которую я, разумеется, не заполнила, так как спешу и мысли о другом. Что сказали заполнить, то и заполнила… И вот сейчас сайт продумается и выдаст мне новое сообщение об ошибке… А так как он сегодня тугодум, то это лишнее время…

И вдруг перед моим изумленным взором возникает сообщение об успешной регистрации о_О

А ведь не искала специально…

Но что-то мы отвлеклись. Раз уж решили обсудить, как будем тестировать эту формочку, то давайте закончим рассуждения:

  1. Проверяем обязательность заполнения полей – нажимаем “Сохранить”, ничего не заполнив, смотрим, где появились сообщения об ошибках.
  2. Проверяем план-минимум, то есть заполняем только обязательные поля и убеждаемся, что внутри системы не зашито обязательным какое-то необязательное поле.
  3. Проверяем план-максимум, то есть заполняем вообще все, а после регистрации в личном кабинете проверяем, что информация сохранилась правильно.
  4. Пока мы прошли первые 3 шага, заодно проверили и юзабилити формы регистрации, вон, даже багу нашли.
  5. Теперь пора докапываться до самих полей. Итак, заполняем все поля корректно, кроме поля “email” – вводим туда что-нибудь, не являющееся email-ом. Ок, сообщение об ошибке есть. Отлично. Копаем дальше – а если email невалидный, но содержит “@”? А если он косит под валидный, но не является стандартным? Например, [email protected]? Итд. Сверяем со спецификацией – какие проверки должны быть у поля, соответствуют ли они реальности? Потом смотрим, а какова максимальная длина поля? О, 64 символа? Вводим граничное значение, проверяем, что работает. Потом вводим 65 символов, проверяем, что не работает. Потом ищем технологическую границу (то есть вводим ооооочень длинное значение, ну, скажем, нажимаем “9” и зажимаем кнопочку секунд на 5-10) – вдруг сайт упадет?
  6. Остальные поля, например, ФИО, проверяем на длину, если нет других ограничений.
  7. Вот разве что дата требует отдельного внимания. У меня, например, календарь вообще не открывается, можете кидать помидоры в сторону ИЕ, но мне лениво пробовать в мозилле. Хотя, если бы надо было протестировать, протестировала бы везде. Опять же, прежде чем заводить багу “не открывается popup календаря”, надо локализовать проблему – он вообще не открывается или только в вашем браузере? Когда видите такие проблемы в веб-приложениях, всегда локализовывайте проблему. Далее. Вводим дату вручную – корректную, нижнюю границу (что-то типа 01.01.0001) и верхнюю (01.01.3333), веб-сайты, кстати, часто падают на таких некорректных значениях просто потому, что они не могут их обработать, код соответствующий не написан.

И последний, 8 пункт – на закуску осталось самое интересное. Казалось бы, на такой простой формочке уже все проверено? Ан нет. Попробуйте ввести неправильные данные, а потом – правильные. Желательно иметь доступ к БД, чтобы быть точно уверенным, что тест корректный.

А именно – вводим все поля, выбирая логин, например, “а1”. А вот email указываем некорретный. Появляется сообщение об ошибке, мы ее исправляем и снова пытаемся зарегистрироваться. Но теперь нам выводится сообщение о том, что пользователь “а1” уже существует в системе! Но ведь он не был зарегистрирован!

Вот для того, чтобы в этом убедиться, нам и нужна БД – изначально делаем select, проверяя, что пользователя “а1” в системе нет. Потом регистрируем его так, чтобы регистрация не удалась, а потом корректно. И если мы видим сообщение об ошибке “пользователь “а1″ уже существует в системе” – смело идем и регистрируем багу. Так как при ошибочном вводе транзакция должна откатываться, а не сохраняться в БД.

Резюмируем:

  1. Обязательность полей.
  2. План-минимум.
  3. План-максимум.
  4. Юзабилити.
  5. Длина полей для ввода.
  6. Спец проверки для email.
  7. Спец проверки для даты.
  8. Корректный ввод после некорректного.

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

Например, “я люблю ходить в кино и поэтому, прочитав такие-то книжки, я решил попробовать свои силы на любимом сайте и провести функциональное тестирование системы. Я открыл формочку регистрации и провел такие-то и такие-то тесты. Сделал я это потому-то и потому-то. И даже баги нашел, представляете? Такие-то и такие-то. И даже в суппорт им написал, вот так-то и так-то (тут мы показываем, как умеем красиво, четко и понятно формулировать баги)“. Это будет показывать как минимум вашу заинтересованность, ваш энтузиазм и стремление учиться!

Просто попробуйте, открыть часто посещаемый сайт и попробовать его протестировать. Это поможет вам структурировать свои знания и чувствовать себя увереннее! А иначе получится так, что – приходишь на собеседование, четко рассказываешь заученные формулировки функционального и нагрузочного тестирования… А потом тебе дают простенькую формочку – “как будешь тестировать?”. И все, ты начинаешь волноваться, разом забываешь только что рассказанные определения, путаешься в показаниях и прочая прочая.

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

PS — и напоследок, еще одна бага из этого кинотеатра. Пришли мы в зал, места 9 и 10. Сели. И тут я смотрю перед собой – на спинках впереди-сидящих ведь тоже дублируются номера кресел. И что я вижу? После 9 идет 12 Smile :)


На самом деле там забавнее, идет такая нумераци – 8, 9 , 12, 11, 12. Но сфотографировать это не удалось, увы. Вот вам и еще одна бага! Зато забавная:

– У тебя какое место?
– 12.
– Тебе справа или слева? Smile :)

PPS — а еще про одну багу я писала позднее, на этот раз про бронирование билетов на сайте.

PPPS — добавила пост в общую копилку багов.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *