В этой статье описывается преимущественно техническая сторона дела. Здесь в тексте много исходного кода на языке 1С. Если вам нужно популярное описание, без программного кода, тогда вам сюда:
//infostart.ru/public/1114877/
Шаг 1. Создадим документ Блокчейн
Цепочку блоков надо где-то хранить. Для простоты я выбрал объект метаданных "Документ". Вобще говоря, хранить цепочку можно и вне базы, хоть в текстовом файле. Также можно использовать справочник или регистр сведений. Я выбрал документ отчасти произвольно, отчасти потому, что в нем есть дата, а она может в дальнейшем пригодиться. Что бы это ни было, нам нужны четыре (всего лишь, впрочем, можно и три) реквизита.
КонтролируемыйДокумент, как можно догадаться - ссылка на документ любого вида. КлючНачальный, ХешДокумента и КлючКонечный - строки неограниченной длины (можно задать длину 64).
Шаг 2. Сделаем обработку генерации цепочки блоков.
Найдем последний элемент цепочки. Я сделал это так:
Функция ПолучитьПоследнийБлок()
запрос=новый запрос;
запрос.Текст=
"ВЫБРАТЬ ПЕРВЫЕ 1
| Блокчейн.Ссылка КАК Ссылка
|ИЗ
| Документ.Блокчейн КАК Блокчейн
|
|УПОРЯДОЧИТЬ ПО
| Блокчейн.Номер УБЫВ";
выб=запрос.Выполнить().Выбрать();
если выб.Следующий() тогда
возврат выб.ссылка;
иначе
возврат неопределено;
конецесли;
КонецФункции
Запомним конечный ключ последнего блока, он станет начальным ключом первого созданного нами блока.
ПоследнийБлок=ПолучитьПоследнийБлок();
если ПоследнийБлок=неопределено тогда
КлючНачальный="";
иначе
КлючНачальный=ПоследнийБлок.КлючКонечный;
конецесли;
Получим все проведенные документы, которые еще не попали в цепочку блоков. Здесь я использую следующую заготовку запроса:
запрос=новый запрос;
текстзапроса=
"ВЫБРАТЬ
| Док.Ссылка КАК Ссылка
|ИЗ
| Документ.<вид> КАК Док
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.Блокчейн КАК Блокчейн
| ПО Док.Ссылка = Блокчейн.КонтролируемыйДокумент
|ГДЕ
| Док.Проведен
| И Блокчейн.Ссылка ЕСТЬ NULL";
Строка <вид> в тексте запроса в дальнейшем заменяется на конкретный вид документа.
Обработаем документы. Я разместил в обработке дерево значений для настройки списка документов, которые мы будем включать в блокчейн, а также списка их реквизитов.
А вот собственно сама генерация цепочки блоков:
видыдокументов=настройка.ПолучитьЭлементы();
для каждого вид из видыдокументов цикл
если вид.пометка тогда
запрос.Текст=стрзаменить(текстзапроса,"<вид>",вид.имя);
выб=запрос.Выполнить().Выбрать();
пока выб.Следующий() цикл
новблок=документы.Блокчейн.СоздатьДокумент();
новблок.Дата=текущаядата();
новблок.КонтролируемыйДокумент=выб.ссылка;
новблок.ХешДокумента=ПолучитьХешДокумента(выб.ссылка);
новблок.КлючНачальный=КлючНачальный;
новблок.КлючКонечный=ПолучитьКонечныйКлюч(КлючНачальный,новблок.ХешДокумента);
новблок.Записать();
КлючНачальный=новблок.КлючКонечный;
конеццикла;
конецесли;
конеццикла;
Функция ПолучитьХэшДокумента() - банальна, но я ее приведу.
Функция ПолучитьДокументСтрокой(ссылка)
рез="";
видд=ссылка.метаданные().имя;
нвид=неопределено;
ветка=настройка.ПолучитьЭлементы();
для каждого вид из ветка цикл
если вид.имя=видд тогда
нвид=вид;
прервать;
конецесли;
конеццикла;
если не нвид=неопределено тогда
реквизиты=нвид.ПолучитьЭлементы();
для каждого рек из реквизиты цикл
если рек.пометка тогда
поз=стрнайти(рек.имя,".");
если поз=0 тогда
рез=рез+строка(ссылка[рек.имя]);
иначе
имятч=лев(рек.имя,поз-1);
имярек=сред(рек.имя,поз+1);
для каждого стр из ссылка[имятч] цикл
рез=рез+строка(стр[имярек]);
конеццикла;
конецесли;
конецесли;
конеццикла;
конецесли;
возврат рез;
КонецФункции
Функция ПолучитьХешДокумента(ссылка)
хд=новый ХешированиеДанных(ХешФункция.SHA256);
хд.Добавить(ПолучитьДокументСтрокой(ссылка));
рез=строка(хд.ХешСумма);
рез=стрзаменить(рез," ","");
возврат рез;
КонецФункции
Строковое представление документа следовало бы сделать более изощренным и включить в него ИД ссылок. Если будете делать рабочую версию, доделайте функцию ПолучитьДокументСтрокой().
Чуть более интересна функция ПолучитьКонечныйКлюч(). Собственно здесь и кроется сама суть технологии.
Функция HEX(знач знч)
рез= "";
Пока знч > 0 Цикл
рез = Сред("0123456789ABCDEF", знч%16+1,1) + рез;
знч = Цел(знч/16) ;
КонецЦикла;
Возврат рез;
КонецФункции
Функция ПолучитьКонечныйКлюч(КлючНачальный,хеш)
нули="00000000000000000000000000000000000000000000";
нули=лев(нули,сложность);
рез="";
сч=0;
пока истина цикл
хд=новый ХешированиеДанных(ХешФункция.SHA256);
рез=HEX(сч);
хд.Добавить(КлючНачальный+хеш+рез);
стр=стрзаменить(хд.ХешСумма," ","");
если сложность=0 тогда
прервать;
иначеесли лев(стр,сложность)=нули тогда
прервать;
конецесли;
сч=сч+1;
конеццикла;
возврат рез;
КонецФункции
Я подбираю значение конечного ключа до тех пор, пока ключ начальный, хэш документа и ключ конечный в сумме не дадут некий "красивый" хеш. Красивым считается хеш, который содержит в начале некоторое количество нулей. Количество нулей определяет сложность нахождения красивого хеша.
Полностью процедура генерации цепочки блоков выглядит так:
Процедура ЗапускНаСервере()
ПоследнийБлок=ПолучитьПоследнийБлок();
если ПоследнийБлок=неопределено тогда
КлючНачальный="";
иначе
КлючНачальный=ПоследнийБлок.КлючКонечный;
конецесли;
запрос=новый запрос;
текстзапроса=
"ВЫБРАТЬ
| Док.Ссылка КАК Ссылка
|ИЗ
| Документ.<вид> КАК Док
| ЛЕВОЕ СОЕДИНЕНИЕ Документ.Блокчейн КАК Блокчейн
| ПО Док.Ссылка = Блокчейн.КонтролируемыйДокумент
|ГДЕ
| Док.Проведен
| И Блокчейн.Ссылка ЕСТЬ NULL";
видыдокументов=настройка.ПолучитьЭлементы();
для каждого вид из видыдокументов цикл
если вид.пометка тогда
запрос.Текст=стрзаменить(текстзапроса,"<вид>",вид.имя);
выб=запрос.Выполнить().Выбрать();
пока выб.Следующий() цикл
новблок=документы.Блокчейн.СоздатьДокумент();
новблок.Дата=текущаядата();
новблок.КонтролируемыйДокумент=выб.ссылка;
новблок.ХешДокумента=ПолучитьХешДокумента(выб.ссылка);
новблок.КлючНачальный=КлючНачальный;
новблок.КлючКонечный=ПолучитьКонечныйКлюч(КлючНачальный,новблок.ХешДокумента);
новблок.Записать();
КлючНачальный=новблок.КлючКонечный;
конеццикла;
конецесли;
конеццикла;
КонецПроцедуры
Обработка генерации цепочки блоков готова. Можно позапускать ее в ручном режиме в учебных целях. В рабочем режиме потребуется заставить ее работать постоянно тем или иным способом.
Шаг 3. Сделаем обработку контроля.
С обработкой контроля все еще проще. Я скопировал предыдущую обработку, чтобы иметь тот же интерфейс настройки
и заменил процедуру генерации на процедуру контроля.
Процедура ЗапускНаСервере()
контрольпройден=истина;
ключ="";
выб=документы.Блокчейн.Выбрать();
пока выб.Следующий() цикл
если выб.КлючНачальный<>ключ тогда
сообщить("Блок "+выб.Номер+" нарушена последовательность блоков");
контрольпройден=ложь;
иначеесли лев(строка(выб.КонтролируемыйДокумент),1)="<" тогда
сообщить("Блок "+выб.Номер+" документ удален");
контрольпройден=ложь;
иначеесли не выб.КонтролируемыйДокумент.Проведен тогда
сообщить("Блок "+выб.Номер+" документ распроведен");
контрольпройден=ложь;
иначеесли выб.ХешДокумента<>ПолучитьХешДокумента(выб.КонтролируемыйДокумент) тогда
сообщить("Блок "+выб.Номер+" документ изменен");
контрольпройден=ложь;
иначеесли не ЭтоКрасивыйХеш(выб.КлючНачальный,выб.ХешДокумента,выб.КлючКонечный) тогда
сообщить("Блок "+выб.Номер+" неправильный хеш");
контрольпройден=ложь;
конецесли;
ключ=выб.КлючКонечный;
конеццикла;
если контрольпройден тогда
сообщить("Контроль пройден");
конецесли;
КонецПроцедуры
Функция ЭтоКрасивыйХеш() - упрощенная вариация того, что мы видели в функции ПолучитьКонечныйКлюч() на предыдущем шаге.
Функция ЭтоКрасивыйХеш(КлючНачальный,хеш,КлючКонечный)
нули="00000000000000000000000000000000000000000000";
нули=лев(нули,сложность);
хд=новый ХешированиеДанных(ХешФункция.SHA256);
хд.Добавить(КлючНачальный+хеш+КлючКонечный);
стр=стрзаменить(хд.ХешСумма," ","");
если сложность=0 тогда
возврат истина;
иначе
возврат лев(стр,сложность)=нули;
конецесли;
КонецФункции
Что в итоге.
Вы можете самостоятельно сделать обработки генерации и контроля, следуя моим инструкциям, или скачать готовые. Позапускать их и убедиться, что любая операция с документом, который попал в цепочку приводит к необходимости пересчитывать все, начиная с этого документа. При правильно подобранной сложности, это становится практически не осуществимо. Теоретически, конечно, можно попросить знакомого китайского майнера задействовать его ферму для решения данной задачи. Но он ведь попросит компенсировать неполученные им биткоины (и еще столько же, в лучшем случае, а сколько это сейчас в долларах/рублях считайте сами). С другой стороны затраты на безопасность базы, как вы можете убедиться, не такие уж большие. Несложная программная часть. Немного дополнительного места на диске. И вычислительные ресурсы для генерации цепочки блоков. Последние могут быть больше или меньше в зависимости от желаемого уровня защиты.
Стоит заметить, что возможна также атака путем подмены контролирующей обработки. Но она настолько проста, что ее может визуально контролировать кто угодно. Как вариант можно регулярно скачивать контролирующую обработку (например, с инфостарта ))) ) .
Обработки тестировались на версии 8.3.10.2639.
Update 09.01.2018
Публикация вызвала оживленное и, что еще более важно, плодотворное обсуждение. И я хочу поблагодарить всех, кто принял в нем участие. Ниже я подведу итоги состоявщегося обсуждения и представлю продукт, в котором учтены существенные замечания.
1. Что это такое?
Блокчейн обычно связывают с криптовалютами. Данная технология не имеет отношения к майнингу криптовалют. Идея состоит в том, чтобы использовать особым образом связанную цепочку блоков (блокчейн) для контроля неизменности документов в информационной базе 1С.
2. Чем это лучше, того что есть сейчас?
В докомпьютерной бухгалтерии существовала (впрочем, она и сейчас существует, только не применяется на практике, по крайней мере в 1С) следующая концепция безопасности. Невозможно предотвратить неправомерные действия, но можно сделать так, что любое такое действие будет быстро выявлено. Современные информационные базы защищены системой прав доступа, паролями и т.д. Но. Когда злоумышленник преодолевает эту защиту, его дествия практически невозможно выявить. Например. Некто меняет в свою пользу в приходном документе количество и цену местами. Условно говоря, вместо 10 пачеки сахара по 1 рублю, ставит 1 по 10. После чего он может спокойно забрать 9 пачек себе. Скорее всего, об этом никто и никогда не узнает. Данная система позволяет создать абсолютную защиту, в том смысле, что любое изменение(удаление) контролируемого документа будет моментально обнаружено. Способов обмануть систему, в том числе путем подмены цепочки, нет. Подробнее см. п.4.
3. Это - дополнительная нагрузка на информационную базу? Документы будут медленнее проводиться?
Система защиты работает автономно, в процесс проведения документов никак не вмешивается. При построении цепочки происходит однократное чтение нового документа. При контроле чтение каждого документа из цепочки.
4. Зачем нужен "майнинг"?
Майнинг конечно же в кавычках. Дело в том, что в настоящем майнинге основным моментом является поиск т.н. красивого хеша. Такого, который содержит в начале определенное количество нулей. В приведенном выше решении я тоже использовал этот прием. Ищется красивый хеш с количеством нулей, соответствующем заданной пользователем сложности. Моя идея заключалась в том, что злоумышленник всегда будет вынужден догонять. Тогда можно будет подобрать такую сложность, что затраты на подмену цепочки сделают атаку бессмысленной. Тут я несколько увлекся и упустил из виду, что злоумышленник может принять решение о подмене документа и сразу же начать строить альтернативную цепочку. Таким образом, атакующий и система находятся в равном положении. CSiER обратил внимание на это и предложил отказаться от "майнинга" и дать пользователю возможность визуального контроля цепочки на предмет подмены. Пользователь записывает куда-нибудь ключ последнего на сегодня(или вчера) блока, а на следующий день сверяет свою запись с состоянием цепочки. В таком виде система действительно дает абсолютную защиту и в коммерческом решении я использую этот метод. Но я все равно оставил "майнинг". Дело в том, что если отказаться от него совсем (задать сложность 0), тогда ключ для контроля будет слишком длинным (64 символа). А если задать сложность 2 или 3, тогда ключ будет длиной 2-4 символа, что гораздо удобнее.
Коммерческое решение представляет собой две исходные обработки соединенные в одну и доработанные с учетом п.4. Интерфейс найстройки принципиально не изменился. Добавилась страница состояния, откуда можно переписывать ключи для контроля цепочки.
При выявлении того или иного нарушения, система выдает соответствующее сообщение.
Принципиальным отличием является то, что для хранения цепочки используется не документ информационной базы, а внешний файл XBase. Это дает возможность организовать негласную проверку базы, такую которая будет незаметна в том числе и для ИТ. Более подробное описание можно найти в руководстве пользователя.
На мой взгляд, надежный контроль неизменности документов - очень важная технология. Можно создать множество решений на ее основе. Если кто-то возьмется за это, то он может использовать код из данной публикации без каких-либо условий.
Update 22.01.2018
Платная версия, которую я представил в прошлый раз, подразумевала не совсем 1С-овский стиль работы. Документ попавший в цепочку блоков уже нельзя было менять совсем. При обнаружении изменения, нужно было вернуть документ в первоначальный вид. Я оставил эту платную версию под новым именем "Докчейн строгий". И в дополнении к ней предлагаю основную версию под названием "Докчейн. Защищенный журнал". В этой версии документы могут изменяться и удаляться. Все такие действия заносятся в ту же цепочку блоков и получается журнал, защищенный от изменений. Чтобы не загромождать данную публикацию, я создал новую: