Excel показує дві речі, які обидві звуться «пароль», і лише одна з них — шифрування. Пароль відкриття задає ключ справжнього шифру: без нього файл узагалі неможливо прочитати. Паролі захисту аркуша й книги не роблять нічого подібного. Вони встановлюють прапорець, який погоджується поважати редактор, що співпрацює, і книга, що несе лише цей прапорець, — звичайний читабельний zip із даними, що сидять у відкритому тексті. Оберіть не той — і ви відвантажите платіжну відомість, що виглядає заблокованою в Excel і читається в будь-якому текстовому редакторі
Доказ займає десять секунд. Перейменуйте захищений .xlsx на .zip, відкрийте його в будь-якому архіваторі й погляньте на xl/worksheets/sheet1.xml. Якщо значення клітинок там, у звичайному UTF-8, файл не зашифрований, скільки б запитів пароля не показував Excel, коли хтось намагається редагувати клітинку. Ця прогалина роками живе всередині команд, що вважають захист аркуша конфіденційністю, і зазвичай проявляється того дня, коли перевірка безпеки виконує рівно це перейменування
HotXLS — нативна бібліотека електронних таблиць для Delphi та C++Builder, і вона тримає ці дві функції по різні боки цієї межі. Захист аркуша й книги — обмеження редагування, підкріплені навмисно слабким застарілим хешем. SaveAsEncrypted створює пакет, зашифрований AES, який ніщо, крім пароля, не відкриє. Розділи нижче охоплюють те, що записує цей виклик, асиметрію, навколо якої треба проєктувати (HotXLS записує зашифровані файли, але не може прочитати їх назад), та те, чим відрізняється старіший шлях XLS
Чому захист аркуша — не шифрування
Методи Protect на аркушах і ProtectWorkbook на книзі зберігають 4-шістнадцятковий хеш пароля. Це застарілий алгоритм, який і OOXML, і BIFF успадкували від Excel 1990-х, і документація формату ніколи не стверджує, що він робить більше, ніж зупиняє випадкові редагування. Пакет лишається звичайним читабельним zip: дані клітинок, формули й спільні рядки — усе у відкритому тексті XML. Значення за замовчуванням робить це гіршим, а не кращим. Кожна клітинка починається з Locked=True, тож виклик Protect без попереднього розблокування діапазону введення заморожує весь аркуш проти редагування, лишаючи водночас кожне значення на видноті
Ніщо з цього не робить захист марним. Скеровування користувачів у редаговані діапазони й стабілізація макета для друку — реальні завдання, розглянуті в нашій статті про захист аркуша та параметри сторінки. Але це завдання зручності використання. Тієї миті, коли вимога — конфіденційність, єдиний API, що на неї відповідає, — SaveAsEncrypted
Що насправді записує SaveAsEncrypted
Реалізація дотримується ECMA-376 Standard Encryption, визначеної в [MS-OFFCRYPTO] розділі 2.3.4. Пароль проходить через 50 000 ітерацій SHA-1, щоб вивести ключ AES-128. Блок верифікатора, зашифрований AES-128 у режимі ECB, дозволяє споживачу підтвердити пароль до того, як він щось розшифрує, а весь пакет книги потім шифрується AES-128 у режимі CBC. Те, що лягає на диск, — це взагалі не zip. Це складений файл OLE, що тримає потоки EncryptionInfo, EncryptedPackage і DataSpaces, без жодного каталогу xl/, який архіватор міг би перелічити, і саме тому тест з перейменуванням тепер не показує нічого читабельного. Excel 2007 і новіші відкривають його лише за паролем, і сучасний LibreOffice також читає Standard Encryption
var
Book: TXLSXWorkbook;
Sheet: TXLSXWorksheet;
rc: Integer;
begin
Book := TXLSXWorkbook.Create;
try
Sheet := Book.Sheets.Add('Payroll');
Sheet.Cells[1, 1].Value := 'Employee';
Sheet.Cells[1, 2].Value := 'Net pay';
Sheet.Cells[2, 1].Value := 'A. Garcia';
Sheet.Cells[2, 2].Value := 4815.16;
rc := Book.SaveAsEncrypted('payroll-2026-06.xlsx', PasswordFromVault);
if rc <> 1 then
raise Exception.CreateFmt('Encrypted save failed (rc=%d)', [rc]);
finally
Book.Free;
end;
end;
Ставтеся до змінної пароля з тією самою обережністю, що й до рядка з’єднання. Отримуйте його зі сховища секретів чи сервісу генерованих секретів в останню мить, ніколи не логуйте його і ніколи не записуйте в саму книгу. Перевірка коду повернення — не необов’язковий ритуал. Збереження з шифруванням, що провалилося на півдорозі, має скасувати доставку, бо єдиний резервний варіант, який може запропонувати код, що викликає, — це незашифрована копія, а ця копія — точнісінько той інцидент, для запобігання якому й існує ця функція
Є також машинно-перевірний прийомний тест, що коштує майже нічого: викличте CanReadEncrypted на файлі, який ви щойно записали. Він повертає true лише тоді, коли вивід справді є контейнером шифрування, тож твердження про це після кожного шифрованого збереження ловить найважливішу регресію — шлях коду, що мовчки відкотився до звичайного SaveAs, — тієї миті, коли це трапляється, а не тижнями пізніше в поштовій скриньці клієнта. Останнє слово все одно належить ручному відкриттю в Excel зі справжнім паролем під час тестування релізу
Лише для запису за задумом: обробка EXlsxEncryptionNotImplemented
Ось асиметрія, яка має формувати архітектуру вашого конвеєра: HotXLS шифрує при збереженні, але не розшифровує при відкритті. OpenEncrypted викликає EXlsxEncryptionNotImplemented, коли спрямований на справді зашифрований пакет; на звичайній книзі він просто провалюється у звичайний Open. Супутня перевірка CanReadEncrypted дешево виявляє контейнер шифрування OLE, тож код прийому може маршрутизувати такі файли, не спричиняючи винятку:
var
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
try
if Book.CanReadEncrypted(FileName) then
begin
// Зашифрований контейнер: HotXLS не може його розшифрувати
Writeln(FileName + ': needs manual decryption in Excel first');
Exit;
end;
try
Book.OpenEncrypted(FileName, ''); // звичайні файли провалюються до Open
Writeln(FileName + ': opened, ' + IntToStr(Book.Sheets.Count) + ' sheet(s)');
except
on EXlsxEncryptionNotImplemented do
Writeln(FileName + ': encrypted - routed to manual queue');
end;
finally
Book.Free;
end;
end;
Ця асиметрія має одне чітке архітектурне прочитання: шифруйте на краю доставки, останнім кроком. Тримайте відкритий текст головного примірника всередині вашої довірчої межі — у базі даних, сховищі документів чи ресурсі з контролем доступу — і виробляйте зашифровану копію як останній крок перед тим, як файл покине систему. Конвеєр, що архівує лише зашифрований вивід, замкнув сам себе поза власними даними, бо жоден пізніший етап тієї самої системи не може повторно відкрити ці файли. Коли подальшому процесу HotXLS знову потрібна книга, передайте йому головний примірник у відкритому тексті, ніколи — артефакт доставки
AES-128 Standard Encryption і межа відповідності AES-256
Шифрування файлів Office існує у двох поколіннях. Standard Encryption, те, що записує HotXLS, використовує AES-128 із виведенням ключа через SHA-1. Agile Encryption з’явилося пізніше й переходить на AES-256 із SHA-512 та інший, описаний XML контейнер ключів. Обидва відкриваються прозоро в Excel, і AES-128 усе ще обчислювально надійне для захисту файлу під час доставки клієнту
Різниця перестає бути академічною того дня, коли анкета безпеки вимагає «шифрування AES-256 файлів у стані спокою». Standard Encryption не відповідає цій вимозі, хоч би яким сильним був пароль, і жоден параметр SaveAsEncrypted не змінює алгоритм, який він видає. Тож формулюйте профіль точно у вашій документації з безпеки: AES-128, ECMA-376 Standard Encryption, виведення ключа SHA-1 на 50 000 ітераціях. Твердження, що переживає перевірку, варте більшого, ніж оптимістичне, що розвалюється під час аудиту
Застарілий шлях XLS: RC4 назовні, RC4 і XOR назад
Фасад BIFF має протилежну форму. Його шифрування старіше й слабше, але цикл туди-й-назад повний: що він записує, він і може прочитати назад. Встановлення EncryptionPassword перед SaveAs створює RC4-зашифрований .xls через механізм BIFF FilePass, а Open з параметром пароля читає всі три застарілі схеми — RC4, RC4 CryptoAPI та стародавню обфускацію XOR:
var
Writer, Reader: IXLSWorkbook; // посилання на інтерфейси: без ручного Free
begin
Writer := TXLSWorkbook.Create;
Writer.Sheets.Add.Cells.Item[1, 1].Value := 'Confidential';
Writer.EncryptionPassword := 'S3cret!';
Writer.SaveAs('confidential.xls');
Reader := TXLSWorkbook.Create;
if Reader.Open('confidential.xls', 'S3cret!') > 0 then
Writeln(Reader.Sheets[1].Cells.Item[1, 1].Value); // Entries з одиниці
end;
RC4 — застаріла криптографія, і вона ніколи не повинна захищати дані, важливі сьогодні; єдина цінність, що в ній лишилася, — сумісність із системами, що все ще обмінюються .xls. Однак бік читання виправдовує себе в міграційній роботі. Захищений паролем застарілий файл відкривається через Open(FileName, Password), переноситься в модель OOXML і повторно захищається через шлях AES — одностороннє оновлення, що виконується без Excel будь-де в циклі. Для доставок із високим обсягом шифрування нотатки про пропускну здатність на боці запису в нашій статті про потокові записи для серверних пакетних завдань застосовуються до фази побудови вмісту, що відбувається перед шифруванням
Шифрування й захист — не суперники
Ще один момент, вартий врегулювання, бо він виникає тієї миті, коли хтось читає попередження на початку цієї сторінки як «захист марний». Це не так. Шифрування й захист відповідають на різні запитання, і вони чисто накладаються один на одного. Шифрування вирішує, хто може відкрити файл; захист вирішує, що може змінити читач, який уже всередині. Доставка платіжної відомості цілком розумно може робити обидва: шифрувати пакет, щоб його бачив лише власник пароля, а потім заблокувати клітинки формул, щоб отримувач міг фільтрувати й сортувати, але не міг мовчки переписати обчислення. Помилка — це ніколи не додавання захисту. Помилка — це дозволити його присутності підміняти шифрування, коли вимогою була конфіденційність
Бік зберігання не має страхувальної сітки, і це навмисно. Виведення ключа на 50 000 ітераціях існує, щоб зробити вгадування дорогим, і ніщо всередині файлу не депонує секрет. Втрачений пароль — це втрачені дані. Генеруйте, доставляйте й зберігайте ці паролі з тією самою дисципліною, яку ви застосовуєте до облікових даних бази даних, і шифрування виконає свою частину
Справжнє шифрування файлу — один виклик у HotXLS. Дисципліна живе в усьому навколо цього виклику: зберіганні пароля, межі лише для запису, що не дозволяє HotXLS повторно відкрити власний вивід, і твердженні про алгоритм, яке ви можете захистити під час аудиту. SaveAsEncrypted та застарілий цикл туди-й-назад постачаються з HotXLS Delphi Component, що працює нативно в процесах Delphi та C++Builder без жодної автоматизації Excel на шляху