Распознаём изображение с токена при помощи камеры

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

    и сказали: жмёшь кнопку, смотришь цифры, вводишь пароль и радуешься. «Безопасность, конечно, превыше всего, но и о комфорте забывать не следует» — примерно так подумал я и провёл ревизию имеющегося у меня электронного хлама.

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

    Анализ технического задания и подбор компонентов



    Первым делом на глаза мне попалась старая веб-камера «Logitech QuickCam 3000», отправившаяся в «хлам» в связи с покупкой ноутбука со встроенной веб-камерой. План созрел моментально: снимаем камерой циферки с токена, распознаём их на компьютере и… Профит! Дальше был найден сервопривод (ну не нажимать же кнопку на токене каждый раз руками, правда?), старый USB-хаб (в моём ноутбуке всего два USB-порта, и один из них постоянно занят USB-Ethernet адаптером), и плата Arduino, неизвестно каким образом у меня оказавшаяся. В качестве корпуса для своего девайса я решил использовать конструктор «Лего», купленный впрок моему годовалому сыну (кажется, теперь я понимаю, почему жена ехидно ухмыльнулась при покупке).

    К сожалению, фотографий донорских девайсов в целости и сохранности у меня нет, поэтому я могу «похвастаться» только устройством в сборе:



    Принципиальная схема и прошивка микроконтроллера



    Собственно, всё до смешного просто (я даже схему рисовать не буду): USB-хаб, к которому подключена веб-камера и ардуина. К ардуине подключен сервопривод (через ШИМ). Вот и всё.Исходный код программы, которая заливается в ардуину, тривиален: github.com/dreadatour/lazy/blob/master/servo.ino
    Ардуина ждёт букву 'G' на ком-порт, и при её поступлении дёргает серву туда-назад. Задержка (500мс) и угол наклона сервы были подобраны экспериментальным путём.

    Выбор языка программирования и анализ существующих библиотек «компьютерного зрения»



    Единственным языком программирования, которому бы я доверил такую сложную задачу, как «компьютерное зрение» — благославленный Python. Благо в нём, практически из коробки, есть биндинги к такой славной библиотеке, как OpenCV. Собственно, на этом и остановимся.

    Алгоритм распознавания кода токена



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

    Для начала берём изображение с камеры:


    Облегчаем себе задачу: камера неподвижна относительно основы, токен может двигаться в своём лотке совсем незначительно, поэтому находим границы возможных положений токена, обрезаем кадр с камеры и (исключительно для нашего удобства) поворачиваем изображение на 90˚:


    Дальше делаем некоторые преобразования: конвертируем получившееся изображение в grayscale и находим границы с помощью детектора границ Канни — это будут границы ЖК-экрана токена:


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


    С помощью тупого алгоритма определяем четыре линии, ограничивающие наш ЖК-дисплей:


    Находим точки персечения этих линий и выполняем несколько проверок:
    • проверяем, чтобы длина вертикальных и горизонтальных линий примерно совпадала друг с другом и чтобы длина линий примерно совпадала с размером ЖК-дисплея (который мы вычислили экспериментальным путём)
    • проверяем, чтобы диагонали были примерно равны (нам нужно прямоугольник — ЖК-дисплей)

    Далее находим угол, на который повёрнут наш токен, поворачиваем изображение на этот угол и вырезаем изображение ЖК:


    Самое сложное позади. Теперь нам нужно повысить контрастность полученного изображения. Для этого мы запоминаем изображение пустого ЖК-экрана (до нажатия на кнопку токена), и просто «вычитаем» это изображение из картинки с цифрами (после нажатия на кнопку):


    Получаем чёрно-белое изображение. Для этого с помощью ещё одного тупого алгоритма находим оптимальный порог, который будет разделять все пиксели на изображении на «чёрные» и «белые», конвертируем изображение в Ч/Б и вырезаем символы:


    Ну а дальше просто распознаём цифры. Нам нет смысла мучаться с нейронными сетями и прочими штуками, т.к. у нас семисегментный индикатор: есть семь «точек», по которым однозначно определяется каждая цифра:


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

    Видео работы девайса


    Осторожно, звук!


    Исходный код целиком
    Поделиться публикацией
    Ой, у вас баннер убежал!

    Ну. И что?
    Реклама
    Комментарии 59
      +12
      Dreadatour — молодец!
        –3
        Отлично сделано. Ждем коммерческую версию :)
        +1
        Я так и не понял как «из коробки» начать работать с опенцв в питоне… :-( Как?
          +2
          всё предельно просто:
          brew install opencv

          а дальше
          import cv

          и поехали…
            0
            почти
            тока brew неизвестно что такое. Гугл ищет софт для пивоварения. А вот это меня вообще сделало бояться:
            «To cut this short, here is what you need to get that Python running: brew install python»

            Кто такой брю?
              +2
              Брю это пакетный менеджер для мака. Вам нужно наверно apt-get install opencv
                +7
                Он признался, у него виндовс
                  0
                  Я еще даже не начинал признаваться…
              0
              bluehat.me/blog/2011/09/10/python-installation-via-homebrew/
              А, блин, это что-то линуксовое…
              Под виндой у меня траблы. Под 7-кой.
                0
                А…
                о… Homebrew is the easiest and most flexible way to install the UNIX tools Apple didn't include with OS X.
                  +9
                  Про windows ничего не знаю, извините
                    0
                    На Win просто устанавливается пакет путём загрузки необходимого исполняемого файла. Собственно, ниже ссылочки дали.
                  0
                  Во-во, самый лучший вариант. Да помимо OpenCV там ещё куча разных библиотек есть.
                    –3
                    я крутой, у меня python 3
                    +3
                    Мне кажется что этому девайсу надо сделать стенки чтобы не было бликов на экране от окон и пр. + добавить подсветку (например светодиодом запитанным от той-же ардуины) во время съёмки…
                    А так — очень даже интересно… правда нагляднее было бы всё-же с кодом в статье, а не по ссылкам :)
                      +2
                      Стенки делать нет смысла, т.к. бликов не бывает — камера строго перпендикулярна ЖК-экрану, поэтому бликовать там нечему.
                      А вот тень от краёв «окошка» экрана иногда мешает распознавать картинку — тут вы правы, нужен светодиод. Я даже экспериментировал с подключенным через второй ШИМ (для управления яркостью) светодиодом, но вмечатляющих результатов не добился — если направлять светодиод строго в экран, он очень сильно бликует, если же подсвечивать экран сбоку, появляется та же тень. Нужен рассеиватель.

                      В общем, надо думать, экспериментировать, а мне, если честно, уже лень ;)
                        +1
                        два диода с двух сторон и белая бумага в качестве рассеивателся.
                      –4
                      Если б Вам разрешили разобрать токен, то можно б было обойтись одной ардуиной — узнавать цифры с помощью анализа напряжений на выводах ЖК дисплея.
                      Но вот мощности ардуины не хватит представиться USB-клавиатурой (чтоб ввести пароль в домен)
                      Хотя Ваша конструкция напоминает считыватель TouchMemory с привязанной к нему скотчем таблеткой — профанация всей идеи безопасности…
                        0
                        Никто не мешает забирать токен с собой, покидая рабочее место, что, думается мне, и было специально предусмотрено конструкцией.
                          +1
                          Ну разобрать токен, не так уж и просто, как кажется на первый взгляд, об этом позаботились его разработчики.
                            +8
                            Разобрать токен никто не даст.
                            Да и «анализировать напряжение на выводах ЖК дисплея» сильно сложнее моей поделки, если честно.

                            Ардуина тут вообще, фактически, для красоты, как на известной картинке. Если бы была нужна USB-клавиатура, никто не помешал бы мне взять нормальную AVR'ку (или даже ARM) и сотворить всё, что душе угодно.

                            Кто куда привязан? Какая профанация? Ничего не понял. Вот, на всякий случай, ещё одна фотка, — возможно, вы не так всё поняли.

                            0
                            а зачем распознавать? у нас для такого же просто фотки с вебкамеры на http-сервер выкладываются
                              +1
                              Ну чтобы надо зайти на сервер — нажал хоткей, дождался распознавания, нажал «вставить» в поле пароля и всё.

                              А у вас зачем фотки на http-сервер выкладываются? о_О
                                –1
                                открыл закладку — посмотрел пароль, ввел
                                  +5
                                  Ууу, это долго. Так можно и взять токен в руку, посмотреть пароль, ввести. А мне так лень )
                                    +3
                                    токен на другом континенте :)
                                      +3
                                      спросонья не понял шутки =)

                                      а как же безопасность, все дела? теряется весь смысл токена
                                        +2
                                        Адрес сервера меняется каждые две минуты.
                                          +16
                                          и чтобы его узнать, нужен еще один токен :)
                                +1
                                для минимизации телодвижений, надо ещё после распознания автоматически вставлять текст в активное поле ввода
                                +17
                                Пожалуй, пора делать токен в виде каптчи — смазанной и прыгающими цифрами
                                  +13
                                  Только нашим безопасникам не говорите, пожалуйста? ;)
                                    +1
                                    А еще лучше загадку или ребус. Условие, естественно, замазать как в каптче.
                                      +1
                                      Это только ускорит популярность таких кустарных приборов.
                                      Капчи гораздо проще распознавать алгоритмом, чем глазом.
                                      0
                                      Скажите, пожалуйста, а как вы освоили OpenCV под Python?

                                      Я пишу курсовую по обработке изображений. Но OpenCV я как-то не потянул — не нашел толковых мануалов. В итоге ограничился достаточно простым но банальным PIL :(
                                        +2
                                        У OpenCV не самая лучшая, но достаточно внятная документация с хорошим поиском (пример запроса по уловию «Canny»).

                                        В исходниках OpenCV можно найти замечательные примеры (директория «samples») — на питоне в том числе.
                                        Я просто грепал название нужной мне функции в этой директории и находил примеры использования.

                                        Ну и google (который, зачастую, выводил меня на stack overflow).
                                          +1
                                          Learning OpenCV. Где взять в оригинале, сами знаете. Есть ещё фанатский русский перевод.
                                          +4
                                          Веб камеры довольно шумные, особенно если освещённость не очень. Качество картинки можно улучшить интегрированием — ну то есть захватить не один кадр, а несколько, сложить их, а потом посчитать среднее. Обычно берут количество кадров, равное степени двойки — скажем 8 или 16 и т.д. — тогда деление можно заменить сдвигом. Соотношение сигнал/шум несколько улучшится. Но если и так работает, можно и не заморачиваться.
                                            0
                                            тогда проще поставить 1-2 светодиода для подсветки, качество вырастет намного!
                                            Кстати легкое смещение токена от оси камеры тоже может повысить контраст, ведь у таких жк дисплеев есть углы где контраст максимален, а в противоположных углах наоборот падает.
                                              +1
                                              Андрей, я думал про интегрирование, но решил не заморачиваться особо, и решил задачу «в лоб».
                                              Путей оптимизации и улучшения алгоритма масса, — когда мне будет скучно, я, возможно, вернусь к этой задаче.
                                              +3
                                              Вова молодец! :-)
                                                0
                                                Спасибо. Как раз собираюсь разбираться с OpenCV. :)
                                                  +1
                                                  М-м-м… узнаю обои
                                                    +2
                                                    Куда смотрит ваш security manager?
                                                      +1
                                                      Ну если вы попробуете объяснить мне, в каком месте здесь нарушена безопасность, — я обещаю, что привлеку его к проблеме.
                                                        +3
                                                        Замечательная статья и замечательный способ повышения удобства. Но давайте я попробую на пальцах объяснить, в каком месте нарушается безопасность.

                                                        Основная идея автономных OTP-токенов в том, что физически разделяются «каналы» генерации и доставки секрета в момент аутентификации. То есть у вас для генерации секрета используется токен, а для его доставки — компьютер и сеть.
                                                        В этой связке недоверенными являются компьютер и сеть передачи данных. Именно поэтому им не позволено генерировать или хранить секрет. Это делает автономное устройство, на которое недоверенный компьютер или недоверенный субъект в сети никак (теоретически) не может повлиять, потому что для генерации секрета нужно физически нажать кнопку и ручками ввести одноразовый пароль. А у компьютера или субъекта в сети ручек нету.

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

                                                        Но в оправдание можно сказать что
                                                        — это не массовый продукт, уязвимости в вашем ПО и принципах работы искать никто не будет
                                                        — токен всегда можно забрать с собой (это нужно делать обязательно, когда Вас нет)
                                                        — это удобно :)

                                                        Но Ваш Security Manager, если ему не зря платят зарплату, должен Вас очень сильно отругать за такое изобретение.
                                                          0
                                                          Я вмешаюсь в разговор и блесну отсутствием каких-либо знаний в области ИБ, извините. Так вот, с чего вдруг в данном случае компьютер стал недоверенным? Если его как-то скомпрометировали, то не проще ли поставить кейлоггер/сниффер, либо воспользоваться поднятой ssh-сессией, чем пытаться найти уязвимость в ПО распознавалки?
                                                            0
                                                            Эта схема работает только если есть токен в устройстве. Процесс генерации сопровождается шумом и визуально виден, т.е. «тихой сапой» генерировать не получится. Уходя, токен просто забирается.
                                                              –1
                                                              Спасибо за развёрнутый ответ и попытку объяснить суть проблемы.

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

                                                              Поправьте меня, если я ошибаюсь.
                                                                +2
                                                                Если я правильно понял суть Вашего девайса, то происходит следующее: по команде из компьютера (например, по нажатию short key), девайс жмет на кнопку на токене снимает результат, после чего изображение передается в компьютер на анализ.

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

                                                                Идеологически, недоверенному компьютеру (вирус, вредоносное ПО, шпионский софт и пр.) ничего не мешает без Вас послать команду на генерацию OTP и получить его значение. Вот и нарушение безопасности.

                                                                Об оговорках («кому это надо?», «можно унести токен с собой», «процесс генерации видно» и пр.) я писАл выше. Но мы сейчас руссуждаем о принципах :)
                                                                  0
                                                                  Да, теперь я понял о чём речь.
                                                                  Согласен со всеми приведёнными доводами.
                                                                  К счастью, есть тысячи более простых (но, тем не менее, практически — невозможных) способов получить доступ к системе и я могу спать спокойно.
                                                                    +1
                                                                    Нужно просто сделать аппаратную кнопку активации процесса вместо управления с компьютера.
                                                                    0
                                                                    как вариант, ранее человек самостоятельно управлял событием «генерация токена».

                                                                    Сейчас же можно удалённо запустить данную процедуру. Тем самым исключая контроль человека над этим независимым участком процесса аутентификации и авторизации.

                                                                +4
                                                                Радовался и хлопал в ладоши, когда ему показали устройство.
                                                                +11
                                                                Томас Эдисон в свое время, работая оператором связи на ЖД, вынужден был каждые 30 минут отстукивать азбукой Морзе «я не сплю», чтобы показывать, что готов принимать сообщение. Ясное дело, ночью ему хотелось спать и он придумал устройство, которое отстукивало нужный код, если провернуть колесо с рукояткой. Затем он договорился с ночным сторожем, чтобы тот каждые 30 минут подходил и поворачивал ручку. :-)
                                                                И можно было долго спать. Правда, он спалился на том, что ночью нужно было принять сообщение о внеочередном важном поезде и отправить ответ о готовности, вместо этого его автомат послал «я не сплю», тут все и поняли, что происходит. Выгнать его выгнали, но это не помешало ему стать известнейшим и уважаемым изобретателем.

                                                                Владимир, браво!
                                                                  0
                                                                  Мне нравится. Конструкция напомнило средневековое орудие пыток.
                                                                    0
                                                                    А можно было бы сделать токен-генератор на андроиде и передавать в компьютер по bluetooth…

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

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