company_banner

Легко ли научить робота проходить тест для программистов?

    Из этой статьи читатель узнает о том, как написать робота, проходящего тесты, и немножко «разомнет мозги» в теории вероятностей, разбираясь вместе с автором, почему при кажущейся сложности задачи автоматический подбор решения сходится за очень короткое время. Предупреждение: половина статьи ― «матан».

    Введение


    Несколько лет назад я сделал тест для программистов, который многим, скорее всего, не понравится. Если вы пишете на языке PHP, ваша любимая СУБД ― MySQL, а в качестве операционной системы вы предпочитаете Linux ― попробуйте его пройти. Заранее предупреждаю, тест своеобразный. Успешно его проходит всего несколько процентов испытуемых. Так что не стоит переживать. Если вы его не пройдете ― ничего страшного. Тест «заточен» под определенные навыки, которые требуются далеко не везде.

    Получить отличный результат в тесте сложно. Поэтому некоторые испытуемые прибегают к черной магии ― пишут бота. Хорошее дело, между прочим. «Настойчивость и храбрость, отвага и удача, в беде не растеряться ― вот главная задача!» Поэтому капчи в тесте не было. Никогда. Наоборот, мне хотелось, чтобы ботов писали. Чтобы боты приходили. Чтобы тест выстоял, боты обломались, а «ботописатели» не жульничали, а учились.

    В тесте 80 вопросов, из которых для каждого испытания случайным образом выбирается 25. У меня был простой (и, как потом выяснилось, абсолютно неверный) расчет. Чтобы тест нельзя было пройти, заучив или подобрав ответы, общая база вопросов изначально должна быть существенно больше, чем количество вопросов в одном испытании. Общее количество комбинаций тестов составляет число порядка 1020. «Раз число такое большое, значит, и подобрать ответы будет очень сложно», ― думал я. Конечно, число сочетаний ― очень грубая оценка. Но задача автоматического подбора интуитивно казалась мне если и решаемой, то такими затратами, на которые ботописатель не пойдет. Думать так было большой ошибкой. Битву с ботами я проиграл. Дальше расскажу, почему.

    Атаки


    Всех атак, конечно, сейчас и не вспомнить. Успешных было две ― о них и пойдет речь.

    Первый успешный подбор был тривиальным (не считая миллиона http-запросов, но это мелочи). Подбор стал результатом моей глупой ошибки. Его осуществил мой знакомый, Игорь Ш. Однажды я увидел его фамилию на первом месте в рейтинге. С очень высоким баллом и временем прохождения теста в районе 5 секунд. Я позвонил ему и спросил, как он это сделал.

    Сначала Игорь попробовал решать задачу подбором. Как я уже написал, парень он оказался весьма упорный, в логах было около миллиона запросов. Но задача была сложнее, чем казалась вначале ― подбирать было слишком долго. И вдруг нашлась «дырка». Оказалось, что можно передавать заведомо неверный ответ, который будет принят и засчитан как неверный, а тест перейдет к следующему вопросу. Это позволяет подбирать ответ на конкретный вопрос, отвечая на все остальные заведомо неверно. Множество вариантов для перебора становится ничтожным, а задача ― элементарной.

    Бот Игоря был первым, кто прошел тест. Баг я исправил, Игоря из рейтинга пришлось удалить. Все остальные атаки успешностью не отличались. Прошло несколько скучных лет, пока не появился Семен К.

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

    В середине ноября 2013 года с какого-то швейцарского хостера прилетели двести пятьдесят тысяч запросов. Уже на второй день бот красовался в рейтинге на первых местах и продолжал дальше. 250 000 запросов, примерно 10 000 прохождений теста ― и на первом месте. Это меня совершенно смутило. Почему так быстро? Какое там число сочетаний, какие 1020, подбор сошелся значительно быстрее! Неужели опять какой-то баг? Если нет, то как я мог так ошибиться в оценке?

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

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

    У меня уже не было сомнений, что надо ставить капчу. Но как я мог так сильно недооценить адаптивный подбор? Почему такая сходимость, всего 10 000 запросов? Короче, пришлось взять ручку, листок бумаги и думать.

    Оценка сходимости


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

    Для начала мы воспользуемся методом, на который меня натолкнул коллега из лондонского офиса, Евгений Кучера. Он предложил смотреть на задачу как на решение системы случайных линейных уравнений: каждое прохождение теста дает одно уравнение вида «сумма таких-то ответов на такие-то вопросы равна такому-то результату». Каждое прохождение теста дает +1 уравнение. Для простоты будем считать, что каждый вопрос имеет по 5 вариантов ответа. Все уравнения линейные, и система может иметь решение, если число независимых уравнений будет равно числу неизвестных. Число неизвестных ― это, грубо говоря, число вопросов, помноженное на число вариантов ответов, N = 80*5 = 400. А необходимая зависимость уравнений ― нюанс, возможно, знакомый читателю из курса линейной алгебры. Нельзя просто так получить первые же N уравнений и считать, что система имеет решение: одно уравнение может быть линейной комбинацией других уравнений, не нести никакой дополнительной информации. Но мы схитрим и просто покажем на пальцах, что за число тестов порядка N не получить систему независимых уравнений ― тут надо очень постараться.

    Действительно, после того как число испытаний M превысит N = 400, число возможных комбинаций из уравнений будет расти как число сочетаний из N по M, то есть невероятно быстро. Уже при M = 2N это число будет составлять (2*400)!/(400!)2. И это очень большое число, без специальных ухищрений его уже даже не посчитать из-за переполнения обычных 64-битовых типов с плавающей точкой double, оно превышает 10+308. При этом скорость «перемешивания» вопросов тоже очень большая: вероятность встретить в одном тесте любую пару вопросов невелика, это примерно (25/80)2 = 0.0977, но уже при M = 2N испытаний вероятность не встретить эту пару ни в одном испытании равна (1 — 0.0977)2*400 = 10-36! Таким образом, вероятность того, что среди M>2N испытаний мы сможем выбрать такие N уравнений, чтобы с одной стороны там были все переменные, а с другой стороны система была независима, очень большая. Более строгое доказательство можно провести через анализ детерминанта случайной квадратной матрицы из нулей и единиц, но математические упражнения такого уровня выходят за рамки этой статьи, к тому же я попросту не уверен в том, что в состоянии достойно завершить это интеллектуальное путешествие.

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

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

    Суть метода в следующем: бот отвечает совершенно случайно, но учитывает только те испытания, которые дали результаты с определенным количеством баллов. Чтобы метод заработал, это определенное количество баллов должно быть больше наиболее вероятного (на самом деле, можно и меньше, лишь бы заметно отличалось). Каждому использованному варианту ответа прибавляется вес ― получается рейтинг гипотез о правильности вариантов ответов. Со временем правильные ответы получают высокий рейтинг, а неправильные ― низкий, и правильные ответы можно легко отличить от неправильных. Звучит странно, да и поверить в это дело с первого раза сложно. Покажем подробнее, как работает метод.

    Рассмотрим вероятность выпадения определенного количества баллов s в тесте из n вопросов — p (s, n). Для простоты будем считать, что каждый вопрос имеет одинаковое число ответов m, все ответы — случайные. В этом случае вероятность угадывания ответа или выпадения единицы P(1) = 1/m, а вероятность неверного ответа, или выпадения нуля, P(0) = (m — 1)/m. Искомая вероятность выпадения s баллов ― что-то типа числа сочетаний из s по n, да еще с какими-нибудь множителями типа P(1) в степени s и P(0) в степени n — s (вероятность выпадение s раз единицы и n — s раз нуля умножаем на общее число комбинаций). Не утомляя пока читателя формулами, приведем график вероятности для n = 24 (почему 24, а не 25, расскажем позже):



    Теперь применим метод пристального всматривания к следующему выражению:

                          p (s, n) = p (s — 1, n — 1) * P(1) + p (s, n — 1) * P(0)                  (1)

    Физический смысл этого выражения следующий: вероятность того, что в тесте из n вопросов выпадет s баллов, равна сумме вероятностей двух событий:
    • на предыдущем (n — 1) шаге выпало s — 1 баллов, и затем выпала единица
    • на предыдущем (n — 1) шаге выпало s баллов, и затем выпал ноль

    И теперь самое интересное. Напомним, наш бот работает следующим образом:
    бот учитывает только те испытания, которые дали ровно s баллов;
    каждому варианту ответа в таких испытаниях бот прибавляет в специальном рейтинге +1.

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

    Итак, чтобы метод заработал, нам нужны такие s, чтобы вероятность выпадения единицы была «заметно» больше вероятности выпадения одного из нулей:

                                     p (s — 1, n — 1) > p (s, n — 1)                                 (2)

    Снова взглянем на распределение (теперь должно быть понятно, почему это распределение для n — 1 = 24, а не для n = 25). Видно, что искомые s расположены справа от максимума распределения s = 5. Интересно, что слева от максимума выполняется обратное условие: вероятность выпадения единицы заметно меньше, поэтому при расчете рейтинга только для испытаний с таким числом баллов рейтинг правильного ответа будет заметно меньше, и правильный ответ будет так же легко отличим от неправильных.

    Таким образом, бот может фиксировать сумму баллов слева от максимума распределения, например для s = 6. Если каждый вариант ответа попадется нам хотя бы несколько десятков раз, то рейтинг правильного ответа и неправильного будет заметно отличаться. Это, конечно, снова нестрогая оценка, но нет желания занудствовать насчет погрешности ― считаем, что за несколько десятков испытаний погрешность будет уже несущественна. Теперь оценим число испытаний, при котором верные ответы определяются с достаточной точностью.

    Для этого нам всё-таки придется записать формулу вероятности ответа ровно на s баллов в серии из n вопросов, где в каждом вопросе есть m вариантов ответа. Число вариантов испытаний, которые дадут s баллов ― это произведение числа сочетаний s из n вопросов C(n, s), в которых мы угадаем ответ, и числа вариантов расположить неверные ответы в оставшихся позициях (m — 1)n — s, ведь неправильных ответов на каждый вопрос останется m — 1, а позиций ― n — s. Общее число комбинаций ― mn. Отношение числа годных комбинаций к общему числу и есть искомая вероятность:

                                     p (s, n, m) = n!/(s!(n-s)!) * (m-1)n-s /mn                                 (3)

    Внимательный читатель может проверить эту формулу иначе: это вероятность встретить s единиц P(1)s = m-s и n — s нулей P(0)n — s = ((m — 1)/m)n — s, помноженная на общее число комбинаций ― число сочетаний из n по s.

    Вернемся к оценке сходимости. Допустим, мы зафиксировали число баллов s = 6. Вероятность выпадения 6 баллов в тесте из 25 вопросов по 5 вариантов ответов по формуле (3) равна 0.163. Следовательно, чтобы набрать 1 «годное» испытание, надо прогнать тест примерно 1/0.163 = 6 раз. Каждый вариант ответа надо прогнать по несколько десятков раз, пусть это будет 30. Тогда каждый вопрос должен встретиться 5*30 = 150 раз. Вероятность встретить определенный вопрос в тесте ― 25/80 = 1/3.2, и значит, очень приблизительно для поиска всех ответов нужно пройти 6 * 150 * 3.2 =~ 3000 тестов!

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



    Выводы


    Мы убедились, что написать бота ― дело несложное, все рассмотренные методы показывают очень хорошую сходимость. Вернемся на светлую сторону и зададимся вопросом: как усложнить жизнь «ботоводу»?

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

    Во-вторых, нужно увеличивать общую базу ответов. Правда, сходимость решений линейная. И для бота что 100 вопросов, что 1000 вопросов ― вычислительная сложность будет отличаться несильно, а составить 1000 вопросов ― большой труд. Тем не менее, базу вопросов лучше иметь как можно больше. База моего теста постоянно растет, и вы можете помочь в этом деле за вознаграждение (все подробности можно выяснить в личной переписке).

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

    Есть одна трудность: неточный результат входит в противоречие со здравым смыслом. Допустим, мы разделили результаты на уровни, например, от «Новичка» до «Эксперта». Этих уровней не может быть два-три, их должно быть не менее пяти. Иначе зачем пользователю проходить тест, который дает совсем уж неточный результат? Но даже в случае ответа в виде уровня адаптивный бот все равно может сходится. Связано это с тем, что адаптивный алгоритм хорошо работает не только на каком-то точном числе баллов, но и на интервале типа s > const, где const ― наиболее вероятное число баллов, максимум распределения. На всем этом интервале вероятность монотонно убывает, а это, как было показано выше, достаточное условие сходимости адаптивного алгоритма. Остается только одно: подобрать такие разделения на уровни, чтобы, с одной стороны, их было достаточно, чтобы тест выглядел вменяемым, а с другой ― чтобы полностью автоматический адаптивный переход с одного уровня на другой был бы практически невозможен.

    Вспомним распределение для модели 25 вопросов по 5 вариантов ответа: вероятность правильного случайного ответа на 12 вопросов и выше ― ничтожная. Что если сделать первый уровень, скажем, с 12-ти баллов, или даже выше? Тогда все наиболее вероятные испытания дадут лишь один ответ: «Не прошел», и бот с «холодного» старта не заработает. Если делать следующую границу уровня достаточно далеко, то продраться с уровня на уровень можно будет только при дополнительном разделении вариантов ответов на «Скорее всего верные» или «Скорее всего неверные», то есть ботовод должен помогать своему боту самостоятельно, обучаясь в процессе. А это уже само по себе неплохо.

    Вот и все выводы. Если у вас есть еще идеи, как защитить тесты от роботов, будет интересно увидеть их в комментариях.

    Алексей Рыбак, Badoo
    Badoo
    256,00
    Big Dating
    Поделиться публикацией

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

      +7
      Я бы задал все предложенные вопросы на Тостере и получил правильные ответы.
        0
        Нельзя просто так взять и получить правильные ответы на вопросы ;)
        Для некоторых вопросов из этого теста требуется уточнение контекста. Например, вопрос про экранирование символов перед вставкой в базу данных для защиты от SQL-Injection. Какие функции для этого подходят? addslashes, например, для одних кодировок годится, а для других нет (подробнее тут).
        +3
        У меня уже была идея написать бота под этот тест по последнему варианту, но когда поставили каптчу, то понял, что уже кто-то воспользовался этим, поэтому интерес пропал.

        Предлагаю следующие варианты защиты теста:
        — Ввод чисел в качестве ответов (например, задачи по результирующий набор данных при джойнах или в задачках типа «что будет результатом работы скрипта»)
        — Варьировать количество общих ответов и правильных ответов на вопрос.
        — Изменять текст в вопросах и ответах, чтобы сложнее было технически привязаться.
        — Добавить вопросы вида «введите название функции, которая делает ...»

        PS: Кстати существуют распознавалки recaptcha. Там вероятность хоть и не очень высокая, но для автоматического перебора хватает. Добавьте еще интервал между ответами и бан на N минут в случае, если отвечают очень быстро. Ну и бан по IP на частый неправильный ввод каптчи.
          +7
          Кстати можно добавить элементы фана:
          В случае, если с одного IP было много тестов за последние 24 часа, то вставлять в тест вопросы с отсутствием правильных ответов, непрофильные вопросы («Какого цвета зебра?»), а в результатах теста говорить о том, что «За сегодня вы уже славно потрудились, поэтому ваш балл мы не покажем. Держите просто красивую циферку: rand(1,100)»
            0
            И любой институт за NAT-ом убъёт день экзамена, если рискнёт экзамен замутить через этот тест, да?
            +1
            Методом, который я привёл — никто не воспользовался пока. Я его сам придумал, пока пытался оценить сходимость адаптивного метода. Что касается Ваших советов, они все по делу, спасибо.
            +1
            Может проще ограничить количество прохождениq теста с одного IP?
              +5
              Переборщики теста с динамическим IP радуются этому комментарию
                +1
                Лучше тогда просто по авторизации. Один пользователь — один тест с интервалом растущим. Плюс каждому пользователю давать кроме стандартного набора ещё пару вопросов конкретно для этого аккаунта.
                  +1
                  Ну при нынешнем автоматическом гуглении прокси-листов, это просто смешная защита
                  +3
                  Алексей, спасибо за статью)) Засел за написание бота, который сможет пробить защиту)
                    0
                    приходите! жду
                    +4
                    Впервые про меня пишут на хабре :-)
                      +1
                      Уберите капчу, она отпугнет людей, а не ботов.
                      Для ботов придумывайте стратегии их определения и нейтрализации.
                      Этим вы будете повышать не только свои умения/знания, но и чужие — ботописателей.
                        +1
                        Капчи бояться — в Интернет не ходить!
                        0
                        Супер, очередной пример того, что человеческая интуиция постоянно делает ошибки на порядки, когда речь заходит о вероятностях.

                        10^4 прохождений с капчей — это 7 долларов на антигейт аккаунт, так что защита так себе ;) Отсутствие четкого фидбека — да, вариант, но тогда пузомерку с рейтингом придется убить.
                          0
                          Пол-цента за капчу, да, но послушай: это же надо значительно сильнее заморочиться :) Что касается пузомерки: её и так пришлось ограничить из-за хэд-хантеров, так что со временем топскор сделаем и всё.
                          С новыми тестами (у меня куплено уже под сотню новых) наверняка четкий фидбек уберу — это самое действенное.
                            0
                            С отсутствием четкого фидбэка можно добавить простейший бот-детектор, при срабатывании которого результат теста всегда будет отрицательный. Детектор должен быть именно что тупой, но zero false positive для реального user-agent.
                          0
                          Есть гипотеза, как можно модифицировать идею с рейтингом ответов. Пусть изначально все ответы имеют равный рейтинг 0,2. При каждом тесте ответ на конкретный вопрос выбирается случайным образом, вероятность выбора конкретного ответа равна его рейтингу… Если тест прошел «удачно», то рейтинг использованного ответа повышается (соответственно, рейтинги остальных ответов понижаются). Если тест прошел «плохо», то рейтинги использованный ответов понижаются. Причем чем лучше/хуже результат теста, тем сильнее повышаются/понижаются рейтинги. Есть предположение, что такой алгоритм будет сходиться быстрее, но это только предположение.
                          Также мне кажется, что тут могут неплохо генетические алгоритмы сработать, но с хитрой процедурой скрещивания, учитывающей только те гены (вопросы), которые были в конкретном тесте.
                            0
                            Отличные доподнения, спасибо! Насчет модификации: возможно, но у меня не было цели найти наиболее эффективный алгоритм, я просто хотел показать математически, как интуиция подводит :) Что касается генетических алгоритмов: именно с них я и начал, но там тяжело показать сходимость. Фактически я случайно придумал вот этот другой способ, и он оказался куда более наглядным.
                            0
                            Против расплывчатого фитбека на помощь приходит регрессионный анализ. Аналогично, решению СЛАУ, каждый вариант ответа — это случайная величина. Задача сводится к нахождению коэффициентов линейной регрессии, например, методом наименьших квадратов. Это ничуть не сложнее, чем искать решения линейного уравнения. Лично я бы начал писать своих ботов с этого метода.

                            Отличить же ботовода я предложил бы анализируя время ответа или поведение на сайте (что чуть сложнее).
                              0
                              Погоди. Если у тебя каждый вариант ответа — случайная величина, то скорее всего при четких баллах ты попадешь в интервал от 0 до 12. А теперь представь, что тебе вместо 0...12 будут отвечать всегда одно «не прошел». Какая регрессия? У тебя просто нет информации, никакой. Весь прикол не в том, что метод не сработает — сработает и тот же адаптивный — а в том, что требуется значительно бОльшее число испытаний, чтобы получить «разные» варианты.
                                +1
                                Почему нет информации? Да же если на выходе будет всего два варианта (да/нет), то этот метод будет вполне эффективен. Если есть хоть какая-то корреляция между ответами и конечным результатом, то метод найдет коэффициенты.
                                Но конечно же, и это вполне очевидно, что для получения более ли менее вменяемого результата понадобиться проводить больше испытаний.
                                Но вопрос в том что сам метод (как и решение СЛАУ) очень прост. Также уверен что в данном случае он будет значительно эффективнее каких-нибудь генетических алгоритмов в чистом их виде.
                                  0
                                  Почти все все ответы будут «нет» = нет информации. Чтобы было «да» — нужно сильно больше испытаний. Можно так подобрать разделение на уровни, что ждать надо будет _очень_ долго. Но ты прав про регрессионный анализ, он не сложнее решения уравнений, и будет работать.
                              0
                              На самом деле для версии теста без каптчи есть еще более быстрый вариант:
                              Поскольку неверных ответов больше, чем верных, то мы можем искать именно неверные ответы, отвечая по одному ответу в каждом вопросе.

                              Запускаем первичный перебор тестов:
                              1. Если в результате мы получили 0 баллов, значит на все вопросы ответили неверно. Такие события будут происходить довольно часто: только сейчас в трех тестах выбирал только первые ответы и в одном набрал 0 баллов.
                              2. Если в результате мы получили > 0 баллов, значит где-то мы ответили правильно — такие результаты нам пригодятся.

                              После каждого теста, используя информацию об уже выявленных правильных ответах и статистику по 2му пункту (где тесты были > 0 баллов), мы сможем быстрее выяснить ответы по остальным вопросам.
                              Таким образом мы выявим ответы на вопросы, в которых правильным является 1 ответ.

                              Запускаем вторичный перебор тестов для выявления ответов на вопросы, в которых более 1 ответа:
                              Зная вопросы с одним ответом и используя статистику по 2ому пункту первичного перебора мы сможем адаптивным методом быстрее выявить ответы на «правильные вопросы с несколькими ответами».

                              В математику вдаваться не стал, но потребуется явно меньше 10^4 переборов.

                              Можно изначально руками пройти несколько тестов, выбирая заведомо неверные ответы, для получения 0 баллов. На такой «ручной» статистике данный метод отработает еще быстрее.
                                0
                                Проблема с тем тестом была в том, что 0 баллов никак не получалось набрать. Возможно там есть защита на этот случай, что если баллов меньше 7 — то выдавать случайное число от 0 до 7 (или другого минимального числа)
                                  0
                                  Как же это у меня получилось в 1 случае из трех?
                                    0
                                    Возможно я плохо пытался. Тогда вообще проблемы нету — держим базу неверных ответов и подбираем ответы на вопросы по-очереди. То есть в начале один вопрос перебираем а все остальные варианты берём неверные ответы.

                                    Кстати вот пример дополнительной защиты — если пользователь набрал меньше 5 баллов. То не говорить ему сколько баллов, просто писать что-то вроде «вы не прошли».
                                      0
                                      Я как раз примерно это и описал в своем комментарии ;)
                                        0
                                        да, я в-общем сделал две вещи пока: капча + для маленького результата ничего не показываю.
                                          0
                                          Тогда метод с поиском неправильных ответов уже не прокатит, но у меня есть еще пара идей.
                                  0
                                  Это все варианты адаптивных методов, решение должно работать. Но думаю, что Вам только кажется, будто сходимость будет лучше. Именно потому, что «в математику вдаваться не стал».
                                    0
                                    Окей. Попробую реализовать данный метод, о результатах отпишусь здесь.
                                    0
                                    Спасибо, не знал что всё так просто вскрывается…
                                      0
                                      Вообще, идея для бота рейтить ответы фактически по степени влияния на цифру результата теста — это круто! Это как раз пример «взгляда с правильной стороны» и «решения задачи путём её переформулирования».
                                        +1
                                        Спасибо за статью, с меня небольшое предложение относительно определения бота.
                                        По своей сущности большинство ботов — парсят DOM и заполняют поля для ввода стандартными значениями. Можно сверстать страницу так, что форма будет включать скрытые посредством верстки поля, которые будут пропарсены ботом. Плюс к умным ботам, они могут определять какие поля являются обязательными (можно использовать этот факт). Вполне возможно данный аспект можно использовать и проверять наличие скрытых полей при проверке форм, пришедших от пользователя.
                                        Я не владею информацией относительно того, можно ли определить фингерпринт браузера для бота, но для реального пользователя в некоем варианте это тоже может являться меткой на уникальность и проверкой на подлинность.
                                          0
                                          Вы правы, что такой метод определения ботов может сработать, но в нашем случае форма очень простая и всего одна, так что скорее всего бото-писатель напишет не код, который старается автоматом пробиться через форму (как это может сделать поисковый бот, например) — а будет запрограммирован так, чтобы передавать только нужные поля.

                                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                        Самое читаемое