Disclaimer!
Я ни в коем случае не претендую на звание разработчика идеальной капчи, равно как и на изгобретателя чего-то нового. Все, что здесь написано, было сделано мной для познавательных целей и open source. И да, я осознаю, что написать свою капчу — это изобрести велосипед.
Совсем недавно я начал разрабатывать свой пока небольшой проект на ASP.NET MVC 3. Суть его заключается в том, что посетители могут добавлять на него свои сообщения, которые впоследствии появляются в публичном доступе (кому интересно, что стоит за этим запутанным объяснением — ссылка будет в конце).
Понятное дело, что раз речь идет о публичном проекте с возможностью постинга какого-либо контента на сервер, необходимо позаботиться о защите от спамеров и прочих неприятных личностей. Иными словами — нужна капча.
Первое, что пришло мне в голову, была ReCaptcha от Google. Установив ее и некоторое время попользовавшись, я окончательно понял, что этот монстр — совсем не для меня и не для большинства адекватных людей, тем более русскоязычных (вывод некоторых изображений не только не читается машинно, он и людьми то не может быть прочитан). Поискав другие решения, я, к своему сожалению, не нашел чего-то нормального для MVC 3, простого и ненавязчивого в использовании. Были разные мануалы как сделать то или иное, но готового решения «взял и использовал» как-то не встретилось. Поэтому решилизобрести велосипед написать свою капчу.
Поиски готовых решений хоть и не дали мне конечного результата, но подкинули мне идеи, как это все можно реализовать. Я решил, что капчу, как обычно мы ее видим (простое распознавание символов на картинке), я вряд ли сделаю качественной в виду простоты ее машинного разбора. В этом случае мне опять придется выбирать либо сложность чтения, либо слабую защиту. Поэтому я решил сделать капчу немного нестандартной, а именно выводить на изображение арифметические операции, чтобы пользователь подсчитал результат и ввел его в специальное поле. Стандартные анализаторы капчи в большинстве случаев вместо суммы и разности скорее подставят распознанный текст, что будет неверным результатом. Ну а уж если под эту капчу будут писать своего бота, то тут не спасет уже ничего.
Сказано — сделано. Недолго думая я создал в студии новый проект сборки (оформить капчу для одного единственного проекта в виде отдельной dll мне подсказало мое чувство хорошего тона и, как оказалось, не зря). В нем я создал класс с обычным методом расширения для HtmlHelper класса. Весь проект так и назвал тогда — SimpleMvcCaptcha.
Суть реализации такова. Хелпер случайно генерит два числа-операнда и одну операцию (пока только + или -). Исходя из этих параметров вычисляется результат. Затем происходят два финта ушами. Первый — мы должны создать изображение с выражением капчи. Однако внутри хелпера этого сделать нельзя. Поэтому нам необходимо создать тег img, источником картинки для которого станет специально подготовленный экшен специального контроллера, о котором ниже. Второй финт ушами — нам надо как-то сохранить информацию о результате, чтобы при последующем посте результатов на сервер не заниматься распознаванием собственной же капчи.
Сначала я хотел пойти по немного нестандартному пути в виду отсутствия богатого опыта. Дело в том, что большинство капчей, про которые я читал, передавали свои значения через кеш или сессии. Мне не очень понравилась такая идея, поэтому я решил хранить результат операции внутри html самой страницы с капчей в hidden поле. Но чтобы не упрощать жизнь анализаторам, данную строку я решил шифровать с помощью AES. Однако скоро мне помогли осознать, что в таком случае боту ничего не стоит подменить как хеш картинки, так и результат для нее, что моментально разрушит стойкость. Поэтому я все же пошел по пути большинства.
В сессии сохраняется небольшой объект, содержащий текст выражения для картинки и текст результата. Затем этот объект извлекается в двух случаях, при генерации изображения и при валидации пользовательского ввода.
Теперь о контроллере. В тех примерах, которые я находил, генерация изображения отдавалась на откуп специальным обработчикам наподобие .axd, .ashx. Я же решил, что пусть этим занимаются привычные нам контроллер и экшен. Тут у меня есть сомнения в правильности решения, поэтому жду критики и конструктивных замечаний на этот счет.
Валидация происходит тоже довольно просто:
Вот так выглядят примеры использования капчи. Как видите, хелпер генерирует изображение с текстом арифметического выражения (с рандомным цветом), также рандомно заменяет оператор + и — на текст (может задаваться в параметрах), а также предоставляет поле для ввода ответа. Все как у всех, поэтому его удобно использовать "из коробки".
Клиентский код выглядит так:
Большинство параметров, используемых в процессе генерации капчи, можно переопределить через web.config вашего ASP.NET MVC проекта. Из таких параметров можно выделить ширину и высоту изображения, размер и тип шрифта, текст-замена для + и — (на картинке сверху это третий кадр), максимальное число для использования в выражениях, наименование контроллера и экшена для выдачи картинки. Также можно кастомизировать CSS свойства элементов div, img и imput с помощью переопределения соответствующих классов.
Теперь то, почему я решил писать на хабр. Данная статья в своем названии упоминает про Open Source. Да, после того, как я реализовал данную капчу для себя, я решил, что неплохо было бы поделиться ей и с остальным сообществом. Это мой первый опыт open source разработки, поэтому он мне стал вдвойне интересен. Весь код, описание и документация выложены на CodePlex по адресу http://simplemvccaptcha.codeplex.com/ под лицензией GPLv2. Заходите, качайте, пользуйтесь.
Я очень надеюсь, что этот небольшой проект поможет вам при создании сайтов на основе ASP.NET MVC 3, в которых будет нужен функционал несложной капчи, которую легко распознать человеку, но поможет оградить от всяких ботов.
P.S. А тот проект, для которого это изначально писалось и о котором я говорил в начале, называется "Факты о программировании". Там пока не так много фактов, но я надеюсь, что в том числе и с вашей поддержкой проект будет активно развиваться!
Пример использования капчи можно найти на странице добавления своего факта. Убедительная просьба — если Вы заметили баг в капче или сайте, не пытайтесь его тут же сломать. Лучше сообщите мне и я его исправлю. Давайте будем конструктивными.
Я ни в коем случае не претендую на звание разработчика идеальной капчи, равно как и на изгобретателя чего-то нового. Все, что здесь написано, было сделано мной для познавательных целей и open source. И да, я осознаю, что написать свою капчу — это изобрести велосипед.
С чего все началось
Совсем недавно я начал разрабатывать свой пока небольшой проект на ASP.NET MVC 3. Суть его заключается в том, что посетители могут добавлять на него свои сообщения, которые впоследствии появляются в публичном доступе (кому интересно, что стоит за этим запутанным объяснением — ссылка будет в конце).
Понятное дело, что раз речь идет о публичном проекте с возможностью постинга какого-либо контента на сервер, необходимо позаботиться о защите от спамеров и прочих неприятных личностей. Иными словами — нужна капча.
Первое, что пришло мне в голову, была ReCaptcha от Google. Установив ее и некоторое время попользовавшись, я окончательно понял, что этот монстр — совсем не для меня и не для большинства адекватных людей, тем более русскоязычных (вывод некоторых изображений не только не читается машинно, он и людьми то не может быть прочитан). Поискав другие решения, я, к своему сожалению, не нашел чего-то нормального для MVC 3, простого и ненавязчивого в использовании. Были разные мануалы как сделать то или иное, но готового решения «взял и использовал» как-то не встретилось. Поэтому решил
Идея
Поиски готовых решений хоть и не дали мне конечного результата, но подкинули мне идеи, как это все можно реализовать. Я решил, что капчу, как обычно мы ее видим (простое распознавание символов на картинке), я вряд ли сделаю качественной в виду простоты ее машинного разбора. В этом случае мне опять придется выбирать либо сложность чтения, либо слабую защиту. Поэтому я решил сделать капчу немного нестандартной, а именно выводить на изображение арифметические операции, чтобы пользователь подсчитал результат и ввел его в специальное поле. Стандартные анализаторы капчи в большинстве случаев вместо суммы и разности скорее подставят распознанный текст, что будет неверным результатом. Ну а уж если под эту капчу будут писать своего бота, то тут не спасет уже ничего.
Реализация
Сказано — сделано. Недолго думая я создал в студии новый проект сборки (оформить капчу для одного единственного проекта в виде отдельной dll мне подсказало мое чувство хорошего тона и, как оказалось, не зря). В нем я создал класс с обычным методом расширения для HtmlHelper класса. Весь проект так и назвал тогда — SimpleMvcCaptcha.
Суть реализации такова. Хелпер случайно генерит два числа-операнда и одну операцию (пока только + или -). Исходя из этих параметров вычисляется результат. Затем происходят два финта ушами. Первый — мы должны создать изображение с выражением капчи. Однако внутри хелпера этого сделать нельзя. Поэтому нам необходимо создать тег img, источником картинки для которого станет специально подготовленный экшен специального контроллера, о котором ниже. Второй финт ушами — нам надо как-то сохранить информацию о результате, чтобы при последующем посте результатов на сервер не заниматься распознаванием собственной же капчи.
Сначала я хотел пойти по немного нестандартному пути в виду отсутствия богатого опыта. Дело в том, что большинство капчей, про которые я читал, передавали свои значения через кеш или сессии. Мне не очень понравилась такая идея, поэтому я решил хранить результат операции внутри html самой страницы с капчей в hidden поле. Но чтобы не упрощать жизнь анализаторам, данную строку я решил шифровать с помощью AES. Однако скоро мне помогли осознать, что в таком случае боту ничего не стоит подменить как хеш картинки, так и результат для нее, что моментально разрушит стойкость. Поэтому я все же пошел по пути большинства.
В сессии сохраняется небольшой объект, содержащий текст выражения для картинки и текст результата. Затем этот объект извлекается в двух случаях, при генерации изображения и при валидации пользовательского ввода.
/// <summary>
/// Captcha object
/// </summary>
internal class Captcha
{
/// <summary>
/// Result of captcha's expression
/// </summary>
public string Result { get; internal set; }
/// <summary>
/// Captcha's expression
/// </summary>
public string Expresion { get; internal set; }
}
Теперь о контроллере. В тех примерах, которые я находил, генерация изображения отдавалась на откуп специальным обработчикам наподобие .axd, .ashx. Я же решил, что пусть этим занимаются привычные нам контроллер и экшен. Тут у меня есть сомнения в правильности решения, поэтому жду критики и конструктивных замечаний на этот счет.
public class CaptchaController : Controller
{
public FileContentResult GetImage(string id)
{
return File(CaptchaUtils.GetImage(id), "image/gif");
}
}
Валидация происходит тоже довольно просто:
/// <summary>
/// Validates input
/// </summary>
/// <returns>true - validation succeeded \nfalse - validation failed</returns>
public static bool Validate()
{
var ctx = HttpContext.Current;
var captchaAnswer = ctx.Request.Form["captchaAnswer"];
var captchaHidden = ctx.Request.Form["captchaId"];
// If input is not empty
if(!String.IsNullOrEmpty(captchaAnswer) && !String.IsNullOrEmpty(captchaHidden))
{
var captcha = ctx.Session[captchaHidden] as Captcha;
ctx.Session.Remove(captchaHidden);
return captcha != null && captchaAnswer == captcha.Result;
}
return false;
}
Что получилось
Вот так выглядят примеры использования капчи. Как видите, хелпер генерирует изображение с текстом арифметического выражения (с рандомным цветом), также рандомно заменяет оператор + и — на текст (может задаваться в параметрах), а также предоставляет поле для ввода ответа. Все как у всех, поэтому его удобно использовать "из коробки".
Клиентский код выглядит так:
<div class="smc-captcha">
<img src='/Captcha/GetImage/08a75516-f1ed-41ca-a926-724a268f171e' alt='captcha' class='smc-img-captcha' ><br/>
<input type='hidden' name='captchaId' value='08a75516-f1ed-41ca-a926-724a268f171e' />
<input type='text' name='captchaAnswer' class='smc-input-result' />
</div>
Кастомизация
Большинство параметров, используемых в процессе генерации капчи, можно переопределить через web.config вашего ASP.NET MVC проекта. Из таких параметров можно выделить ширину и высоту изображения, размер и тип шрифта, текст-замена для + и — (на картинке сверху это третий кадр), максимальное число для использования в выражениях, наименование контроллера и экшена для выдачи картинки. Также можно кастомизировать CSS свойства элементов div, img и imput с помощью переопределения соответствующих классов.
Open Source
Теперь то, почему я решил писать на хабр. Данная статья в своем названии упоминает про Open Source. Да, после того, как я реализовал данную капчу для себя, я решил, что неплохо было бы поделиться ей и с остальным сообществом. Это мой первый опыт open source разработки, поэтому он мне стал вдвойне интересен. Весь код, описание и документация выложены на CodePlex по адресу http://simplemvccaptcha.codeplex.com/ под лицензией GPLv2. Заходите, качайте, пользуйтесь.
В заключение
Я очень надеюсь, что этот небольшой проект поможет вам при создании сайтов на основе ASP.NET MVC 3, в которых будет нужен функционал несложной капчи, которую легко распознать человеку, но поможет оградить от всяких ботов.
P.S. А тот проект, для которого это изначально писалось и о котором я говорил в начале, называется "Факты о программировании". Там пока не так много фактов, но я надеюсь, что в том числе и с вашей поддержкой проект будет активно развиваться!
Пример использования капчи можно найти на странице добавления своего факта. Убедительная просьба — если Вы заметили баг в капче или сайте, не пытайтесь его тут же сломать. Лучше сообщите мне и я его исправлю. Давайте будем конструктивными.