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

OTP & AP (a.k.a. ОП и ПП)

27.01.2015

Эти непонятные аббревиатуры означают One-time Password (одноразовый пароль) и Application Password (пароль приложения). Как вы знаете, в 15 версии мы значительно развили одноразовые пароли и сделали их использование действительно удобным. Теперь их можно использовать не только в БУС, но и в КП. Давайте посмотрим, как ПП сделали возможным использование ОП в КП.

Одноразовые пароли

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

Напомню, что ранее поддерживались одноразовые пароли по счетчику, которые нужно было водить в форме логина в поле пароля. Поддерживались аппаратные брелоки для генерирования таких ОП. С тех пор одноразовые пароли стали популярнее, появились мобильные приложения для генерирования ОП на телефоне. В 15 версии мы поддерживаем уже два вида ОП:

- по счетчику (HMAC-Based One-time Password, HOTP), описан в RFC4226
- по времени (Time-based One-time Password, TOTP), описан RFC6238

Была решена задача поддержки популярных мобильных приложений для обоих типов ОП. Общепринятым способом инициализации ОП является сканирование и распознавание QR-кода телефоном. Это избавляет пользователя от ввода длинных ключей (хотя мы оставили возможность и ручной инициализации). Мы выпустили свое мобильное приложение Bitrix OTP для Android и iOS. Кроме того, поддерживаются другие приложения (Google Authenticator, FreeOTP).

Вот так выглядит инициализация в панели управления:

2015_01_27_104131.png

Для публичной части создан компонент security.user.otp.init, который так же выводит QR-код:

2015_01_27_104812.png

После инициализации пользователю предлагается создать резервные коды для авторизации на случай, если утеряно устройство генерирования ОП. Использование резервных кодов включается в настройках модуля security. Это очень важно! Если отсутствует доступ к скриптам сервера, то потеря устройства или сбой мобильного приложения у администратора приводит к полной невозможности авторизоваться! Спасут только резервные коды, сохраненные в надежном месте (компонент security.user.recovery.codes):

2015_01_27_110559.png

Давайте теперь немного углубимся в разработку формы авторизации на сайте или КП. Для удобства пользователей мы сделали разделение форм ввода основного пароля и ОП. Теперь одноразовый код спрашивается отдельным шагом авторизации:

2015_01_27_111356.png
(На Bitrix24 форма красивее)

Форма выводится системным компонентом system.auth.otp. Вы можете кастомизировать шаблон этого компонента для своего сайта точно так же, как шаблоны других компонентов авторизации. Также доработан компонент system.auth.form, его шаблон по умолчанию теперь понимает ОП. Если на вашем сайте используется кастомизированный шаблон system.auth.form, не переживайте, по-прежнему поддерживается ввод ОП в поле основного пароля. Если вы хотите сделать ввод ОП отдельным шагом, то нужно выполнить следующую доработку в шаблоне:
<?
elseif($arResult["FORM_TYPE"] == "otp"):
?>

<form name="system_auth_form<?=$arResult["RND"]?>" method="post" target="_top" action="<?=$arResult["AUTH_URL"]?>">
<?if($arResult["BACKURL"] <> ''):?>
   <input type="hidden" name="backurl" value="<?=$arResult["BACKURL"]?>" />
<?endif?>
   <input type="hidden" name="AUTH_FORM" value="Y" />
   <input type="hidden" name="TYPE" value="OTP" />
   <table width="95%">
      <tr>
         <td colspan="2">
         <?echo GetMessage("auth_form_comp_otp")?><br />
         <input type="text" name="USER_OTP" maxlength="50" value="" size="17" autocomplete="off" /></td>
      </tr>
<?if ($arResult["CAPTCHA_CODE"]):?>
      <tr>
         <td colspan="2">
         <?echo GetMessage("AUTH_CAPTCHA_PROMT")?>:<br />
         <input type="hidden" name="captcha_sid" value="<?echo $arResult["CAPTCHA_CODE"]?>" />
         <img src="/bitrix/tools/captcha.php?captcha_sid=<?echo $arResult["CAPTCHA_CODE"]?>" width="180" height="40" alt="CAPTCHA" /><br /><br />
         <input type="text" name="captcha_word" maxlength="50" value="" /></td>
      </tr>
<?endif?>
<?if ($arResult["REMEMBER_OTP"] == "Y"):?>
      <tr>
         <td valign="top"><input type="checkbox" id="OTP_REMEMBER_frm" name="OTP_REMEMBER" value="Y" /></td>
         <td width="100%"><label for="OTP_REMEMBER_frm" title="<?echo GetMessage("auth_form_comp_otp_remember_title")?>"><?echo GetMessage("auth_form_comp_otp_remember")?></label></td>
      </tr>
<?endif?>
      <tr>
         <td colspan="2"><input type="submit" name="Login" value="<?=GetMessage("AUTH_LOGIN_BUTTON")?>" /></td>
      </tr>
      <tr>
         <td colspan="2"><noindex><a href="<?=$arResult["AUTH_LOGIN_URL"]?>" rel="nofollow"><?echo GetMessage("auth_form_comp_auth")?></a></noindex><br /></td>
      </tr>
   </table>
</form>

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

