Случайны выбор дневника Раскрыть/свернуть полный список возможностей


Найдено 1290 сообщений
Cообщения с меткой

стандарты - Самое интересное в блогах

Следующие 30  »
rss_rss_hh_new

Как выбрать поставщика услуг информационной безопасности

Вторник, 25 Апреля 2017 г. 13:35 (ссылка)





Что важно при выборе провайдера услуг по нейтрализации DDoS-атак и защиты сетевого периметра?



«Ширина канала к серверу» — скажете вы. Ну, и добавите: «Защита от разных векторов атак». Возможно в вашем списке ещё есть активный сканер уязвимостей. Что там сложного?



Многим кажется, что DDoS-mitigation решения, это просто «быстрый и масштабный бан плохих IP», что недалеко от правды, но всё-таки не до конца верно. Учитывая, что только за прошедший год количество DDoS-атак увеличилось в полтора раза и вышло на передовицы СМИ из-за разрушительного эффекта, новостной волной хотят воспользоваться не только чистоплотные и высокопрофессиональные компании из области информационной безопасности.



Для того чтобы не гадать, а знать наверняка, на какие основные параметры обращать внимание при выборе такой важной вещи, как защита сетевой инфраструктуры от атак на отказ в обслуживании, мы в Qrator, совместно с Wallarm и CDN-провайдером NGENIX подготовили специальную страницу, собраны наиболее важные критерии, на которые требуется обращать внимание в момент выбора конкретного решения, услуги, сервиса, продукта — неважно.



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



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



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



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







Как правило, если вы в теме, то самый простой способ проверить, чью услугу на самом деле вы покупаете — это посмотреть A-записи DNS. Сделать это можно с помощью бесплатного «Радара». Но так как в бизнесе речь идёт о расходах на приобретение или создание услуг, требуется исчерпывающий список требований, понятный не только сетевым администраторам.



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




  1. Наличие более одной точки присутствия в каждом из ключевых регионов, с подключением к поставщикам связи не ниже Regional Tier 1 (исключение единых точек отказа за счёт наличия геораспределённой сети);

  2. Инфраструктура созданная на базе иерархически не связанных между собой сетей интернет-провайдеров (что особенно актуально для небольших стран с малым количеством ключевых провайдеров);

  3. Более одного поставщика услуг на сетевой префикс (что исключает возможность наследования проблем от провайдера);

  4. Наличие защиты DNS-протокола (после падения Dyn здесь даже не требуется аргументация);

  5. Защита всех протоколов используемых целевым приложением (а не только HTTP/HTTPS);

  6. Постоянная автоматическая фильтрация трафика (минутные и даже секундные задержки на включение решения в работу и нейтрализация атаки — плохо);

  7. Фильтрация по всей сетевой модели ISO OSI, вплоть до L7. Последнее особенно важно, так как атаки на уровень приложений становятся всё более распространёнными. Здесь же важна совместимость решения с любыми продуктами и услугами, использовавшимися до этого, что снижает расходы на внедрение;

  8. Полноценная фильтрация шифрованного трафика без раскрытия ключей;

  9. False positive не более 5% под атакой;

  10. Отсутствие изменений UX (обратный тест Тьюринга) — гарантия отсутствия раздражения у пользователя;

  11. Возможность осуществления внешнего тестирования защиты независимыми экспертами;



Отдельным, двенадцатым пунктом идёт наличие WAF в списке предоставляемых услуг — и данному пункту требуется уделять отдельное внимание, так как Web Application Firewall это необходимое и обязательное условие любой серьёзной системы защиты инфраструктуры и нейтрализации атак. К WAF предъявляется три отдельных технических требования:




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

  2. Возможность применять виртуальные патчи, что не нужно комментировать: куча уязвимостей в системах самой разной степени распространённости (Magento, Wordpress и так далее) не закрываются разработчиком по полгода. Виртуальные патчи позволяют эффективно справляться с данной проблемой, сохраняя полную работоспособность приложения;

  3. Защита от перебора различных категорий паролей, от администраторских до клиентских, в разных частях приложения.



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

https://habrahabr.ru/post/327326/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

[Перевод] Всё плохо

Вторник, 25 Апреля 2017 г. 12:50 (ссылка)

image



