Шифрование и дешифрование текстовой информации с применением пароля

11 9

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

// Создать объект для шифрования
EncryptObj: ICrypto = CreateObject('SBRte.SBCrypto')
Encrypter: IEncrypter = EncryptObj.Encrypter

По умолчанию используется модуль шифрования Standard Encryption с GUID {B1B27433-D685-47F8-8500-CF9525407145}. Передаем текст и пароль для шифрования, вызываем метод Encrypt. После шифрования в свойство CryptContent записываются зашифрованные данные.

Encrypter.PluginName = '{B1B27433-D685-47F8-8500-CF9525407145}'
Encrypter.Content = 'Текстовая информация для шифрования'
Encrypter.Password = 'Пароль'
Encrypter.Encrypt
// Получить зашифрованные данные
EncryptData = Encrypter.CryptContent

В результате получим зашифрованную текстовую информацию.

Для дешифрования следует вызвать метод Decrypt объекта IEncrypter. Предварительно требуется задать в свойстве CryptContent зашифрованные данные, указать плагин шифрования и пароль. Для дешифрования данных, заданные в свойстве CryptContent, в свойстве Password следует указывать то же значение пароля, с помощью которого были зашифрованы исходные данные.

// Дешифрование данных
EncryptObj: ICrypto = CreateObject('SBRte.SBCrypto')
Encrypter:  IEncrypter = EncryptObj.Encrypter
Encrypter.PluginName = '{B1B27433-D685-47F8-8500-CF9525407145}'
Encrypter.CryptContent = 'Зашифрованные данные'
Encrypter.Password = 'Пароль'
Encrypter.Decrypt
// Получение исходных данных
Result = Encrypter.Content
Encrypter = nil
EncryptObj = nil

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

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

Тарас Асачёв

Мне кажется вы усложняете, для ограничения пользователей хватит и простеньких операций:

Object.Requisites('LongString').CanGUIWrite = FALSE // Блокируем от изменений!
Object.Requisites("LongString2").CanGUIRead = FALSE // Скрываем из виду!  

 

Тарас Асачёв

Ну и раз пошла такая пьянка:

1. Создаем Реквизиты:

  • Строка "Пароль" (String2)
  • Строка "Скрытый пароль" (DFAString2)
  • Строка для шифрования или что угодно иное (String3)

2. Создаем Действие "OnExecute_ЗадатьПароль"

if Object.Requisites("DFAString2").IsNull
  Object.Requisites("DFAString2").AsString = Object.Requisites("String2").AsString
  MessageBox("Поздравляем!";"Вы назначили новый пароль!")
  Object.Requisites("String3").CanGUIRead = FALSE                 // Скрываем шифруемую строку
  Object.Requisites("String2").AsString = ''                      // Скрываем введенный пароль
  Object.Form.Actions.FindAction("ЗадатьПароль").Visible = FALSE  // Скрываем кнопку
endif

3. Создаем Действие "OnExecute_Дешифровать"

if Assigned(Object.Requisites("DFAString2").Value)
    if Object.Requisites("String2").AsString == Object.Requisites("DFAString2").AsString
        Object.Requisites("String2").AsString = ''
          Object.Requisites("String3").CanGUIRead = TRUE
            Object.Form.Actions.FindAction("ЗадатьПароль").Visible = TRUE
              Object.Requisites("DFAString2").Value = NULL
                MessageBox("Внимание!";"Пароль сброшен!")
    else
      MessageBox("ВНИМАНИЕ!";"Пароль не Верный!!!")
    endif
endif

4. Вносим строки в Форму-карточки-Показ:

if not Object.Requisites("DFAString2").IsNull
       Object.Requisites("String3").CanGUIRead = FALSE
       Object.Requisites("String2").AsString = ''
       Object.Form.Actions.FindAction("ЗадатьПароль").Visible = FALSE
endif

Готово. Теперь выводим поля и кнопки на Форму карточки:

Тестируем:

Жмем "Задать Пароль"

Сохраняем. Закрываем. Открываем вновь:

Пробуем ввести пароль "12345" и дешифровать:

Теперь вводим "123456":

Работа выполнена!

 

Андрей Сорокин

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

Тарас Асачёв

Вы правы - забить это в таблицу и можно спать спокойно.

Андрей Посаженников

Наталья, а какой алгоритм шифрования используется в вашем примере? Насколько оно взломостоек и для чего его можно применять?

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

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

Тарас Асачёв

Андрей, упаси Господь использовать столь примитивное решение для реальной работы! Нет, это решение не более чем ограничение от некоторых пользователей и не далее. У нас есть некоторые процессы, где есть данные не для общего круга лиц и сделано это было скорее как "игрушка" для тех, кто считает, что данные по переписке читают все кому не лень. 

Андрей Посаженников

Тарас, тогда и шифровать смысла нет. Заодно и процессор с памятью не занимать лишний раз. Ну или чтобы не совсем "светиться" - XOR еще никто не отменял. Шутка конечно.

А вообще вводить пользователей в заблуждение это плохо. Они же думают что у них все защищено паролем и никто больше прочитать информацию не сможет. А это не так.

По поводу кейса "читают все кому не лень" - интересное решение. Ведь человек, который шифровал данные может забыть пароль, уволиться, заболеть, или уйти в отпуск. Да и что делать, если данные нужно смотреть нескольким людям? Передавать пароль? Но тут опять проблема - пароль нельзя забрать обратно. А значит и доступ к информации нельзя отозвать. 

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

 

Андрей Посаженников

По поводу алгоритма шифрования раскопал сам, может кому интересно. Согласно справке используется 3DES.

Тарас Асачёв

Андрей Посаженников, ну я с этого и начал:

Object.Requisites('LongString').CanGUIWrite = FALSE // Блокируем от изменений!
Object.Requisites("LongString2").CanGUIRead = FALSE // Скрываем из виду!  

Это легко активируется простым вычислением пользователей по Ролям/группам/полномочиям.

CurrentUser = ServiceFactory.GetUserByName(Application.Connection.UserName) 
Admin = ServiceFactory.GetGroupMembers(ServiceFactory.GetGroupByName('Administrators')).Find(CurrentUser)
////////////////////////////////
FinDirectorRole = ServiceFactory.GetRoleMembers(ServiceFactory.GetRoleByName('ФинДиректор'); NIL) 
IsFinDirector = FinDirectorRole.Find(CurrentUser) 
///////////////////////////////
CurrentUser.UserType = utAdministrator

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

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

Тарас Асачев: обновлено 17.01.2019 в 13:26

Авторизуйтесь, чтобы написать комментарий