Если вы разрабатываете свой компонент с авторизацией, то вам будет полезен пример из компонента system.auth.form. Работа идет с API модуля security:
   if(CModule::IncludeModule("security") && Mfa\Otp::isOtpRequired() && $_REQUEST["login_form"] <> "yes")
   {
      $arResult["FORM_TYPE"] = "otp";

      $arResult["REMEMBER_OTP"] = (COption::GetOptionString('security', 'otp_allow_remember') === 'Y');

      $arResult["CAPTCHA_CODE"] = false;
      if(Mfa\Otp::isCaptchaRequired())
      {
         $arResult["CAPTCHA_CODE"] = $APPLICATION->CaptchaGetCode();
      }
      if(Mfa\Otp::isOtpRequiredByMandatory())
      {
         $arResult['ERROR_MESSAGE'] = array("MESSAGE" => GetMessage("system_auth_form_otp_required"), "TYPE" => "ERROR");
      }
   }

 
Обратите внимание, важно соблюдать названия полей формы, так как авторизация по ОП происходит в main/include.php:
         elseif($_REQUEST["TYPE"] == "OTP")
         {
            $arAuthResult = $GLOBALS["USER"]->LoginByOtp($_REQUEST["USER_OTP"], $_REQUEST["OTP_REMEMBER"], $_REQUEST["captcha_word"], $_REQUEST["captcha_sid"]);
         }

 
Мы также улучшили инструменты администратора по управлению ОП. Теперь администратор может:

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

2015_01_27_114736.png
Отключение на срок.

2015_01_27_114835.png
Настройки двух-этапной авторизации модуля security.

Пароли приложений

Если вы помните, в начале я писал, что ОП добавлены в КП. Может возникнуть резонный вопрос: а почему собственно только сейчас одноразовые пароли появились в КП, они же давно уже существуют? Дело в том, что в корпоративном портале много различных интеграций с внешними приложениями, например Outlook, WebDAV или календари по CalDAV. С практической точки зрения эти приложения невозможно использовать при включенных ОП, т.к. они бы запрашивали пароль при каждом обращении к серверу.

Для поддержки таких интеграций мы создали новую сущность: пароль приложения (ПП). Это пароль, выдаваемый для конкретного приложения, и только оно с этим паролем может работать. Почему? Потому что считается, что безопасность работы без одноразового пароля снижена, поэтому доступ приложения к серверу сильно ограничен со стороны сервера. Например, мобильное приложение может обращаться только к папке /mobile, а десктопное - к папке /desktop_app. При попытке обратиться с выданным паролем за пределы отведенных папок ("скоупов" ) будет выдана ошибка "403 Forbidden". Таким образом поддерживается баланс между безопасностью и удобством.

За генерирование ПП отвечает новый компонент main.app.passwords:

2015_01_27_122038.png

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

2015_01_27_122143.png

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

С точки зрения разработки, авторизация по ПП производится в той же функции CUser::Login(), как и по обычному паролю. Это сделано для совместимости, чтобы существующие скрипты понимали новую сущность ПП. Эта функция сначала пытается авторизовать пользователя по его обычному паролю, а если он не подошел, то по паролю приложения:
               if(!$passwordCorrect)
               {
                  //let's try to find application password
                  if(($appPassword = ApplicationPasswordTable::findPassword($arUser["ID"], $arParams["PASSWORD"], ($arParams["PASSWORD_ORIGINAL"] == "Y"))) !== false)
                  {
                     $passwordCorrect = true;
                     $applicationId = $appPassword["APPLICATION_ID"];
                     $applicationPassId = $appPassword["ID"];
                  }
               }

В параметре APPLICATION_ID текущего пользователя запоминается, что авторизация произошла по ПП. Именно это позволяет отличить обычную авторизацию от авторизации по ПП и проконтролировать доступ приложения:
//application password scope control
if(($applicationID = $GLOBALS["USER"]->GetParam("APPLICATION_ID")) !== null)
{
   $appManager = \Bitrix\Main\Authentication\ApplicationManager::getInstance();
   if($appManager->checkScope($applicationID) !== true)
   {
      CHTTP::SetStatus("403 Forbidden");
      die();
   }
}


Список приложений, для которых может быть сгенерирован ПП, не является "вшитым". Если на вашем сайте или КП есть интеграция, для которой не предусмотрен ПП, то вы можете описать собственное приложение с вашим контролем доступа.

1) Вы должны создать свой класс, отнаследовав его от базового:
namespace Bitrix\Main\Authentication;

use Bitrix\Main;

class Application
{
   protected $validUrls = array();

   public function __construct()
   {
   }

   /**
    * Checks the valid scope for the applicaton.
    *
    * @return bool
    */
   public function checkScope()
   {
      /** @var Main\HttpRequest $request */
      $request = Main\Context::getCurrent()->getRequest();
      $realPath = $request->getScriptFile();

      foreach($this->validUrls as $url)
      {
         if(strpos($realPath, $url) === 0)
         {
            return true;
         }
      }

      return false;
   }
}

Базовый класс содержит метод проверки доступа, вы его можете переопределить. Для самого простого случая проверки доступа по путю вы можете переопределить только свойство $validUrls, содержащее список путей:
class DesktopApplication extends Bitrix\Main\Authentication\Application
{
   protected $validUrls = array(
      "/desktop_app/",
      "/bitrix/tools/disk/",
      "/bitrix/services/disk/index.php"
   );

   public static function OnApplicationsBuildList()
   {
      return array(
         "ID" => "desktop",
         "NAME" => GetMessage('DESKTOP_APPLICATION_NAME'),
         "DESCRIPTION" => GetMessage("DESKTOP_APPLICATION_DESC"),
         "SORT" => 2100,
         "CLASS" => "DesktopApplication",
      );
   }
}


2) Вы должны подписаться на событие ядра OnApplicationsBuildList:
RegisterModuleDependences("main", "OnApplicationsBuildList", "im", "DesktopApplication", "OnApplicationsBuildList");

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

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


Возврат к списку



Вас интересует ""?!
Напишите нам и мы с вами свяжемся!