Что ж, всё плохо. Немного забавно так говорить: на конференции (Web `a Qu'ebec) было много разговоров об удивительном будущем и вещах, возможных благодаря новым технологиям. О новых средствах и устройствах, которые должны сделать нашу жизнь проще. Мои знакомые знают, что у меня обычно очень циничный взгляд на технологии; лично я боюсь всех этих умных устройств, которые реагируют на мои слова, чем восхищались другие спикеры.



В основном потому, что чем больше времени я трачу на программирование и провожу в этой отрасли, тем больше узнаю, как всё работает изнутри, и тем меньше доверия всё это мне внушает. Я подобрал изображение для слайда. Это картина «Триумф смерти» Питера Брейгеля. В некоторой степени она раскрывает моё отношение к «умному дому».



image



Я хочу показать, что имея даже очень простое приложение, выглядящее очень и очень разумно, и показать множество проблем и потенциальных ошибок, которые могут скрываться в нём и неприятно удивлять нас. Я хочу продемонстрировать, что сложно чувствовать себя по-настоящему в безопасности, когда дело касается кода. Это будет страшная история!



image



Чтобы раскрыть свою точку зрения, я начну с базового приложения, знакомого любому разработчику в этом зале. Здесь у меня маленькое веб-приложение. Справа — пользователи, они с помощью своих устройств подключаются к моему фронтенду, исполняющему код, написанный на некотором языке и отвечающий за логику приложения. Там происходит подключение к базе данных, где хранится информация. Далее — cron, он нужен для ряда фоновых задач, возможно, не особо сложных. Затем идёт облако, которое, вероятно, используется множеством других составляющих системы. Может быть, вы храните изображения в S3 или что-то ещё.



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



image



Такая схема безопаснее. Теперь у меня есть дополнительный фронт, и я могу подключать или отключать любой из них и по-прежнему оставаться доступным для клиентов. Второй узел базы данных даёт нам возможность аварийного переключения в случае возникновения проблем, но это не резервное решение. Достаточно всего одного человека, DROP TABLE users и репликацией в реальном времени, чтобы удалить таблицу «Пользователи» и потерять этот горячий резерв. Так что давайте скажем, что мы поступили разумно и создали резервную копию в этом облаке.



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



image



Вот несколько абстракций.



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



Дальше у нас идут идентификаторы. Я считаю их абстракциями. Они могут быть вашими автоинкрементными идентификаторами в базе данных, UUID или GUID, а также переменными, указателями, URL или URI. Они в основном позволяют ссылаться на элемент, часть данных или объект без необходимости его полного описания. Обычно идентификаторы связаны контекстом, который придает им смысл. Я могу сказать: «Ты Джон», и люди, которые знают конкретного Джона, будут иметь представление о том, кто такой Джон, основываясь на своём знакомом, на таких показателях, как его рост, профессия, возраст и т. д. Идентификаторы позволяют нам определить то, что поддерживает весь истинный элемент.



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



Внизу слева у нас сеть. Это всё просто абстракции. Ваши соединения, упорядоченные потоки данных, IP-адреса и номера портов (которые также являются идентификаторами!), пакеты и т. д. К счастью, мы не просто передаём электрические сигналы по кабелю.



Далее идёт время. И здесь я не буду его описывать. Философы, метафизики и учёные тысячелетиями спорили, чтобы приблизиться к тому, что мы сегодня понимаем под этим словом.



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



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



image



Начнём с простых чисел с плавающей запятой. Если вы когда-нибудь видели сумму 0,1 + 0,2, равную 0,30000000000000004, вы знаете, что это такое. Существует бесконечность чисел от 0,1 до 0,2, но у нас есть ограниченное количество байтов для их представления. Некоторые цифры не делятся нацело, и без работы с дробной частью будет очень сложно не потерять точность, когда компьютер начнёт подменять цифры, чтобы они приобрели смысл.



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



Я слышал об одном проекте, в котором банк пытался транслировать свои старые базы кода с помощью node.js. К несчастью для команды, никто не сказал им о том, что в JavaScript есть только числа с плавающей запятой, и команде пришлось отказаться от проекта.



Кстати говоря, языки с флоатами типа JavaScript имеют верхний предел точности целых чисел, в данном случае 253.



image



С целыми числами немного проще. Люди по большей части лучше понимают ограничения, что помогает. Но этого недостаточно: нужна правильная структура и тип использования, поскольку не все целые числа означают одно и то же. Вспомните о Mars Climate Orbiter, который потерпел неудачу, потому что одни части кода работали в имперских единицах, а другие — в метрической системе. Упс.



На изображении показан особый взгляд на эти запутанные единицы. Спросите Siri или Wolfram|Alpha, сколько китайских королей на одном квадратном метре, и вы получите 1,628 x 10–4. Не совсем уверен, что это значит, но каждый раз это достоверно определяется.



image



Ещё интереснее, когда добавляется языковая обработка. Я не понимаю почему, но на вопрос «Кто король Соединенных Штатов?» получаем ответ «1,57 миллиарда китайских королей».



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



image



Допустим, что моё приложение отлично справляется со своей избыточностью и так же отлично справляется с манипуляцией цифрами. Возможно, у меня даже появились пользователи. Теперь мне необходимо обратить внимание на такую полезную вещь, как шардинг, или, может быть, я просто буду работать с внешними сервисами. В любом случае я, скорее всего, стану использовать UUID или GUID, поскольку они непредсказуемы и могут «гарантировать» уникальность.



UUID — это всего лишь группа битов, которые вы сравниваете. Если они все сошлись, то идентификатор прошёл проверку. Если нет, тогда он другой. Там множество разных вариантов, какие-то случайные, какие-то основаны на времени или адресе.



Как мы можем видеть, UUID — это то, что расположено на вершине слайда, с шестнадцатеричными числами, разделёнными дефисами. Это немного рискованно.



image



В зависимости от языка или стека, к которым вы прибегаете, у вас могут быть библиотеки, которые позволяют хранить UUID как двоичные блобы в памяти. Или же строки, где хранятся их абстрактные представления. В некоторых случаях вам придётся использовать строки в качестве промежуточного формата, например при передаче информации по различным системам, не поддерживающим необработанные двоичные данные, таким как SQL-запросы или JSON.



В этом заключается риск. По умолчанию у большинства строк в большинстве языков есть операторы сравнения, чувствительные к регистру. Значит, хотя эти три UUID идентичны в своём аутентичном двоичном представлении, они не будут сравниваться как равные строки. Чувствительность к регистру существует в любом случае и обязательно должна учитываться вашей системой, так как строковое представление не является идеальным абстрактом истинных свойств UUID.



image



И действительно, различные компоненты, не использующие одинаковое точное представление, могут стать серьёзной головной болью. Ваши пользователи, front-end, back-end, базы данных и облачные сервисы должны либо быть нечувствительными к регистру, либо не противоречить общему представлению.



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




  • Используя PostgreSQL, вы получаете нечувствительное к регистру сравнение, но представление в нижнем регистре.

  • MySQL поддерживает создание UUID верхнего регистра, но не имеет формата хранения для них. Рекомендуется выбирать чувствительный к регистру VARCHAR.

  • MSSQL может хранить GUID, но подходит для представления в верхнем регистре.

  • Oracle может хранить необработанные данные, так что здесь не должно возникнуть проблем.

  • Redis не поддерживает UUID, и, скорее всего, вам придётся использовать строку с учётом регистра.

  • MongoDB всё делает правильно, с двоичным представлением.



Тем не менее даже если вы со своей стороны делаете всё безошибочно, нет никакой гарантии, что система будет работать. Достаточно всего одной подсистемы, чтобы всё разрушить. Например, внешние службы, такие как некоторые сервисы Amazon, имеют множество различных предложений, которые не всегда согласуются друг с другом (например, DynamoDB и SimpleDB чувствительны к регистру, поэтому третий сервис AWS, основывающийся на них, скорее всего, унаследует эти свойства). Если подобное произойдёт с вами, если вы, скажем, используете PostgreSQL локально и храните UUID в качестве UUID, то ничего хорошего из этого не выйдет. Теоретически объекты могут начать конфликтовать друг с другом или просто исчезнуть, поскольку ваше локальное представление нижнего регистра не существует для сервиса верхнего регистра.



Любая часть системы, действующая не так, как остальные, может вызвать проблемы. Вам придётся хранить канонический UUID (для сравнения) с его строчной копией (для его исходной версии) или изучать, как каждый сервис хранит материал. Не очень весело.



image



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



Если я сравниваю хеши паролей, причём самый верхний из них — правильный, а второй и третий — это другие попытки, то, когда мой оператор '==' достигает разницы, он обнуляется и выдаёт false.



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



Собственно говоря, это атака по времени. Хотя существует гораздо больше их разновидностей.



image



Эту проблему можно решить, заменив оператор сравнения строгой дизъюнкцией. Установите значение false, а затем проведите побитное или побайтное сравнение с XOR. Каждый раз, когда оба значения одинаковы, выдаётся 0 (false), и каждый раз, когда значения отличаются, выдаётся 1 (true). ИЛИ приводит к исходному значению, и если в итоге это не 0, то вы знаете, что есть разница.



По-прежнему необходимо быть осторожными. Нужно удостовериться, что не происходит утечки информации о количестве данных и что определённые оптимизации не причиняют вам вреда. Хорошие криптографические библиотеки делают это в любом случае. Используйте bcrypt или scrypt, и с паролями не возникнет проблем, но чем больше вы знаете, тем лучше.



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



image



Конечно, некоторые устройства принимают это слишком близко к сердцу, и их медлительность на самом деле необязательна!



image



Итак, у нас есть это замечательное приложение. Теперь оно прекрасно справляется с избыточностью, целыми числами, плавающими запятыми, UUID и паролями. У меня появляется намного больше пользователей, и производительность относительно времени отклика начинает снижаться. Из сообщений в блоге я узнал, что теряю важный процент пользователей, не получающих ответ каждую десятую секунду потраченного времени. Это сигнал к действию!



Некоторые операции длятся дольше и тормозят остальные. Как правило, по-настоящему трудно предугадать, что это может быть, и пиковые времена раздражают. Кому-то из команды приходит в голову идея, которая поможет решить все проблемы. Что это за идея?



image



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



image



И что же? Все мои действия возвращены. Чёрт, это даже быстрее, чем раньше!



Тем не менее есть некоторая проблема.



image



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



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



image



На самом деле, если работа не выполняется тщательно, события могут повторяться. Вот пользователь Reddit, который приобрёл игру за 12,74 доллара. Он купил её однократно, но получил запрос об оплате множество раз, пока на его банковском счёте не образовалось превышение кредита в –93 тыс. долларов.



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



image



Но это ещё не всё. Причина, из-за которой моё приложение стало медленно работать: оно было перегружено. Так что сейчас я полностью отделил воспринимаемую производительность от фактической нагрузки в системе.



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



image



В итоге очередь переполняется и вылетает. Конечно, выходит из строя не только она.



image



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



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



image



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



image



В следующий раз, когда произойдёт ошибка, мы сможем сделать то же самое.



image



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



image



И это микросервисы!



image



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



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



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



image



Мы могли бы выбрать что-то вроде JSON. Это диаграмма из seriot.ch, отслеживающая около 50 реализаций библиотек JSON на более чем десяти языках.



Почти каждая из них обрабатывает информацию по-своему.



image



Это не очень хорошо.



image



Стандарт JSON очень мал, но это, вероятно, означает, что он предоставляет пространство для интерпретации и, следовательно, для особого нестандартного поведения.



Самое интересное: если запустить несколько микросервисов и отправить всем им одинаково тщательно обработанный набор данных, это может привести к противоречивому поведению. Возьмём, к примеру, неверный JSON со множеством одинаковых ключей, имеющих разные значения. Скажем, у меня есть объект «человек», где атрибут «имя» появляется дважды, первый раз это «Марк», второй раз — «Джон».



Скорее всего, анализатор поведёт себя одним из трех способов:




  1. Откажется от разбора записи, как и должно быть.

  2. Сохранит первое имя (Марк).

  3. Сохранит второе имя (Джон).



Выбор последних двух способов зависит от порядка анализа (с использованием стека или по очереди).



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



image



Ещё одна проблема связана со временем. Различные часы работают на разных скоростях. В прошлом году я проводил эксперимент для презентации по календарям (нет, не смейтесь, календари на самом деле очень интересны), во время которого я отключил синхронизацию часов на своём компьютере. Затем я проделал то же самое с духовкой и микроволновой печью, чтобы посмотреть, где будет наибольшее отклонение. Где-то через три-четыре недели время на микроволновке сдвинулось примерно на 3 минуты, на ноутбуке — примерно на 2 минуты и 16 секунд, а на духовке — не изменилось.



Часы отклоняются в зависимости от аппаратного обеспечения, температуры, напряжения, влажности и т. д. Они не могут оставаться точными долгое время.



image



Значит, без синхронизации временные метки для одного и того же события могут разделиться и привести к разрозненным результатам. Чтобы этого избежать, необходим NTP. Вы можете проследить за временем и убедиться, что оно незначительно отклоняется. Тем не менее для событий, которые происходят очень быстро, даже у NTP может появиться достаточно вариаций, чтобы вызвать проблемы.



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



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



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



Хитрость здесь состоит в том, чтобы создать значительное различие между монотонным и системным временем.



image



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



В данном случае клиент может отправить запрос, который переведёт его на первый сервис, затем на второй и на третий. Допустим, сервис подтверждает покупку товара и пересылает уведомление об этом в интерфейс. После третий сервис сразу же отправляет заказ на четвёртый сервис, который, скажем, подтверждает доставку или что-нибудь в этом роде. Он также отправляет уведомление в интерфейс.



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



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



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



image



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



image



Но это ещё не всё. Присутствующие здесь наверняка знакомы с часовыми поясами. Но кто-нибудь здесь слышал про пояса в полчаса?



(Большинство людей поднимают руки.)



Да, такой пояс расположен в Ньюфаундленде. Это внутри страны, хорошо, что вы знаете.



Но опять же, кто знает о существовании часового пояса в четверть часа? Подобный находился в Новой Зеландии. Или что в Либерии был зафиксирован 44-минутный? Может быть, некоторые здесь слышали, что в 1927 году в часовых поясах в Китае произошли отклонения в пять минут и несколько секунд?



Но и это ещё не всё. Не всегда изменения в часовых поясах незначительны. Например, острова Самоа существуют между UTC –11 и UTC +13, полностью переключая дни. Хитрость в том, что они находятся на линии изменения даты. В 1892 году острова решили согласовать свои календари с США, исходя из рыночных соображений. В том году у них дважды было 4 июля. Первое июля, второе июля, третье июля, четвёртое июля, четвёртое июля, пятое июля...



И опять же в 2011 году (совсем недавно!) они согласовали календари с Китаем, и на этот раз на островах Самоа не было 31 декабря.



К тому же существует летнее время. Если вы знакомы с бразильскими сисадминами, вы, возможно, слышали о таком забавном факте (я не знаю, делают ли они так до сих пор), что каждый регион/провинция/штат в Бразилии ежегодно голосует за то, будут ли они придерживаться DST. Невозможно узнать заранее, надо ли обновлять файлы часовых поясов.



image



Далее, високосные секунды. Проблемы часовых поясов решит просто UTC. Но это имеет весьма интересные последствия, поскольку каждый тип всё ещё использует временные метки UNIX и свободно конвертируется между UTC и эпохой UNIX, которая начинается 1 января 1970 года.



Это связано с тем, что UTC учитывает високосные секунды, которые часто корректируются: добавляются или удаляются, основываясь на вращении по земной орбите, чтобы синхронизировать часы с реальным миром. С 1970 года мы находимся в сети 27-секундных смещений. Эпоха UNIX в наших системах не учитывает эти секунды.



Изображение, которое вы можете видеть на слайде, появилось пару лет назад из-за ошибки в iPhone, в результате которой перемотка даты на телефоне до 1 января 1970 года приводила к его поломке. Устройство считало программное обеспечение недействительным и отказывалось что-либо воспроизводить. В результате в руках оказывался девайс, который было невозможно ни отремонтировать, ни перезагрузить.



Моё личное предположение, почему это произошло (и я надеюсь, что я прав), связано с несоответствием временных представлений. Если вы используете целое число без знака — опять эти надоедливые целые числа — для представления времени, начинающегося 1 января 1970 года, в качестве эпохи, но с помощью преобразования UTC для установки даты и времени, вы получите 27, что невозможно считать целым числом без знака. Вместо желаемого результата произойдёт потеря значимости. При 32 битах устройство выдаст нам 2106 год, которого может просто не существовать в данном программном обеспечении, и это опять приведёт к поломке.



image



Но это ещё не всё. Далеко не всё. Здесь, в Квебеке и Северной Америке, мы используем григорианское время. Кто-нибудь из присутствующих допускал ошибки в коде, связанные с високосными годами? (Многие поднимают руки.)



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




  • Бенгальский календарь. Солнечный, разделён на шесть сезонов по два месяца в каждом.

  • Китайский календарь. Довольно запутанный лунно-солнечный календарь. Официально используется в Китае (где живёт более миллиарда человек) наряду с григорианским.

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

  • Еврейский календарь. Один из самых старых. Одновременно и лунный, и солнечный. В нём самые сложные правила, связанные с выбором дат, которые я когда-либо видел. Простые правила выбора первого дня года могут занимать несколько страниц. Он официально используется в Израиле и имеет тот же статус, что и григорианский календарь.

  • Индуистский календарь, также очень сложный для меня. Он использует как солнечные, так и лунные циклы. Интересно, что в зависимости от региона в качестве начала цикла принимается новолуние или полнолуние, поэтому в одной и той же стране один и тот же календарь даёт два разных набора дат. В совокупности с жителями Индии мы близки к трети мирового населения, которое довольно часто пользуется негригорианскими календарями.

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

  • И наконец, исламский календарь, который используется в Саудовской Аравии официально, а в других странах — в культурных или религиозных целях. Интересно, что он основан на наблюдениях. То есть каждый новый лунный цикл какой-то уполномоченный человек должен выйти, посмотреть на небо и сказать: «Это новолуние, у нас официально новый месяц». Раньше, когда этот календарь использовался во многих странах, месяцы могли начинаться с разных дат, поскольку в зависимости от местоположения наблюдения отличаются.



Так что да. Здесь нужно многое иметь в виду. Давайте оставим всё это сложное время и пойдём дальше.



image



О нет. Юникод. Осмелюсь предположить: многие в этом зале сталкивались с тем, что различные системы коверкали ваши имена. Поднимите руки. (Более половины зала поднимают руки.)



Да. Стало быть, вы знаете, как это происходит. Проблема заключается в конфликте кодировки между Latin-1 (или ISO-8859-1) и UTF-8.



image



Выходит так, что в нижних символах UTF-8 и ISO-8859-1 абсолютно одинаковы, а самые нижние символы разделены с ASCII.



Поэтому для получения одной и той же кодировки нам необходимо настроить каждый шаг. Сначала пользователь, затем передача данных с помощью HTTP (включая надоедливые метатеги), сами экземпляры, затем языки программирования (некоторые функции по своей сути не являются UTF-8), далее соединение с базой данных (поскольку SQL основан на тексте, он чувствителен к кодировке), а затем и сама база данных. Если вам повезёт, то ваша БД также позволит настроить конфигурацию для таблицы и для столбца.



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



image



В Юникоде длина — это также переменная. Это можно объяснить четырьмя способами. Используем небольшую строку с а и лошадью в ней:




  • Имеется длина в байтах, которая даёт нам 14 байтов в UTF-8, 12 в UTF-16 и 20 в UTF-32.

  • В кодовой единице содержится длина, которая говорит о том, сколько комбинаций битов используется для каждой кодировки строки. В данном случае 14 для UTF-8, 6 для UTF-16 и 5 для UTF-32.

  • Длина кода основана на количестве логических символов Юникода. У нас длина равна 5, так как второй символ здесь сделан с комбинированной меткой, придающей ему маленькую кривую сверху.

  • Кроме того, есть кластеры графем, которые мы, люди, считаем символами. Мне нравится описывать это как «сколько раз нужно нажимать клавишу Delete, пока строка не станет пустой». Длина равна 4.



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



Это весело. На прошлой работе мы один раз удалили целый кластер на 40+ минут. Бинарный протокол запросил длину байта по переданным ему данным, но одна из двух точек связи использовала длину кода для работы. Это продолжалось годами, пока мы не начали отправлять произвольные данные, передаваемые клиентами. Потребовалось около 30 секунд, чтобы ввести с Юникод данные, которые десинхронизовали оба протокола и всё исправили.



Несмотря на то что мы сделали это оперативно, нам понадобилось ещё около трёх дней, чтобы решить проблему окончательно. Подходящее время для отпуска.



image



Этот опрос касается используемых языков. Не знаю, как были получены результаты, но мне они кажутся правильными.



image



А, как забавно. Я получил это в результате одной интересной ошибки Spotify, которая произошла несколько лет назад. Я не буду повторять, что я тогда сказал, а просто дам ссылку на сообщение в блоге.



image



На этом слайде объясняется нормализация Юникода. Он использовался в качестве поддержки ошибки Юникод в Spotify, так что вот ссылка на сообщение в блоге.



image



И теперь мы добрались до по-настоящему интересного материала! Безопасность! Это из статьи 2012 года «Самый опасный код в мире: проверка SSL-сертификатов вне браузера», которую я советую почитать.



Когда дело дошло до плохих абстракций, безопасность оказалась на высоте. Она обнаружила, что почти всё обследованное программное обеспечение было вынуждено проверять сертификаты вне веб-браузеров. Это привело к критической ошибке, в результате которой могли быть пропущены атаки «человек посередине» и перехвачены или изменены данные всего сеанса. Весёлые времена.



image



Вот хороший отрывок из библиотеки OpenSSL. С таким плохим интерфейсом многие люди пропустили критические биты проверки.



image



И вот один о GnuTLS с таким же ужасным интерфейсом.



image



Но API cURL в PHP мой любимый. По умолчанию настройки правильные и корректные, но если вы прочтёте документ, то сможете установить для параметра CURLOPT_SSL_VERIFYHOST значение true. Проблема заключается в том, что в PHP (так же, как в C и C++) true — почти то же самое, что 1. Однако значение 1 для CURLOPT_SSL_VERIFYHOST отключает проверку. Правильное значение — 2.



Упс.



image



Итак, мы подошли к концепции class breaks, о которой я впервые узнал из блога Брюса Шнайера.



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



В случае с программным обеспечением у нас есть концепция class breaks, согласно которой слабое место может быть использовано для всего сразу. Это относительно новое и особенно страшное явление.



image



«Интернет вещей», который был воспринят как нечто поразительное на этой конференции, вызывает особое беспокойство. Реализации просто ужасны. Чем больше вы работаете с кодом, тем меньше вы верите в то, что разработчики IoT хорошо делают своё дело.



Бывают довольно интересные случаи. Например, автомобиль взломали и отправили в кювет (возможно, к этому причастна страховая компания, которая в стремлении уменьшить страховые выплаты была готова подключиться к автомобилю через сеть?), холодильники отправляют спам, устройства, подключённые к бот-сетям, роняют инфраструктуру и т. д.



image



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



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



Применяем ли мы адекватные средства для обеспечения безопасности своих творений? Оставим ли мы всё как есть только потому, что ещё не убили достаточно людей? Может, мы все знаем о проблеме, но просто отрицаем свою личную ответственность, пока что-нибудь не заставит нас действовать как единое целое, чтобы добиться большего?



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


Original source: habrahabr.ru.

https://habrahabr.ru/post/327264/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Как я писал предложение к стандарту С++

Пятница, 21 Апреля 2017 г. 14:30 (ссылка)

Это будет история младшего разработчика из Яндекс.Паспорта о появлении предложения в стандарт С++, разработанного в соавторстве с Антоном antoshkka Полухиным. Как часто бывает в жизни, что-то новое началось с боли, а точнее — с желания её прекратить.







Жила-была библиотека у меня на поддержке. Всё у неё было хорошо: собиралась под Linux, работала, не падала. Однажды пришли люди с просьбой (требованием) собрать её под Windows. Почему бы и нет? Но с первого раза не получилось. Корнем зла оказалась рукописная криптография, которая в какой-то момент умножала два 64-битных целых числа. Для сохранения результата такого умножения потребуется число на 128 бит, и в библиотеке использовался тип __int128. Он прекрасен: имеет естественный интерфейс, поддерживается несколькими компиляторами (gcc, clang), работает без аллокации памяти, но главное — он есть.



Разработчики компилятора из Microsoft поддержку этого типа не обеспечили, аналогов не придумали — или я их не нашёл. Единственное пришедшее на ум кроссплатформенное решение — Big Numbers из OpenSSL, но оно несколько другое. В итоге конкретно эту проблему я решил «велосипедом»: нужен был только uint128_t с ограниченным набором операций. Из нескольких чужих решений собрал класс UInt128, положил его в исходники библиотеки. «Велосипед» — как раз и есть та самая боль. Задача была решена.



Вечером того же дня пошёл развеяться на мероприятие, где люди из «Рабочей Группы 21» (РГ21) рассказывали о том, как они обрабатывают напильником С++. Я послушал и написал на cpp-proposal@yandex-team.ru короткое письмо из двух предложений на тему «нужен int128 в сpp». Антон Полухин в ответ поведал о том, что разработчики стандарта хотят решить эту проблему раз и навсегда. Логично: сейчас мне потребовалось число на 128 бит, а кому-то надо работать с числами на 512 бит — и этот кто-то тоже захочет удобный инстумент.



Ещё Антон поведал, что есть два пути к решению: через ядро языка и через библиотеку. Существует мнение, и я его разделяю, что синтаксис языка и так достаточно сложен: добавить в язык конструкцию, которая обеспечит кроссплатформенную и эффективную возможность использовать числа разной точности, будет очень непросто. А вот в рамках библиотеки справиться вполне реально: шаблоны — наше всё. «Нужен работающий прототип, — сказал Антон. — И желательно с тестами». А ещё выяснилось, что тип должен быть plain old data (POD), чтобы понравиться большему количеству людей.



И я пошёл делать прототип. Название wide_int выбрал осознанно: устойчивых ассоциаций с таким названием нет, во всяком случае — распространённых. Например, big_number мог ввести в заблуждение — мол, он хранит значение в куче (heap) и никогда не переполняется. Хотелось получить тип с поведением, аналогичным поведению фундаментальных типов. Хотелось сделать тип, размер которого будет продолжать их прогрессию: 8, 16, 32, 64… 128, 256, 512 и т. д. Через какое-то время появился работающий прототип. Сделать его оказалось несложно: он должен был компилироваться и работать, но необязательно по-настоящему эффективно и быстро.



Антон его изучил, сделал ряд замечаний. Например, не хватало преобразования к числам с плавающей точкой, надо было пометить максимальное число методов как constexpr и noexcept. От идеи так ограничивать выбор размера числа Антон меня отговорил: сделал размер, кратный 64. После этого мы совместно с Антоном написали текст самого предложения. Оказалось, что писать документ гораздо сложнее, чем писать код. Ещё немного шлифовки — и Антон (как единственный понимающий, что делать дальше) начал показывать наше предложение людям из комиссии по стандартизации.



Критиковали немного. Например, кто-то высказал желание сделать целочисленный тип, который не переполняется. Или тип, размер которого можно задать с точностью до бита (и получить, например, размер в 719 бит!). Предложение отказаться от привязки к количеству бит, а задавать количество машинных слов, мне показалось самым странным: бизнес-логике всё равно, сколько слов в числе на какой-то платформе, — ей важно однозначно определять одни и те же числа на разных платформах. Скажем, уникальный идентификатор пользователя — беззнаковое целое число из 64 бит, а не из одного unsigned long long.



Если в двух словах, это были идеи для других типов. Критику мы выслушали, каких-то существенных замечаний не оказалось. После этого Антон опубликовал предложение к стандарту и поехал его защищать на очередное заседание комиссии.



Защита прошла успешно: наше предложение взяли в работу — другими словами, оно будет рассматриваться на заседаниях и дальше. Был высказан ряд замечаний; сейчас мы вносим нужные исправления. В частности, комиссия всё-таки попросила в wide_int оперировать количеством машинных слов. Аргументация проста: тип так или иначе будет реализован, но если использовать эти самые машинные слова, то выйдет эффективнее. У меня остаётся надежда, что удобный алиас uint128_t попадёт в стандарт — тогда я смогу выкинуть свой тип UInt128, пока его не увидел кто-то ещё. =)



Актуальную версию имплементации можно найти здесь. Ещё есть документ и небольшое обсуждение на stdcpp.ru. Всего со дня отправки первого письма на cpp-proposal@yandex-team.ru прошло около четырёх месяцев. Из них около 40 часов нерабочего времени мною было потрачено на это предложение. На момент написания статьи имплементация распухла на 1622 строки, да ещё тесты добавили 1940 строк.



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



Во-вторых, я могу изменить C++ в ту сторону, которая мне нравится. Конечно, тут важно помнить, что для реализации любой крупной идеи нужны единомышленники. Например, есть идея сделать интерфейс для контейнеров и строк чуть более выразительным и очевидным: я хотел добавить контейнерам operator bool(). Но неравнодушные к C++ коллеги дали понять, что я неправ.



В-третьих, я много нового для себя узнал о шаблонах в С++.



В-четвёртых, говорят, что это как-то усилит моё резюме… Пока не проверял, но поверю опытным коллегам на слово.



В-пятых, когда Бьярне Страуструп где-то в переписке, посвящённой обсуждению твоей работы, пишет кому-то «+1» — это весело. =) Даже если он поддерживает чью-нибудь критику.



Напоследок скажу, что про новости и мероприятия РГ21 С++ можно узнавать, подписавшись в Твиттере на канал stdcppru.

Original source: habrahabr.ru.

https://habrahabr.ru/post/327080/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

…And Justice for All

Четверг, 20 Апреля 2017 г. 19:10 (ссылка)

Коллега IvanKlut в своей статье "В поисках идеальной модели лицензирования" поднял вопрос о несовершенстве существующих лицензий, используемых при разработке OpenSource-проектов, с точки зрения монетизации усилий разработчиков, и предложил "поразмыслить об устройстве более эффективной экосистемы разработки сложных программных продуктов сообществом независимых разработчиков" (с).



image

Под катом мои субъективные соображения на этот счет.



Централизованное распределение дохода



Как мне кажется, в предлагаемой коллегой схеме "Нужна некоммерческая организация, целью которой является обеспечение устойчивого развития проекта и максимальная доступность для потребителей при достаточном ресурсном обеспечении" не хватает толики анархии.



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



У меня есть некоторый опыт разработки модулей в подобной структуре, правда это коммерческая структура (но это-то как раз и естественно, коль мы обсуждаем монетизацию разработки). Я имею в виду мою "любимую" Magento (нет, и вправду любимую — я все-таки на нее потратил лет 6 своей жизни). Так вот, платформа Magento CE вполне себе даже бесплатна (в отличие от Enterprise Edition), а вот стоимость некоторых модулей для нее может достигать 5-х значных чисел в американской валюте.



Некоторая аналогия с предложением коллеги IvanKlut прослеживается также и в размещении приложений (модулей) на таких сервисах как Google Play (проект — Android) и App Store (проект — Apple).



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



Delegation pattern



А что будет, если применить к сложившейся ситуации шаблон делегирования? Допустим, разработчик не заморачивается сам сбором денег с потребителя его продукта, а делегирует ответственность за эту хлопотную работу некоему "связанному объекту"? Назовем этот объект Агентом — по аналогии с Риком Пеком, агентом актера Тагга Спидмена (фильм "Tropic Thunder")



image



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



Так вот, пусть Разработчик пишет программы, а Агент собирает для него деньги с Потребителя, использующего эти программы в коммерческих целях. Справедливо ведь, что Разработчик может рассчитывать на часть коммерческой прибыли, получаемой Потребителем за счет его программ? Уверен, что разработчики сочтут этот вопрос риторическим.



Для чего вводить Агента посредником? Мне кажется, что каждый должен заниматься своим делом: разработчик — разрабатывать программы, актер — играть на сцене и в кино, предприниматель — зарабатывать деньги, а агент — представлять чьи-то интересы. Ну а что делать, если Тагг Спидмен лучше играет в кино, а с Лессом Гроссманом лучше говорит о деньгах Рик Пек?! Это очевидно — Таггу лучше продолжать играть, а Рику — продолжать говорить о деньгах. Не стоит им меняться местами, не выйдет из этого ничего путевого.



Хорошо, допустим, Разработчик делегировал Агенту право собирать плату за разработанный им продукт с Потребителя. Где гарантия, что деньги полученные Агентом дойдут хоть в каком-то виде до Разработчика? Ведь это далеко не риторический вопрос.



Я бы сказал так, до Разработчика дойдет ровно столько денег, сколько нужно, чтобы он сидел, развивал свой продукт дальше и не сильно интересовался окружающим миром в целом и стоимостью его продукта для конечного Потребителя в частности. Ну а разве не в этом и заключается цель большинства Разработчиков свободного ПО — иметь возможность развивать свой продукт?



Будет ли разделен полученный доход Агентом по справедливости? Уверен, что — да! Как минимум с точки зрения того, кто этот доход делит. А что делать, если сам Разработчик считает иначе? Ответ прост — уволить Агента и делегировать его обязанности другому Агенту. А лучше — другим Агентам.



У каждого Агента свой стиль работы, своя "потребительская ниша". Это актеру тяжело сниматься в 100500 фильмах одновременно, а Разработчику написать программу, которая будет работать в 100500 коммерческих проектах вполне по силам. Вот пусть Агенты и представляют его интересы в этих самых 100500 проектах. Если нужно — пусть хоть по одному Агенту на проект. На каких условиях Агент продает его продукт? Да на каких продается — продукт стоит столько, за сколько его можно продать. Больше Агентов, хороших и разных. Самое главное, чтобы у Разработчика была возможность "уволить" любого Агента, если он не доволен по каким-то причинам его работой.



И у меня есть подозрения, что хорошие Агенты смогут представлять интересы не одного Разработчика, а интересы сразу множества Разработчиков. Причем самых разных проектов — начиная с jQuery, и заканчивая ядром Линукса (хотя там с монетизацией все более-менее, разве нет?).



Таким образом, имеем как раз "сложную систему со множеством независимых субъектов" (ну, или слабо-зависимых). Агенты зависят от множества Разработчиков, а Разработчик — от множества Агентов. В целом, отдельная связка "Агент РП — Разработчик ТС" в данной композиции ничего не решает и с легкостью может быть разорвана любой стороной. Но вот если все Агенты разорвут свои отношения с конкретным Разработчиком или все Разработчики — с конкретным Агентом, то для этой конкретной стороны игра может закончиться.



С моей точки зрения, подобная ситуация должна стимулировать все элементы этой мозаики придерживаться стратегии "win-win", что должно пойти на пользу индустрии в целом.



"Что делать?" (с)



И как нам дойти до жизни такой? Пусть специалисты по лицензированию меня поправят, но мне кажется, что достаточно вставить следующие 3 пунта в некторые лицензии типа MIT и BSD, чтобы предпосылки для подобной жизни начали создаваться и накапливаться. Вот эти три пункта:




  • Любая институция, имеющая законные права на проведение финансовых операций и признающая условия данной лицензии, может выступать Агентом, представляя коммерческие интересы Владельца данного ПО, если только Владелец в явном виде не ограничил список приемлемых для него Агентов.

  • В случае прямого коммерческого использования данного ПО конечный выгодополучатель обязуется приобрести право коммерческого использования у любого Агента, приемлемого для Владельца данного ПО.

  • В случае коммерческого использования данного ПО в составе другого ПО, конечный выгодополучатель обязуется приобрести право коммерческого использования на весь комплект программного обеспечения у любого Агента, приемлемого для Владельца данного ПО.



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



Владельцу (разработчику) даже не нужно самому следить за тем, чтобы пользователи выполняли этих три пункта. Достаточно добавить их в лицензионное соглашение. Как только сложится такая ситуация, что станет возможно вести коммерчески выгодную деятельность по взыманию денег с выгодополучателей, я уверен, что сразу же появятся Агенты. Не зря ведь бытует мнение, что "нет такого преступления, на которое не пошел бы капитал при 300% прибыли". А тут даже и на преступление идти нет нужды.



Ну а если даже такие парни, как Лесс Гросманн и Рик Пек не смогут извлечь из твоей программы доход, то куда уж тебе, простому разработчику, впрягаться? Программируй и далее своего питомца в свободное от основной работы время.



И самое главное



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


Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/327000/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

[Перевод] Нативные ECMAScript модули — первый обзор

Среда, 19 Апреля 2017 г. 10:45 (ссылка)

Бандлеры и компайлеры против нативных модулей



В этой статье хочу поделиться переводом статьи о нативных ECMAScript модулях, которые все больше и больше обсуждаются среди фронтендеров. Javascript ранее никогда не поддерживал нативно работу с модулями, и нам, фронтендерам, всегда приходилось использовать дополнительные инструменты для работы с модулями. Но вы только представьте, что в скором времени не нужно будет использовать Webpack для создания бандлов модулей. Представьте мир, в котором браузер будет собирать все за вас. Подробнее об этих перспективах я и хочу рассказать.



В 2016 году в браузеры и Nodejs было добавлено много интересных фич и полезностей из новых стандартов, в частности спецификации ECMAScript 2015. Сейчас мы сталкиваемся с ситуацией, когда поддержка среди браузеров близка к 100%:



Таблица совместимости EcmaScript 6



Также фактически в стандарт введены ECMAScript модули (часто называют ES/ES6 модули). Это единственная часть спецификации, которая требовала и требует наибольшего времени для реализации, и ни один браузер пока не выпустил их в стабильной версии.



Недавно в Safari 19 Technical Preview и Edge 15 добавили реализацию модулей без использования флагов. Уже близится то время, когда мы можем отказаться от использования привычных всем бандлов и транспиляции модулей.



Чтобы лучше понять, как мир фронтенда пришел к этому, давайте начнем с истории JS модулей, а затем взглянем на текущие преимущества и реализации ES6 модулей.



Немного истории



Было много способов подключения модулей. Приведу для примера наиболее типичные из них:



1. Просто длинный код внутри script тега. Например:







2. Разделение логики между файлами и подключение их с помощью тегов script:

/* js */

// module1.js
// module1 code

// module2.js
// module2 code







3. Модуль как функция (например: модуль функция, которая возвращает что-то; самовызывающаяся функция или функция конструктор) + Application файл/модель, которые будут точкой входа для приложения:



// polyfill-vendor.js
(function(){
// polyfills-vendor code
}());

// module1.js
function module1(params){
// module1 code
return module1;
}

// module3.js
function module3(params){
this.a = params.a;
}

module3.prototype.getA = function(){
return this.a;
};

// app.js
var APP = {};

if(isModule1Needed){
APP.module1 = module1({param1:1});
}

APP.module3 = new module3({a: 42});









Ко всему этому Frontend сообщество изобрело много разновидностей и новых способов, которые добавляли разнообразие в этот праздник анархии.



Основная идея заключается в том, чтобы обеспечить систему, которая позволит вам просто подключить одну ссылку JS файла, вот так:







Но всё свелось к тому, что разработчики выбрали сторону бандлеров — систем сборки кода. Далее предлагается рассмотреть основные реализации модулей в JavaScript.



Асинхронное определение модуля (AMD)



Такой подход широко реализуется в библиотеке RequireJS и в инструментах, таких как r.js для создания результирующего бандла. Общий синтаксис:



// polyfill-vendor.js
define(function () {
// polyfills-vendor code
});

// module1.js
define(function () {
// module1 code
return module1;
});

// module2.js
define(function (params) {
var a = params.a;

function getA(){
return a;
}

return {
getA: getA
}
});

// app.js
define(['PATH/polyfill-vendor'] , function () {
define(['PATH/module1', 'PATH/module2'] , function (module1, module2) {
var APP = {};

if(isModule1Needed){
APP.module1 = module1({param1:1});
}

APP.module2 = new module2({a: 42});
});
});


CommonJS



Это основной формат модулей в Node.js экосистеме. Одним из основных инструментов для создания бандлов для клиентских устройств является Browserify. Особенность этого стандарта — обеспечение отдельной области видимости для каждого модуля. Это позволяет избежать непреднамеренной утечки в глобальную область видимости и глобальных переменных.



Пример:



// polyfill-vendor.js
// polyfills-vendor code

// module1.js
// module1 code
module.exports= module1;

// module2.js
module.exports= function(params){
const a = params.a;

return {
getA: function(){
return a;
}
};
};

// app.js
require('PATH/polyfill-vendor');

const module1 = require('PATH/module1');
const module2 = require('PATH/module2');

const APP = {};

if(isModule1Needed){
APP.module1 = module1({param1:1});
}

APP.module2 = new module2({a: 42});


ECMAScript модули (ака ES6/ES2015/нативные JavaScript модули)



Еще один способ работы с модулями пришел к нам с ES2015. В новом стандарте появился новый синтаксис и особенности, удовлетворяющие потребностям фронтенда, таким как:




  • отдельные области видимости модулей

  • строгий режим по умолчанию

  • циклические зависимости

  • возможность легко разбить код, соблюдая спецификацию



Есть множество реализаций загрузчиков, компиляторов и подходов, которые поддерживают одну или несколько из этих систем. Например:





Инструменты



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





Как правило, инструмент предоставляет CLI интерфейс и возможность настроить конфигурацию для создания бандлов из ваших JS файлов. Он получает точки входа и набор файлов. Обычно такие инструменты автоматически добавляют “use strict”. Некоторые из этих инструментов также умеют транспилировать код, чтобы заставить его работать во всех окружениях, которые необходимо (старые браузеры, Node.js и т.д.).



Давайте посмотрим на упрощенной WebPack конфиг, который устанавливает точку входа и использует Babel для транспиляции JS файлов:



// webpack.config.js
const path = require('path');

module.exports = {
entry: path.resolve('src', 'webpack.entry.js'),
output: {
path: path.resolve('build'),
filename: 'main.js',
publicPath: '/'
},
module: {
loaders: {
"test": /\.js?$/,
"exclude": /node_modules/,
"loader": "babel"
}
}
};


Конфиг состоит из основных частей:


  1. начинаем с файла webpack.entry.js

  2. используем Babel лоудер для всех файлов JS (то есть, код будет транспилироваться в зависимости от пресетов/плагинов + сгенерируется бандл)

  3. Результат помещается в файл main.js



В этом случае, как правило, файл index.html содержит следующее:






И ваше приложение использует бандлы/транспилируемый код JS. Это общий подход для работы с бандлерами, давайте посмотрим, как заставить его работать в браузере без каких-либо бандлов.



Как сделать так, чтобы JavaScript модули работали в браузере



Поддержка Браузеров



На сегодняшний день каждый из современных браузеров имеет поддержку модулей ES6:





Где можно проверить



Как вы видели, в настоящее время можно проверить нативные JS модули в Safari Technology Preview 19+ и EDGE 15 Preview Build 14342+. Давайте скачаем и попробуем модули в действии.



Safari Technology Preview с доступными ES модулями



Если вы используете MacOS, достаточно просто загрузить последнюю версию Safari Technology Preview (TP) с developer.apple.com. Установите и откройте его. Начиная с Safari Technology Preview версии 21+, модули ES включены по умолчанию.



Если это Safari TP 19 или 20, убедитесь, что ES6 модули включены: откройте меню «Develop» -> «Experimental Features» -> «ES6 Modules».



image



Другой вариант — скачать последнюю Webkit Nightly и играться с ним.



EDGE 15 — включаем ES модули



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



Просто выберите виртуальную машину (VM) «Microsoft EDGE на Win 10 Preview (15.XXXXX)» и, например, «Virtual Box» (также бесплатно) в качестве платформы.



Установите и запустите виртуальную машину, далее откройте браузер EDGE.



Зайдите на страницу about:flags и включите флаг «Включить экспериментальные функции JavaScript» (Enable experimental JavaScript features).







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



Отличия родных и собранных модулей



Давайте начнем с нативных особенностей модулей:




  1. Каждый модуль имеет собственную область видимости, которая не является глобальной.

  2. Они всегда в строгом режиме, даже когда директива «use strict» не указана.

  3. Модуль может импортировать другие модули с помощью import директивы.

  4. Модуль может экспортироваться с помощью export.



До сих пор мы не увидели особенно серьезные отличия от того, к чему мы привыкли с бандлерами. Большая разница в том, что точка входа должна быть предусмотрена в браузере. Вы должны предоставить script тег с конкретным атрибутом type=«module», например:

  


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

Почему интерпретатор JavaScript не может определять модули, если файл и так по сути является модулем?


Одна из причин — нативные модули в строгом режиме по умолчанию, а классические script-ы нет:




  1. скажем, интерпретатор анализирует файл, предполагая, что это классический сценарий в нестрогом режиме;

  2. потом он находит «импорт\экспорт» директивы;

  3. в этом случае, он должен начать с самого начала, чтобы разобрать весь код еще раз в строгом режиме.



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



Определение типа ожидаемой загрузки файла открывает множество способов для оптимизации (например, загрузка импортируемых файлов параллельно/до парсинга оставшейся части файла html). Вы можете найти некоторые примеры, используемые движками Microsoft Chakra JavaScript для модулей ES.



Node.js способ указать файл как модуль



Node.js окружение отличается от браузеров и использовать тег script type=«module» не особо подходит. В настоящее время все еще продолжается спор, каким подходящим способом сделать это.



Некоторые решения были отклонены сообществом:




  1. добавить «use module» к каждому файлу;

  2. метаданные в package.json.



Другие варианты все еще находятся на рассмотрении (спасибо @bmeck за подсказку):


  1. определение, если файл является ES модулем;

  2. новое расширение файла для ES6 Модули .mjs, которое будет использоваться в качестве запасного варианта, если предыдущая версия не сработает.



Каждый метод имеет свои плюсы и минусы, и в настоящее время до сих пор нет четкого ответа, каким путем Node.js будет идти.



Простой пример нативного модуля



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












Вот файл модуля:

// main.js
import utils from "./utils.js";

utils.alert(`
JavaScript modules work in this browser:
https://blog.whatwg.org/js-modules
`);


И, наконец, импортированные утилиты:

// utils.js
export default {
alert: (msg)=>{
alert(msg);
}
};


Как вы могли заметить, мы оставили расширение файла .js, когда используется директива import. Это еще одно отличие от поведения бандлеров — нативные модули не добавляют .js расширения по умолчанию.



Во-вторых, давайте проверим область видимости у модуля (демо):

var x = 1;

alert(x === window.x);//false
alert(this === undefined);// true


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

// module.js
var x;
delete x; // !!! syntax error

alert(`
THIS ALERT SHOULDN'T be executed,
the error is expected
as the module's scripts are in the strict mode by default
`);

// classic.js
var x;
delete x; // !!! syntax error

alert(`
THIS ALERT SHOULD be executed,
as you can delete variables outside of the strict mode
`);


Строгий режим нельзя обойти в нативных модулях.



Итого:




  • .js расширение не может быть опущено;

  • область видимости не является глобальной, this ни на кого не ссылается;

  • нативные модули в строгом режиме по умолчанию (больше не требуется писать «use strict»).





Встроенный модуль в тег script



Как и обычные скрипты, вы можете встраивать код, вместо того, чтобы разделять их по отдельным файлам. В предыдущем демо вы можете просто вставить main.js непосредственно в тег script type=«module» что приведет к такому же поведению:



Итого:




  • script type=«module» можно использовать как для загрузки и выполнения внешнего файла, так и для выполнения встроенного кода в тег script.





Как браузер загружает и выполняет модули



Нативные модули (асинхронные) по умолчанию имеют поведение deffered скриптов. Чтобы понять это, мы можем представить каждый тег script type=«module» с атрибутом defer и без. Вот изображение из спецификации, которое объясняет поведение:





Это означает, что по умолчанию скрипты в модулях не блокируют, загружаются параллельно и выполняются, когда страница завершает парсинг html. Вы можете изменить это поведение, добавив атрибут async, тогда скрипт будет выполнен, как только он загрузится.



Главное отличие нативных модулей от обычных скриптов заключается в том, что обычные скрипты загружаются и выполняются сразу же, блокируя парсинг html. Чтобы представить это, посмотрите демо с разными вариантами атрибутов в теге script, где первым будет выполнен обычный скрипт без атрибутов defer \ async:
















Порядок загрузки зависит от реализации браузеров, размера скриптов, количества импортируемых скриптов и т. д.



Итого:




  • модули по умолчанию асинхронны и ведут себя как deffered скрипты



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



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



Если хотите узнать больше сейчас, предлагаю пройтись по ссылкам:



Честно говоря, когда я пробовал нативные модули в первый раз, и они заработали в браузере, я почувствовал то, чего не чувствовал с появлением таких языковых фич, как const/let/arrow functions и прочих новомодных фишек, когда они начали работать непосредственно в браузерах. Я надеюсь, что вы будете, как и я, рады добавлению нативного механизма работы с модулями в браузеры.



Другие статьи автора по данной теме





От переводчика



Я Frontend разработчик в команде Авиа в Tutu.ru. Сейчас у нас в проектах используется Webpack в качестве бандлера. Есть легаси код и старые проекты с RequireJS. Нативные модули очень интересны и ждем их с нетерпением, тем более мы уже перевели все наши проекты на HTTP/2. Конечно, совсем без бандлеров обходиться мы не собираемся, так как у нас большое количество модулей во всех проектах. Но приход нативных модулей мог бы поменять воркфлоу сборки и деплоя.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/326716/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Безопасность OAuth в эпоху мобильных приложений, или о чем молчит интернет

Четверг, 13 Апреля 2017 г. 07:31 (ссылка)

image



«В API ВКонтакте для получения ключа доступа используется открытый протокол OAuth 2.0. При этом пользователь не передает логин и пароль приложению, поэтому его аккаунт не может быть скомпрометирован»документация VK API.



«ОАuth — это открытый протокол, предоставляющий простой и безопасный способ авторизации для мобильных, десктопных и веб приложений» — вольный перевод слогана oauth.net.



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



Материал насыщен специфической терминологией и рассчитан на подготовленного читателя.





От автора



Автор не является экспертом в области информационной безопасности и не претендует на 100% правоту. Эссе написано скорее с целью пробудить в читателе здоровое любопытство и критическое отношение к используемым технологиям и областям их применимости, чем в попытке разжечь пламя войны с какой-либо сложившейся парадигмой. Все нижесказанное в той или иной степени справедливо для других подобных протоколов и способов контроля доступа к публичному API.



Исторические предпосылки



Мы живем в эпоху стремительно развивающихся технологий. Получая в распоряжение что-то новое, мы начинаем активно его эксплуатировать, раздвигать границы применимости, решать все более комплексные и разнообразные задачи, часто при этом руководствуясь методом познания из серии: «Работает и ладно», «Это помогло мне решить ту задачу, значит поможет и с этой», «Этим пользуется много людей, значит это хорошо». Такой подход естественен, так как работает в большинстве ситуаций и позволяет получать результаты не затрачивая излишнее количество времени и усилий, особенно в случае когда результатом нашего труда будут пользоваться небольшое количество людей, и в случае если цена ошибки невелика. Одной из технологий, границы использования которой были раздвинуты подобным образом, на мой взгляд, является OAuth.



Для начала немного истории: если верить википедии, то работа над протоколом началась в ноябре 2006 года, а OAuth версии 1.0 был утвержден 4 декабря 2007 года. То было время когда Firefox начал основательно теснить Internet Explorer не только на компьютерах веб-разработчиков и интернет-гиков, но и на машинах обычных людей; Facebook стал доступен для всех пользователей интернета, появился ВКонтакте, а Gmail открыл регистрацию без инвайтов; мобильный интернет был медленным, а смартфоны — малораспространенными. Таким образом, разработчики стандарта OAuth естественным образом полагали, что браузер — безопасный, доверенный и единственный способ доступа пользователя к интернет-ресурсам. Ответственность же за доверенность и безопасность браузера возлагалась на пользователя (в виде необходимости установки обновлений и слежения за отсутствием вирусов на ПК) и разработчиков (в виде необходимости поставлять эти самые обновления). Такая система была актуальна и достаточно хорошо работала до тех пор, пока не произошел очередной скачок технологий: в июне 2007 года поступает в продажу первый iPhone, затем в сентябре 2008 выходит первая версия ОС Android.



Безопасность пользователей



Почему же выход на рынок (а точнее — повсеместное распространение) мобильных платформ делает предположение о доверенности браузера неактуальным?



Разработчики мобильных платформ предоставили программистам достаточно широкие возможности для написания приложений, в том числе и свободный доступ к стеку TCP/IP. В результате пользователь не может теперь быть уверенным, где же на самом деле он вводит свой логин и пароль, для него не существует способа узнать, действительно ли данная веб-форма открыта с нужного веб-сайта (если например используется WebView), не перехватываются ли нажатия клавиш или введенные данные недобросовестным разработчиком приложения. Более того, разработчики мобильных платформ, неохотно расширяя API для встроенных браузеров, только усугубляют такое положение дел.



Можно возразить, что пользователю надо быть внимательнее, не стоит вводить логин и пароль от своей социальной сети в первом встречном приложении которые вы установили с маркета, пусть даже форма ввода пароля и выглядит как настоящая. И вообще, если у вас запрашивают пароль — это явный признак того, что что-то идет не так, ведь честное приложение наверняка использует SDK авторизации соответствующей социальной сети. Но на практике пользователи так привыкли к кнопочкам «Зайти через ВКонтакте» и «Login with Facebook» у себя в браузерах, что их не смутит, если по такой же кнопке в приложении появится соответственно выглядящая форма для ввода логина и пароля. Даже при том, что они будут мучительно вспоминать когда-то давно измененный и один-два раза введенный пароль. Таким образом проблема фишинга, которая достаточно остро стояла для OAuth даже в случае его использования через браузеры, поднимается на совершенно новый уровень.



Что же на это говорят нам разработчики OAuth? В OAuth 2.0, увидевшем свет в октябре 2012, о мобильных приложениях нет ни слова. В предварительном же варианте документа под названием OAuth 2.0 for Native Apps, появившемся лишь в феврале 2016, разработчикам приложений и OAuth провайдеров предлагается постараться сделать так, чтобы пользователю не приходилось часто вводить пароль или показывать какую-то информацию связанную с аккаунтом с которого был произведен вход. Таким образом пользователь сможет заподозрить что-то неладное в случае со зловредным приложением.



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



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



Проблемы OAuth провайдера



Все становится гораздо интереснее, если мы сами захотим стать (или уже являемся) OAuth провайдером. Допустим, у нас реализован autorization code flow и API используется только для подконтрольных сервисов — вроде бы пока все неплохо. Затем появилась необходимость сделать доступ для внешних сервисов: «Конечно, без проблем, OAuth ведь для этого и предназначен, разве нет?» — думаем мы. Но тут закрадывается мысль: а какие конкретно внешние сервисы будут нами пользоваться? А вдруг эти сервисы будут на самом деле мобильными приложениями? Как в таком случае приложения смогут гарантировать безопасность своих client_id и client_secret? Как в таком случае мы сможем узнать — не прикидывается ли какое-нибудь зловредное приложение вполне безобидным и от его имени творит всякие безобразия?



К сожалению, OAuth2 не дает ответа на этот вопрос, лишь в пункте 10.1 RFC6749 говорится о том, что запрещено (!!!) использовать пароль (речь идет про client_secret) для аутентификации OAuth клиентов, реализованных в виде мобильных или клиентских приложений, за исключением случая, когда этот пароль (и уникальный client_id) выдаются отдельно для каждой конкретной установки приложения на пользовательское устройство (но нас вряд ли интересует такой случай). Драфт «OAuth для мобильных клиентов» только лишь начиная с версии от 2 марта 2017 (пункты 8.8, 8.9) предлагает использовать App-claimed HTTPS URI Redirection, но не говорит о том, что безопасная версия такого подхода доступна только для iOS 8, Android 6.0 и выше. Такой подход хоть и оберегает пользователя от зловредных приложений, но некоим образом не помогает OAuth провайдеру обнаружить зловредный клиент, завладевший чужим client_id. При этом стандарт не дает никаких рекомендаций по поводу того, как же наша реализация провайдера будет отличать мобильные приложения от серверных. Т.е. фактически, безопасность client_secret целиком в руках клиента, который может быть и вне нашего контроля.



Ну что ж, раз стандарт нам не помощник, то будем пользоваться собственным здравым смыслом. Допустим, нам нужно пускать только серверные приложения — тут все относительно просто: нужно к каждому client_id привязать IP адрес (или несколько) с которого он может отправлять запросы на получение токена. Можно даже предоставить пользовательский интерфейс для заполнения этого списка, главное только контролировать, чтобы этих адресов было не слишком много. А то введет кто-нибудь целую подсеть какого-нибудь хостинг-провайдера, и прости-прощай вся безопасность: злоумышленнику будет достаточно поселиться с клиентом в одном дата-центре.



Хорошо, а что делать, если нужно все-таки предоставлять доступ и мобильным приложениям? В случае если пользование нашим сервисом подразумевает под собой некоторую плату и приложение находится под нашим контролем, то можно задействовать механизм счетов, предоставляемых AppStore и Play Market-ом по факту совершения покупки. Эти счета содержат Bundle ID приложения, привязаны к конкретному пользователю и их можно проверить на стороне сервера, отправив запрос в Apple или Google. Проверку счета можно связать, например, с обновлением access или refresh токена.



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



В том случае, когда круг пользователей нашего приложения достаточно хорошо нам известен (например работники предприятия) и контролируется, то для авторизации клиента можно задействовать клиентские сертификаты. С другой стороны, если на предприятии активно используются пользовательские сертификаты, то контроль доступа к API вероятно будет удобнее осуществить на базе TLS, а не реализовывать собственное расширение OAuth.



Если все-таки круг пользователей приложения достаточно широк, и мы не хотим заставлять пользователей совершать покупки и вводить данные своей карточки? Некоторое время назад у нас оставалась только одна возможность: обфускация client_id (client_secret) в нашем приложении и затруднение перехвата нешифрованного трафика в сетевом стеке ОС. Устойчивая ко взлому реализация такой задачи требует как высокого уровня подготовки специалистов, так и больших временных затрат; и таким образом практически недоступна для небольших компаний и программистов-фрилансеров.



К счастью, начиная с некоторого момента, компания Google предоставляет сервис SafetyNet, который позволяет узнать отпечаток ключа, которым было подписано приложение, а также его Bundle ID и проверить эти данные на стороне сервера (увы, при проверке работоспособности сервиса не получилось получить ответ отличный от {"isValidSignature": false}). Этот API поставляется как часть Google Play Services и, теоретически, доступен начиная с Android 2.3 при условии обновления Play сервисов.



Остается открытым вопрос, позволяет ли SafetyNet проверять данные приложений опубликованных другими разработчиками, и, следовательно, можем ли мы использовать его для контроля доступа к нашему API со стороны других приложений? Документация не дает явного ответа на этот вопрос, но написана в ключе, который не подразумевает такого сценария. Также Google Play Services доступны не для всех стран и могут отсутствовать на телефонах китайских производителей.



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



Что же делать, если ни один из предложенных вариантов нам не подходит? Тогда нам, как разработчикам публичного API, придется иметь в виду, что достоверно различать приложения клиентов мы не можем, и пользователь фактически не имеет контроля над тем, какие ресурсы API каким приложениям он предоставляет. То есть мы не можем опираться на концепции scope и client_id из OAuth, что составляет примерно половину возможностей, предоставляемых протоколом. Либо, при наличии достаточной компетенции и ресурсов, мы можем внедрить на серверной стороне какие-либо эвристические алгоритмы для определения запросов с поддельным client_id.



Надеюсь, что крупные OAuth провайдеры используют один из последних двух (остальные накладывают слишком жесткие ограничения), предложенных здесь способов обхода проблем OAuth. Косвенно об этом может свидетельствовать к примеру то, что раньше ВКонтакте давал доступ к электронной почте пользователя только определенным доверенным приложениям, теперь же такой запрос включен в публичный API.



Итого



Из всего вышесказанного можно сделать вывод, что OAuth на самом деле очень далек от того уровня безопасности, который мы привыкли подразумевать, используя такие промышленные технологии как TLS или SSH. При реализации OAuth провайдера необходимо очень аккуратно взвесить пользу от его внедрения и все потенциальные проблемы безопасности. Также требуется реализация подходящих механизмов обхода описанных выше проблем, так как ни одна из известных автору библиотек для популярных web-фреймворков их не учитывает. Для доступа к API со стороны мобильных приложений может иметь смысл разработка собственного SDK, использующего наиболее безопасные для пользователя методы взаимодействия с OAuth.



Автор благодарит своих друзей и коллег за конструктивные комментарии и помощь при подготовке данного материала и отдельно — Сергея Маккену за помощь в исследовании возможностей Apple iOS SDK.



Логотип OAuth разработан Chris Messina и распространяется по Creative Commons Attribution ShareAlike 3.0 лицензии.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/320744/

Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

[Перевод] Раскрываем тему WebAssembly с Бренданом Айком

Вторник, 12 Апреля 2017 г. 00:07 (ссылка)

https://habrahabr.ru/post/326276/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество

Следующие 30  »

<стандарты - Самое интересное в блогах

Страницы: [1] 2 3 ..
.. 10

LiveInternet.Ru Ссылки: на главную|почта|знакомства|одноклассники|фото|открытки|тесты|чат
О проекте: помощь|контакты|разместить рекламу|версия для pda