![](https://habrastorage.org/webt/fl/5w/8a/fl5w8aafwqrndu6abs1ndeieljw.png)
В комментариях к предыдущей статье, задавали вопросы как организовать многофакторную аутентификацию, используя текстовые сообщения (SMS), предпочтительно бесплатно для владельца приложения/системы.
В этой статье я опишу одну из опций как добиться этого «без регистрации и СМС» (хотя конечно и с регистрацией и тем более СМС, но зато бесплатно и без проблем!)
Если вы используете в качестве хостинга одну из облачных платформ (AWS/Azure/Google Cloud), то конечно имеет смысл использовать сервис предоставляемый этой платформой.
Если же нет, то можно попробовать воспользоваться сервисом предоставляемым одним из лидером в области систем аутентификации Okta.
Если у вас менее чем 1000 активных пользователей в месяц и не более пяти приложений, вы можете создать аккаунт разработчика и вам будут доступны все возможности системы, совершенно бесплатно. 1000 активных пользователей в месяц это не лимит в 1000 посланных SMS, а количество пользователей которые хотя бы один раз аутентифицировались в течении текущего месяца. Количество SMS и страны мобильных номеров не лимитируются.
Особо одарённые резонно отметят, что можно создать несколько аккаунтов и организовать шардинг для ваших пользователей и они будут правы (тем более для создания аккаунта и его использования, не требуется предоставлять персональные данные или кредитную карту), но я думаю что если у вас достаточно большое количество пользователей, то можно и выделить бюджет для платного аккаунта.
Мы рассмотрим пример когда у вас есть приложение с уже существующей базой пользователей и вы хотите добавить дополнительную защиту. Т.е. либо вы не доверяете первичную аутентификацию (username/password) сервису Okta, либо хотите внести только минимальные, точечные изменения.
Регистрация аккаунта
Первый шаг это регистрация аккаунта. Для этого примера я создал мусорного пользователя на gmail и зарегистрировал аккаунт разработчика на него, это было едиственное что потребовалось для получения аккаунта в Okta. Открываем в браузере страницу регистрации и заполняем требуемые поля.
![](https://habrastorage.org/webt/kg/jo/_b/kgjo_brkkf6_6csjyx5y1cyabnq.png)
После верификации почты, вы станете счастливым обладателем аккаунта типа
https://dev-71250.okta.com
, открыв подобную ссылку браузере и аутентифицируясь, вы увидете консоль управления.![](https://habrastorage.org/webt/of/uh/ur/ofuhurgdneglsebd7iyhov9g6eq.png)
Я рекомендую переключиться в режим «Classic UI» из режима «Developer Console», мне было более комфортно работать в этом режиме.
Создание приложения
Создание приложения опционально для целей простейшего сценария, но полезно если вы хотите назначить policy или реализовать дополнительные возможности.
Из меню Applications выбираем подпункт Applications и нажимаем конопку “Add Application” и на следующем экране нажать ещё одну кнопку “Create New App”.
![](https://habrastorage.org/webt/s2/tz/de/s2tzdes6g-ijayfun5vvce4d6ai.png)
Если вы сделали всё правильно то увидете что-то подобное:
![](https://habrastorage.org/webt/he/pt/i1/hepti1ke3h7r1tfsjeajfocex44.png)
Создание токена
Следующий шаг, это создание токена для управления функциональностью Okta используя REST API.
![](https://habrastorage.org/webt/py/d4/i7/pyd4i7-jkxzcknpg5amahtbsgte.png)
Выбираем пункт меню Security и подпункт API, после этого выбираем вкладку Tokens, нажимаем кнопку «Create Token», вводим имя токена описывающего ваше приложение и нажимаем еще одну «Create Token» кнопку.
![](https://habrastorage.org/webt/tm/pu/dk/tmpudkqz5qandl0x6bxdmhnwpco.png)
В моём случае он был типа
0051TT-oaWLfFbq2trgppk2D1dJ3vrYykU
и вы должны его использовать при API вызовах в заголовке Authorization (замените его на ваш)Authorization: SSWS 0051TT-oaWLfFbq2trgppk2D1dJ3vrYykU
Сохраните токен в секретное место, используя этот токен, вы сможете программно управлять фактически всеми настройками вашего аккаунта.
Активация SMS в качестве фактора аутентификации
Следующий шаг после создания токена, это активация SMS в качестве дополнительного фактора.
Переходим в меню Security, подпункт Multifactor выбираем SMS Authentication и меняем статус на Active.
![](https://habrastorage.org/webt/zj/if/qd/zjifqdexeunahs7xuwbfsnf_c28.png)
Импорт/создание пользователей
Последний шаг в конфигурации, это импорт текущей базы пользователей.
Есть несколько способов создать аккаунты пользователей, включая синхронизацию из LDAP. Мы рассмотрим два наиболее простых, импортировать из CSV файла и создать пользователей используя API.
Чтобы импортировать из CSV файла, перейдите в меню Directory, подпункт People, нажмите на опцию More Actions и выберите пункт Import Users from CSV.
![](https://habrastorage.org/webt/fi/-b/o6/fi-bo66xvwyauaifxsmna_toexw.png)
Пример CSV файла в правильном формате можно загрузить нажав ссылку «this template».
![](https://habrastorage.org/webt/u7/tg/yw/u7tgyw9cu4wiorvrmfdsarpcnta.png)
Можно выбрать опцию «Automatically activate new users» чтобы все пользователи автоматически были активированны.
![](https://habrastorage.org/webt/op/9_/c0/op9_c0e1bg3b_qmo4shwvp-spk8.png)
Если всё прошло успешно, то вы увидите импортированных пользователей в списке. Если произошли ошибки в течении импорта, вы сможете загрузить отчёт с детальным описанием проблем импорта.
Второй способ, это создание пользователей програмно используя вызов API create-user-with-password.
Можно создать пользователей используя случайные пароли, чтобы не требовалось дополнительных действий для активации. Пример вызова используя curl (я использую его для простоты демонстрации, но точно также, вызов REST API это фактически пара-тройка строк для вызова HTTP запроса в любом языке программирования):
curl -v -X POST -H "Accept: application/json" -H "Content-Type: application/json" -H "Authorization: SSWS 0051TT-oaWLfFbq2trgppk2D1dJ3vrYykU" -d '{ "profile": { "firstName": "Isaac", "lastName": "Brock", "email": "isaac.brock@mytest.com", "login": "isaac.brock@mytest.com" }, "credentials": { "password" : { "value": "tlpWENT2m344" } } }' https://dev-72150.okta.com/api/v1/users?activate=true
Вы получите подтверждение в JSON
{
"id":"00uxwl899jsEO8DEy4z6",
"status":"ACTIVE",
"created":"2020-09-11T23:11:20.000Z",
"activated":"2020-09-11T23:11:20.000Z",
"statusChanged":"2020-09-11T23:11:20.000Z",
"lastLogin":null,
"lastUpdated":"2020-09-11T23:11:20.000Z",
"passwordChanged":"2020-09-11T23:11:20.000Z",
"type":{"id":"otyxv3zumCroBcUlu4x6"},
"profile":{"firstName":"Isaac","lastName":"Brock","mobilePhone":null,"secondEmail":null,"login":"isaac.brock@mytest.com","email":"isaac.brock@mytest.com"},
"credentials":{"password":{},"emails":[{"value":"isaac.brock@mytest.com","status":"VERIFIED","type":"PRIMARY"}],
"provider":{"type":"OKTA","name":"OKTA"}},
"_links":{
"suspend":{"href":"https://dev-72150.okta.com/api/v1/users/00uxwk7e3GKMn4tBF4x6/lifecycle/suspend","method":"POST"},
"schema":{"href":"https://dev-72150.okta.com/api/v1/meta/schemas/user/oscxv3zumCroBcUlu4x6"},
"resetPassword":{"href":"https://dev-72150.okta.com/api/v1/users/00uxwk7e3GKMn4tBF4x6/lifecycle/reset_password","method":"POST"},
"expirePassword":{"href":"https://dev-72150.okta.com/api/v1/users/00uxwk7e3GKMn4tBF4x6/lifecycle/expire_password","method":"POST"},
"changeRecoveryQuestion":{"href":"https://dev-72150.okta.com/api/v1/users/00uxwk7e3GKMn4tBF4x6/credentials/change_recovery_question","method":"POST"},
"self":{"href":"https://dev-72150.okta.com/api/v1/users/00uxwk7e3GKMn4tBF4x6"},"type":{"href":"https://dev-72150.okta.com/api/v1/meta/types/user/otyxv3zumCroBcUlu4x6"},
"changePassword":{"href":"https://dev-72150.okta.com/api/v1/users/00uxwk7e3GKMn4tBF4x6/credentials/change_password","method":"POST"},
"deactivate":{"href":"https://dev-72150.okta.com/api/v1/users/00uxwk7e3GKMn4tBF4x6/lifecycle/deactivate","method":"POST"}
}
}
В дальнейшем при создании пользователя в вашей системе, необходимо создать соотвествующего пользователя и в Okta используя один из возможных способов.
Также, при удалении пользователя, необходимо удалить пользователя и из Okta. Для удаления пользователя необходимо сначала перевести его в состоянии деактивации используя API вызов deactivate-user, а после этого можно удалить окончательно, используя API вызов delete-user.
На этом подготовительные шаги закончены и можно приступать к самому интересному.
Вам будет необходимо изменить свою систему/приложение так, чтобы она научилась поддерживать использование второго фактора. В самом простом случае, это вызов нескольких REST API методов.
Подключение SMS фактора для пользователя
Поддержка состоит из первичного подключения SMS фактора для конкретного аккаунта, активации и собственно верификации этого фактора.
После того как все изменения внесены, пользователи вашей системы должны выполнить одноразовую, первичную регистрацию и подтверждение активации. В дальнейшем, если у пользователя изменился номер мобильного, необходимо повторить подобный процесс.
Id пользователя можно сохранить после вызова API для создания пользователя, либо его можно получить используя вызов API get user.
Для первичного подключения делаем вызов API
curl -v -X POST -H "Accept: application/json" -H "Content-Type: application/json" -H "Authorization: SSWS 0051TT-oaWLfFbq2trgppk2D1dJ3vrYykU" -d '{ "factorType": "sms", "provider": "OKTA", "profile": { "phoneNumber": "+7 945-500-6000" } }' "https://dev-72150.okta.com/api/v1/users/00uxwl899jsEO8DEy4z6/factors"
Здесь и далее:
72150 — id вашего сайта в Okta
0051TT-oaWLfFbq2trgppk2D1dJ3vrYykU — это ваш API токен.
00uxwl899jsEO8DEy4z6 — это id пользователя.
На телефон пользователя +7 945-500-6000 придёт SMS с кодом подтверждения.
В ответе на вызов мы получаем подтверждение JSON
{
"id":"mblxwleaf79ugvCvG4x6",
"factorType":"sms",
"provider":"OKTA",
"vendorName":"OKTA",
"status":"PENDING_ACTIVATION",
"created":"2020-09-11T23:02:06.000Z",
"lastUpdated":"2020-09-11T23:02:06.000Z",
"profile":{"phoneNumber":"+79455006000"},
"_links":{
"resend":[{"name":"sms","href":"https://dev-72150.okta.com/api/v1/users/00uxwl899jsEO8DEy4z6/factors/mblxwleaf79ugvCvG4x6/resend","hints":{"allow":["POST"]}}],
"activate":{"href":"https://dev-72150.okta.com/api/v1/users/00uxwl899jsEO8DEy4z6/factors/mblxwleaf79ugvCvG4x6/lifecycle/activate","hints":{"allow":["POST"]}},
"self":{"href":"https://dev-72150.okta.com/api/v1/users/00uxwl899jsEO8DEy4z6/factors/mblxwleaf79ugvCvG4x6","hints":{"allow":["GET"]}},"user":{"href":"https://dev-72150.okta.com/api/v1/users/00uxwl899jsEO8DEy4z6","hints":{"allow":["GET"]}}
}
}
Значение «id» будет необходимо использовать в вызове активации.
После чего посылаем запрос на активацию
curl -v -X POST -H "Accept: application/json" -H "Content-Type: application/json" -H "Authorization: SSWS 0051TT-oaWLfFbq2trgppk2D1dJ3vrYykU" -d '{ "passCode": "519138" }' "https://dev-72150.okta.com/api/v1/users/00uxwl899jsEO8DEy4z6/factors/mblxwleaf79ugvCvG4x6/lifecycle/activate"
Код 519138 это код который был получен по SMS на номер пользователя и должен быть им введён в систему для потверждения.
Получаем подтверждение в JSON:
{
"id":"smsxwkq8xAO2Z8btF4x6",
"factorType":"sms",
"provider":"OKTA",
"vendorName":"OKTA",
"status":"ACTIVE",
"created":"2020-09-11T23:03:28.000Z",
"lastUpdated":"2020-09-11T23:03:28.000Z",
"profile":{"phoneNumber":"+79455006000"},
"_links":{
"self":{"href":"https://dev-72150.okta.com/api/v1/users/00uxwl899jsEO8DEy4z6/factors/smsxwkq8xAO2Z8btF4x6","hints":{"allow":["GET","DELETE"]}},
"verify":{"href":"https://dev-72150.okta.com/api/v1/users/00uxwl899jsEO8DEy4z6/factors/smsxwkq8xAO2Z8btF4x6/verify","hints":{"allow":["POST"]}},
"user":{"href":"https://dev-72150.okta.com/api/v1/users/00uxwl899jsEO8DEy4z6","hints":{"allow":["GET"]}}
}
}
«id» фактора (в нашем случае «smsxwkq8xAO2Z8btF4x6») можно сохранить, либо его можно получить для конкретного пользователея используя вызов API list-enrolled-factors.
Верификация пользователя используя SMS код
После того как первичное подключение было успешно завершено и фактор активирован, можно начинать его использование в повседневной работе. SMS фактор работает для всех стран и единственное ограничение, что посылка SMS может быть не чаще чем 30 секунд для пользователя. (т.е. несколько пользователей могут посылать одновременно, но перепослать для того кому только что была отправлена SMS можно только после 30 секундного интервала.
Для верификации фактора, сначала необходимо отправить запрос на отсылку кода
curl -v -X POST -H "Accept: application/json" -H "Content-Type: application/json" -H "Authorization: SSWS 0051TT-oaWLfFbq2trgppk2D1dJ3vrYykU" -d '{ }' "https://dev-72150.okta.com/api/v1/users/00uxwl899jsEO8DEy4z6/factors/smsxwkq8xAO2Z8btF4x6/verify"
В случае успеха пользователь с id 00uxwl899jsEO8DEy4z6 получит SMS с кодом, на телефон который был активирован для этого фактора. В ответе на вызов, вы получите подтверждение в JSON:
{
"factorResult":"CHALLENGE",
"profile":{"phoneNumber":"+79455006000"},
"_links":{
"verify":{"href":"https://dev-72150.okta.com/api/v1/users/00uxwl899jsEO8DEy4z6/factors/smsxwkq8xAO2Z8btF4x6/verify","hints":{"allow":["POST"]}},
"factor":{"href":"https://dev-72150.okta.com/api/v1/users/00uxwl899jsEO8DEy4z6/factors/smsxwkq8xAO2Z8btF4x6",
"hints":{"allow":["GET","DELETE"]}}
}
}
После этого отсылается запрос на проверку полученного кода
curl -v -X POST -H "Accept: application/json" -H "Content-Type: application/json" -H "Authorization: SSWS 0051TT-oaWLfFbq2trgppk2D1dJ3vrYykU" -d '{ "passCode": "213199" }' "https://dev-72150.okta.com/api/v1/users/00uxwl899jsEO8DEy4z6/factors/smsxwkq8xAO2Z8btF4x6/verify"
Код 213199 это код который был получен на телефон пользователя по SMS.
При успешном завершении проверки вы получите JSON с подтверждением:
{"factorResult":"SUCCESS"}
При ошибке, JSON с деталями ошибки
{
"errorCode":"E0000082",
"errorSummary":"Each code can only be used once. Please wait for a new code and try again.",
"errorLink":"E0000082",
"errorId":"oaeNyUSSDUkRvmgoN5TsW-zKw",
"errorCauses":[{"errorSummary":"Each code can only be used once. Please wait for a new code and try again."}]
}
Заключение
Пример в данной статье продемонстрировал возможность легкого и бесплатного использования дополнительных факторов аутентификации для вашего приложения с небольшой пользовательской базой (до тысячи активных пользователей в месяц).
Выполнив начальную конфигурацию и используя несколько простых HTTP вызовов можно включить SMS аутентификацию в своё приложение.
Существует реализация open source клиента для Okta на многих языках, но в принципе можно обойтись и прямыми HTTP вызовами, особенно если вы планируете ограничится только поддержкой SMS.
На данный момент поддерживается несколько дополнительных факторов и Okta позволяет использовать любые комбинации которые вы захотите (если разрешит ваш админ или СБ):
- Okta Security Question Factor
- Okta SMS Factor
- Okta Call Factor
- Okta Verify TOTP Factor
- Okta Verify Push Factor
- Google Authenticator Factor
- RSA SecurID Factor
- Symantec VIP Factor
- Upload YubiKey Seed
- YubiKey Factor
- Okta Email Factor
- U2F Factor
- WebAuthn Factor
- Custom HOTP Factor
Например Call фактор, позволяет проводить верификацию используя голосовые звонки, так что даже пользователи без мобильных телефонов смогут произвести верификацию.
Если вы хотите использовать только TOTP факторы (типа Google Authenticator и т.п.), то можно не городить интеграцию с Okta, а добавить реализацию для вашего языка (обычно не больше пары сотен строк кода) и проводить проверку без зависимости от сторонних сервисов. Только не забудьте шифровать пользовательские secret перед сохранением!
Детальная документация расположена по ссылке.
Исходный код клиента для многих языков можно найти на GitHub.
Я не являюсь сотрудником Okta и не получаю выгоду от его использования. Также, не являюсь экспертом в системах безопасности, но мере возможности отвечу на ваши вопросы относительно реализации и использования дополнительных факторов аутентификации. Либо на вопросы о других возможностях сервисов Okta.
Сервис Okta предоставляет множество возможностей, включая поддержку OAuth/OIDC/SAML и множество раcширенных опций для интеграции.
Например, если вы хотите предоставить онлайн сервисы для корпораций, то Okta это фактически монополист на рынке для реализации single-sign on. Если вы реализуете SAML service provider и зарегистрируете свой сервис на Okta, корпорация сможет предоставить услуги вашего сервиса для своих сотрудников совершенно прозрачно, т.е. им не надо будет создавать аккаунты или проходить дополнительную аутентификацию на вашем сервисе.
Аутентифицируясь один раз в своей корпоративной сети они смогут мгновенно иметь доступ к вашему сервису. Администрирование со стороны админов тоже превращается в простейшую операцию, добавив пользователя в группу в корпоративной системе, он даёт пользователю возможность работать со сторонним сервисом. Сравните с тем как это было организованно раньше — выгрузка списков пользователей, синхронизация между системами, периодический аудит что ничего не рассинхронизировалось и т.п.
Воистину, сложно переоценить удобство подобной функциональности и как следствие дополнительную привлекательность вашего сервисе по сравнению с конкурентами. Можно посмотреть список уже существующих сервисов и тогда поймёте что подобная функциональность это не будущие, а уже настоящее.
Надеюсь что данная статья поможет сделать онлайн сервисы чуть более надёжными, а мир чуточку лучше.
Wesha
Это вопрос из серии "как правильно забивать гвозди микроскопом". По одной простой причине.
SteepP Автор
Как раз в предыдущей статье обсуждались рекомендации NIST по использованию SMS в качестве фактора.
Плюс идёт работа над митигацией проблем подобного плана в SS7.
Я не призываю использовать этот фактор в критичных системах (хотя банки это делают), но каждый решает за себя, удобство или защита. Особенно для бабушки, которая при словах google authenticator, может словить инфаркт миокарда.
Finesse
Это уже продвинутый английский. Статьи с такими комментариями надо помещать в раздел «лингвистика».
Русский аналог этого слова: смягчение.
SteepP Автор
Это замечательно что вы умеете виртуозно пользоваться словарём, но к сожалению «смягчение» это не подходящий вариант.
В контексте систем безопасности mitigate означает уменьшение риска посредством добавления внешних устройств/процессов/правил и т.п.
Spiritschaser
ЕМНИП, в случае более мощной БС с 2G она предпочитается менее мощным 3G и 4G станциям.
А на 2G можно форсировать, прости господи, «экспортное» 56-bit шифрование, ломаемое нынче в реальном времени. Даже если SS7 пофиксят/запретят, уводить SMS всё равно будет не сложно (конечно, спалиться будет проще).
dobergroup
В общем случае это не так. Ранжирование обслуживающей BS зависит от нескольких факторов. Но даже если не вдаваться, то для того, что бы MS «померяла» на частоте фейковой соты RSSI/RSCP — обслуживающая BS должна эту частоту передать как соседнюю. Если поставить фейковую BS на незанятую частоту — MS ее не увидит до тех пор, пока в эфире остаются другие. Если на частоту одной из легитимных соседей — то очень сложно добиться осмысленного взаимодействия BS/MS из-за помех.
Но при смене соты произойдет новое пересогласование алгоритма и если для удержания A5/2 нет объективных причин — он вернется к разрешенному A5/1 или A5/3
В любом случае вектор атаки ускользает — СМС должна передавать легитимная на своем нисходящем, какой смысл его заменять и НЕ передавать СМС? А Ki в эфире не гуляет, MITM не получится.
centralhardware
А насколько хорошая идея рассылать сообщения самим с помощью скажем GSM модема? Не обязательно для 2fa
vp7
Идея хороша, но при отправке на абонентов других операторов ваши смс могут заблокировать антиспам-системы других операторов посчитав это коммерческой рассылкой (на которую ценники по России уже начинаются от 1.5-2 руб за sms).
SteepP Автор
Всё можно сделать, но как только добавляется железка, надёжность снижается. Надо делать бэкап, дополнительные каналы и т.п.
Плюс стоймость модема vs бесплатно, тут надо выбирать.
Mobile1
Все замечательно, только вы не знаете самого главного — а именно — что работает под капотом у Okta и самое главное — как оно работает?
Вы исходите из того что есть вот такой замечательный сервис Okta и можно легко добавить SMS и все это бесплатно и что все это якобы работает и гарантия доставки SMS — 100%.
На самом деле этот сервис пользуется API какого-нибудь Nexmo, который имеет 60-70% доставки SMS.
Что это означает?
Что 30% пользователей приложения не получат SMS и будут писать в отзывах на Плейгугл что-то типа — так и не дождался кода, плохой сервис, невозможно пользоваться и т.д.
vp7
Del
SteepP Автор
Okta публичная компания с одним сервисом, капитализация на сегодня составляет 24 миллиарда долларов.
Так что уровень доверия достаточно высокое.
Mobile1
А причем здесь капитализация?
Okta же не занимается специализированно отправкой СМС.
Этим занимаются компании типа Nexmo, у которых есть и SMS гейты свои и которые агрегируют вот это все.
И там такой треш и угар творится, что вы даже не представляете.
vp7
Уверены, что по России SMS доставляются?
Коммерческие каналы дорогие, серые (через кучку gsm модемов) нестабильны.
SteepP Автор
Личная практика конечно не критерий истины, но пока проблем небыло, в том числе в Индии, где качество операторов существенно хуже.
vp7
Про Индию ничего не скажу, но в России все операторы уже давно поставили антиспам-платформы, которые выявляют потенциально коммерческий трафик и блокируют его.
Поэтому и спрашиваю.
Meiblorn
Я вообще не против Okta. Однако слово «бесплатно» в отношении этой компании звучит несколько нелепо. www.okta.com/pricing — 3$ / user — как-то дорого: примерно столько же будет стоить купить аккаунт программисту в jira/gitlab cloud. Поэтому если и использовать okta «бесплатно», то исключительно для внутренних сервисов, иначе просто можно разориться при нормальной такой user-base.
SteepP Автор
Если вы энтерпайз решения смотрите, то как бы да, но примерно на уровне остальных.
Для того что я описал цены надо смотреть на developer.okta.com/pricing
SteepP Автор
Не то что я был против минусов, как раз наоборот. Просто увидел детали и стало очень любопытно.
![](https://habrastorage.org/webt/6y/yv/ud/6yyvudtfohfk_befwxpxpem6g3k.png)
Ну с пунтком «не согласен с изложенным» — я согласен, мнения разные.
Два за пункт «Больше рекламы чем пользы» — недоумеваю, как бы описал как бесплатно поиспользовать сервис, в чем реклама и выгода? В описании дополнительных возможностей сервиса — ну это для пользователей которые не работали в корпорациях и не в курсе того что например поддержка single-sign on, это почти что маст-хэв сегодня. Реализовать раз плюнуть, а выхлоп реальный. Если тот кто не в курсе прочитает и задумается.
Ну может конечно имели в виду «чем пользы», ну тогда тоже в принципе могу согласиться.
Но вот пункт «Не соответсвует тематике хабра» честно говоря удивил, что тогда соответствует то? Похоже пропал калабуховский дом, совсем гиктаймеры его погрызли.
Moskus
Делать выводы по четырем голосам? Это как-то очень далеко от статистически значимого количества.