Я решил, что правильно будет разделить все приводимые понятия на уровни, чтобы шаг за шагом пройти наиболее часто встречающиеся термины, начав с самых азов. Однако, надо понимать, что здесь не будет разбора совсем базы, вроде видов http-запросов или что такое "заголовок" - только понятия и примеры по теме
Уровень 1: Авторизация и аутентификация
Это два действия, с которых начинается любая интеграция.
Аутентификация - это проверка, при которой действующее лицо подтверждает свою личность. Когда вы, например, вводите свои данные для входа на каком-нибудь сайте, то это, в первую очередь - аутентификация. Вы подтверждаете, что вы - это вы, используя пароль, соответствующий вашему логину
Авторизация - это процесс проверки и выдачи прав соответственно вашему аккаунту. Войдя в свой профиль на сайте, вы получаете доступ к некоторому набору действий, которые были определены вам разработчиками и администраторами - но не более того
Аутентификация без авторизации возможна, но лишена смысла - система вас узнает, но ничего не даст сделать. Авторизация без аутентификации также возможна, но только если в системе предусмотрены действия, доступные для анонимных пользователей
Когда речь идет о http-запросах, то аутентификация и авторизация, как правило, совмещены. Внутри запроса (параметров, тела или заголовков) мы передаем сразу как данные аутентификации (например, токен) так и запрос на выполнение некоторых действий из списка тех, которые нам, потенциально, должны быть доступны. В случае, если аутентификация будет пройдена успешно, а авторизация подтвердит наличие прав на выполнение необходимого действия - мы получим необходимый результат
Уровень 2: Схемы Http-аутентификации/авторизации
Рассмотрим основные схемы аутентификации с примерами
Basic
Самый простой способ аутентификации: в заголовки запроса добавляется заголовок Authorization со значением Basic Логин:Пароль, где пара Логин:Пароль кодированы в Base64. Никакого дополнительного преобразования этих данных не требуется
Логин = "bayselonarrend";
Пароль = "14AB22";
Сервер = "exemple.com";
Адрес = "/api";
Заголовки = Новый Соответствие;
Basic = Логин + ":" + Пароль;
Basic = Base64Строка(ПолучитьДвоичныеДанныеИзСтроки(Basic));
Заголовки.Вставить("Authorization", "Basic " + Basic);
НовыйЗапрос = Новый HTTPЗапрос(Адрес, Заголовки);
SSL = Новый ЗащищенноеСоединениеOpenSSL;
Соединение = Новый HTTPСоединение(Сервер, 443, , , , 3000, SSL);
Ответ = Соединение.ВызватьHTTPМетод("GET", НовыйЗапрос);
На сегодняшний день такой способ является устаревшим и активно вытесняется, хотя при использовании https считается достаточно безопасным. Никаких хитрых решений для его обработки, в том числе и из 1С, не требуется
Digest
Более сложная система. Сервер по запросу отправляет клиенту некоторые данные (nonce), после чего клиент преобразует пару логин-пароль в MD5 хэш-строку на их основе. Практически не используется, так как требует хранения пароля в открытом виде на стороне сервера. Как способ аутентификации конкретно для API встречается еще реже, вероятно из-за необходимости отправки предварительного запроса получения nonce, что в обычной жизни берет на себя браузер
Про 1С:
MD5 в 1С реализуется штатными средствами через Новый ХешированиеДанных(ХэшФункция.MD5). Также реализация Digest есть в Коннекторе
Bearer
Пожалуй самый распространенный способ аутентификации на данный момент. Bearer - это любые, полученные пользователем от провайдера API, данные, которые при передаче в этот API подтверждают его (пользователя) личность. В большинстве случаев это текстовые токены того или иного формата
Authorization: Bearer 17fa874c-cdbf-49e5-88fc-625aa63b3b00
Например, вы регистрируетесь на портале ресурса, который предоставляет публичный API. После входа в некоторый "личный кабинет" при помощи логина и пароля, вам становится доступна функция генерации токена. Вы нажимаете на кнопку, копируете себе сгенерированную строку, после чего передаете её в каждом своем запросе к API. Эта строка - Bearer токен
Про 1С:
В зависимости от реализации API, Bearer можете передаваться в
- Заголовках запроса
Сервер = "exemple.com"; Адрес = "/api"; Токен = "17fa874c-cdbf-49e5-88fc-625aa63b3b00"; Заголовки = Новый Соответствие; Заголовки.Вставить("Authorization", "Bearer " + Токен); НовыйЗапрос = Новый HTTPЗапрос(Адрес, Заголовки); SSL = Новый ЗащищенноеСоединениеOpenSSL; Соединение = Новый HTTPСоединение(Сервер, 443, , , , 3000, SSL); Ответ = Соединение.ВызватьHTTPМетод("GET", НовыйЗапрос);
- В URL - как, например, у Telegram
https://api.telegram.org/bot61111111:AAFyzNBOAFfuhAL5GXqbVidwAAAAAAAA/getUpdates | | ------------------------------------------- Вот эта часть
- В теле запроса
Сервер = "exemple.com"; Адрес = "/api"; Токен = "17fa874c-cdbf-49e5-88fc-625aa63b3b00"; Параметры = "?my_token_field=" + Токен; Заголовки = Новый Соответствие; Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"); НовыйЗапрос = Новый HTTPЗапрос(Адрес, Заголовки); НовыйЗапрос.УстановитьТелоИзСтроки(Параметры); SSL = Новый ЗащищенноеСоединениеOpenSSL; Соединение = Новый HTTPСоединение(Сервер, 443, , , , 3000, SSL); Ответ = Соединение.ВызватьHTTPМетод("POST", НовыйЗапрос);
AWS4-HMAC-SHA256
Замороченный способ авторизации AWS и всех сочувствующих - поставщиков S3 в частности. Сводится к генерации авторизационных данных на основе не только лишь токена от провайдера, как в Bearer, но и на основе самого содержимого отправляемого запроса. Сформированные данные отправляются в заголовке Authorization
Authorization: AWS4-HMAC-SHA256
Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request,
SignedHeaders=host;range;x-amz-date,
Signature=fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024
Где:
- Строка1 - Наименование метода
- Строка2 - Строка <Ваш ID ключа доступа>/<Дата>/<Регион AWS>/<Сервис>/aws4_request
- Строка3 - Список передаваемых заголовков
- Строка4 - Сигнатура, вычисляемая по одному из доступных алгоритмов
Вычисление сигнатуры - вообще отдельная тема. Пока могу предложить только ссылки на ресурсы Amazon:
Для 1С:
AWS - сложный механизм, но благо на 1С уже есть реализации
OAuth
Стандарт авторизации, чем-то напоминающий AWS. При его использовании, для авторизации необходимо сформировать составную строку из различных данных, после чего передать её в качестве заголовка запроса
Из чего состоит авторизационная строка?
- OAuth - наименование стандарта
- oauth_consumer_key - секретный ключ от провайдера API
- oauth_token - токен от провайдера API
- oauth_signature_method - метод создания сигнатуры. Про сигнатуру будет далее.
- oauth_timestamp - временная отметка в UNIX Time
- oauth_nonce - любой уникальный идентификатор
- oauth_version - версия API
- oauth_signature - сигнатура
Из представленных выше частей наиболее загадочной является сигнатура. Давайте разбираться, что же это такое
Сигнатура - хэш, получаемый путем вычисления базовой строки при помощи метода, указанного в поле oauth_signature_method. Что же является базой сигнатуры?
Это соединение через & следующих данных:
- Вида запроса
- Целевого URL
- Всех полей авторизационной строки (из списка выше; в виде Ключ=Значение), но без поля oauth_signature
- Всех не-двоичных полей основного запроса (в виде Ключ=Значение).
При этом, все поля новой строки (кроме URL и вида запроса) должны быть предварительно отсортированы по алфавиту по названиям (ключам) полей и кодированы в кодировке URL. После соединения строки, она должна быть приведена к верхнему регистру
Т.е. после того, как '10 плюс Число полей в запросе минус oauth_signature' пунктов соединены (с кодированием значений в кодировке URL и в расстановке по алфавиту) в одну большую строку вида
POST&https%3A%2F%2Fexemple.com&ПОЛЕ1=<ЗНАЧЕНИЕ1>&ПОЛЕ2=<ЗНАЧЕНИЕ2>...OAUTH_CONSUMER_KEY=<КЛЮЧ>&OAUTH_TOKEN=<TOKEN>&OAUTH_TIMESTAMP=<UNIX TIME>&OAUTH_NONCE=<UID>&OAUTH_VERSION=<V>
данная строка прогоняется по алгоритму, указанному в oauth_signature_method. Список доступных алгоритмов определяется провайдером API (как правило, это какой-нибудь один метод). Обычно это алгоритмы HMAC и RSA с SHA хэшированием: HMAC-SHA1, HMAC-SHA256 (H256), RSA-SHA256 (R256) и др. - о них мы поговорим на следующем уровне. После прогона строки через алгоритм, полученное значение переводится в Base64Строка и кодируется в кодировке URL
В результате получается хэш, который и является сигнатурой - его значение дописывается в исходную строку:
OAuth oauth_consumer_key="<ключ>",oauth_token="<token>",oauth_timestamp="<unix time>",oauth_nonce="<uid>",oauth_version="<v>",oauth_signature="<Наша сигнатура>"
Для создания сигнатуры, алгоритму необходима не только база (наша строка), но и ключ - им может выступать строка <oauth_token> &<oauth_consumer_key>. Так или иначе - подобное будет оговорено в документации к конкретному API
Готовая строка передается в заголовке Authorization
Для 1С:
Пример создания заголовка
OAuth2
Сиквел OAuth, более щадящий в вопросах подготовки запроса, но более сложный в организационных вопросах. При его использовании нет необходимости собирать огромную авторизационную строку как у первого OAuth - используется просто обычный токен (т.е. в вопросах непосредственной отправки запроса, OAuth2 - это Bearer)
Основная суть тут уже в получении и обновлении данного токен. Принцип работы таков:
- Где-то в настройках API "для разработчиков" указывается redirect_url - адрес вашего ресурса, который будет готов принять внешний запрос с токеном. Говоря просто - это должен быть http-сервис с доступом извне. Т.е. без web-сервера ничего не получится
- Для получения токена, пользователь в браузере переходит на страницу авторизации и нажимает нечто вроде "Войти"
- После нажатия кнопки, Http-запрос с токеном отправляется по redirect_url. На нем наш обработчик должен забрать эти данные и сохранить
- В этом запросе есть два токена - обычный access_token (токен доступа), который и используется как раз для необходимых нам запросов и refresh_token (токен обновления), о котором далее
- Токен доступа (access_token) - не вечен. Время его жизни оговаривается в документации или летит отдельным полем в запросе из п.4 как expire. Для продолжения работы по истечении срока жизни токена, его необходимо обновить. Для этого отправляется особый запрос к API с refresh_token на борту
- В ответе этого "особого" запроса приходит новый access_token, а
у особо поехавших (привет, Twitter)в некоторых случаях - и новый refresh_token. Все это заменяет прошлые данные
- Пункты 5 и 6 повторяются периодически
|--> ОбновитьТокен() ->|access_token --> Используется в т-нии n часов для запросов | |refresh_token --| |--------[через n ч.]-------------------|
На самом деле, все мы сталкиваемся с подобным механизмом каждый день: "Войти при помощи Google/Yandex/VK ID" на разных сайтах - это реализация OAuth2, где сайт, на котором осуществляется вход, также получает токен нашего аккаунта с определенными правами (они, как правило, показываются на панели входа: "Получит доступ к адресу почты", "Получит доступ к номеру телефона" и все такое)
Для 1С:
Пример работы с OAuth и OAuth2 есть в реализации API Twitter в ОПИ
JWT
JWT (JSON Web Tokens) - не стандарт аутентификации, но скорее формат передачи подписанных данных. Готовые токены такого формата могут использоваться для передачи в качестве Bearer
JWT это JSON данные, состоящие из 3-х частей: заголовка, полезных данных и сигнатуры (подписи)
- Заголовок (header) - JSON-объект с информацией о способе вычисления подписи
{ "alg": "HS256", "typ": "JWT"}
- Данные (payload) - JSON-объект непосредственно с полезной нагрузкой
{ "Поле": "Значение" }
- Подпись (signature) - значение, вычисляемое следующим способом
СекретныйКлюч = "1111"; B64Заголовок = Base64UrlEncode(ПолучитьДвоичныеДанныеИзСтроки(Заголовок)); B64Данные = Base64UrlEncode(ПолучитьДвоичныеДанныеИзСтроки(Данные)); НеподписанныйТокен = B64Заголовок + "." + B64Данные; Сигнатура = Криптография.HMAC(ПолучитьДвоичныеДанныеИзСтроки(СекретныйКлюч) , ПолучитьДвоичныеДанныеИзСтроки(НеподписанныйТокен) , ХэшФункция.SHA256); Сигнатура = Base64UrlEncode(Сигнатура); ... Функция Base64UrlEncode(Знач Значение) Ответ = Base64Строка(Значение); Ответ = СтрРазделить(Ответ, "=")[0]; Ответ = СтрЗаменить(Ответ, Символы.ВК + Символы.ПС, ""); Ответ = СтрЗаменить(Ответ, "+", "-"); Ответ = СтрЗаменить(Ответ, "/", "_"); Возврат Ответ; КонецФункции
Сам токен - соединение всех частей через точку
Токен = Заголовок + "." + Данные + "." + Сигнатура;
Далее его можно использовать по прямому назначению
Для 1С:
Open-source библиотека для JWT в 1С
Статья по теме
Конструктор JWT на jwt.io
Помимо этих вариантов есть еще схемы: Mutual, HOBA, VAPID и др., но вероятность встретить подтверждение личности по паспорту в реальной жизни куда выше, чем их реализацию в публичном API. И если некоторые из них (например Mutual) в реальном мире на самом деле существуют, просто под капотом интернета, то найти хотя бы теоретическую информацию о том, что же такое HOBA, вообще крайне сложно
Уровень 3 - Алгоритмы
На предыдущем уровне в некоторых из схем нам встречалось создание сигнатур. При работе с каждой из них, в зависимости от воли провайдера API, требуется применение того или иного алгоритма обработки данных. Наиболее распространенными из них на данный момент являются HMAC и RSA, в вариациях, основанных на различных алгоритмах хэширования - HMAC-SHA1, RSA-SHA256 и др. О них и поговорим
HMAC
HMAC (Hash-based message authentication code) - один из самых популярных механизмов проверки целостности информации. Я не буду рассказывать прохладные истории, будто бы понимаю (или должен понимать) как он внутри работает - никому из нас, я думаю это и не нужно. Как и в любых подобных вещах, 95% HMAC - это зубодробительный МАТАН, так что лучше сразу перейдем к 1С
Тут нам повезло гораздо больше (спойлер) чем с алгоритмом RSA: в Библиотеке стандартных подсистем, а именно в модуле РаботаВМоделиСервисаБТС есть замечательная, но, почему-то не экспортная, функция
HMAC(Знач Ключ, Знач Данные, Тип, РазмерБлока)
В параметре Тип она принимает значение платформенного перечисления ХешФункция (ХешФункция.SHA1, ХешФункция.SHA256, ХешФункция.SHA512) от которого и будет зависеть, собственно, будет у нас HMAC-SHA256, HMAC-SHA512 или HMAC-SHA1. А большего тут и не надо
RSA
RSA используется не так часто, как HMAC, но зато печально известно в мире 1С своим применением в сервисах от Google, когда речь заходит о работе через Service account. В 1С нет реализации RSA и лично я встречал всего несколько вариантов решений данной проблемы:
- В репозитории malikov-pro/google_api_1c можно найти подобное решение
Функция ПолучиьПодписьRSASHA256(СтрокаДанные, КлючПодписи_XML) Экспорт Хеширование = Новый ХешированиеДанных(ХешФункция.SHA256); Хеширование.Добавить(СтрокаДанные); ХешДвоичный = Хеширование.ХешСумма; КриптоПровайдер = Новый COMОбъект("System.Security.Cryptography.RSACryptoServiceProvider"); КриптоПровайдер.FromXmlString(КлючПодписи_XML); SafeArrayBinХешДляПодписи = SafeИзДвоичных(ХешДвоичный); SafeArrayBinПодписьДвоичная = КриптоПровайдер.SignHash(SafeArrayBinХешДляПодписи, "SHA256"); Возврат ДвоичныеИзSafe(SafeArrayBinПодписьДвоичная); КонецФункции
Тут используется COM объект, что не очень хорошо, но выглядит довольно просто и под Windows будет работать -
Dll на Инфостарте. Скажу честно - не проверял
-
Формирование объекта через новый платформенный объект ТокенДоступа. Есть недавняя статья на эту тему, но подойдет только тем, у кого свежая версия 1С (в статье 8.3.21)
-
Есть пример решения на Python, интегрированного в решение для Google Sheets на 1С от Евгения Комиссарова
Возможно есть и другие, но я о них не знаю. Хотя очень искал, когда начинал делать интеграцию с Google Drive
Другие же алгоритмы на практике встречаются гораздо реже
В заключении
В принципе, это все, что я хотел рассказать. Если я что-то упустил или вы нашли ошибку - напишите в комментариях. Также ниже будет список полезных ресурсов, который могут помочь при работе с API. Список будет дополняться, так что если знаете еще что-нибудь - об этом можете написать также
Спасибо за внимание!
- Коннектор: удобный HTTP-клиент для 1С:Предприятие 8
- 1С-JWT от pintov
- Внешня компонента для работы с RabbitMQ по http
- Открытй пакет интеграций для различных популярных API
Мой GitHub: https://gitub.com/Bayselonarrend Лицензия MIT: https://mit-license.org