Как обеспечить безопасность и подписать PDF-документы в TypeScript

Как обеспечить безопасность и подписать PDF-документы в TypeScript

Это руководство показывает, как шифровать, сертифицировать, подписывать и проверять PDF-документы с помощью Aspose.PDF FOSS для TypeScript. Document.Save() и Document.Open() обрабатывают шифрование с открытым ключом для сертификатов получателей, тогда как Document.Certify(), Document.Sign() и Document.VerifySignatures() работают с цифровыми подписями в стиле PAdES. Требуется Node.js 22 или новее.

Пошаговое руководство

Шаг 1: Установите пакет

git clone https://github.com/aspose-pdf-foss/Aspose.PDF-FOSS-for-TypeScript.git
cd Aspose.PDF-FOSS-for-TypeScript
npm install
npm run build

Проверьте установку, импортировав класс Document в новый файл TypeScript — эта строка должна успешно разрешаться без ошибок после установки пакета:

import { Document } from '@asposefoss/pdf';

Шаг 2: Импортируйте необходимые классы

Импортируйте Document, чтобы открыть, сохранить, подписать и проверить файл; шаги подписи и шифрования ниже передают обычные объектные параметры, поэтому дополнительные импорты не требуются:

import { Document } from '@asposefoss/pdf';

Шаг 3: Зашифровать документ для сертификатов получателя

Document.Save() принимает параметр encrypt, содержащий один или несколько recipients, каждый из которых идентифицируется сертификатом (строка PEM или байты DER), algorithm и общим permissions:

const doc = Document.OpenFile('report.pdf');

const bytes = doc.Save({
  encrypt: {
    recipients: [{ certificate: recipientCertPem }],
    algorithm: 'aes256', // 'aes256' (default) | 'aes128' | 'rc4'
    permissions: { copying: false }, // shared across all recipients
  },
});

Шаг 4: Открыть зашифрованный документ

Передайте параметр recipient в Document.Open() с соответствующим закрытым ключом и сертификатом или пакетом PKCS#12:

const opened = Document.Open(bytes, {
  recipient: { privateKey, certificate: recipientCertPem },
  // or: recipient: { pkcs12: p12Bytes, passphrase: '…' },
});

console.log(opened.Permissions); // recovered permission flags (not enforced)

Шаг 5: Засвидетельствовать и подписать документ

Document.Certify() и Document.Sign() обе являются асинхронными и принимают идентичность (certificate + privateKey) плюс параметры, описывающие поле подписи, её внешний вид и причину. Засвидетельствование должно происходить первым, охватывая весь файл; дальнейшие подписи-утверждения добавляются инкрементно после этого:

async function certifyAndSign(sourcePath: string, signaturePageIndex: number): Promise<void> {
  const certifying = Document.OpenFile(sourcePath);
  await certifying.Certify(
    { certificate: authorCert, privateKey: authorKey },
    {
      permissions: 'form-fill',
      reason: 'Certifying the document',
      fieldName: 'Certification',
      appearance: { page: signaturePageIndex, rect: [400, 100, 550, 140] },
    },
  );
  const certifiedBytes = certifying.Save();

  const approving = Document.Open(certifiedBytes);
  await approving.Sign(
    { certificate: approverCert, privateKey: approverKey },
    { reason: 'Approved for publication', fieldName: 'Approval', subFilter: 'PAdES' },
  );
  approving.WriteTo('signed.pdf');
}

Шаг 6: Проверить подписи

Document.VerifySignatures() является асинхронным и возвращает один SignatureReport для каждого поля подписи, каждый из которых сообщает криптографический integrity, валидность signature и то, coversWholeFile:

async function verify(path: string): Promise<void> {
  const doc = Document.OpenFile(path);
  const reports = await doc.VerifySignatures();
  for (const r of reports) {
    console.log(`${r.name}: integrity=${r.integrity} signature=${r.signature} `
      + `coversWholeFile=${r.coversWholeFile} docMDP=${r.docMDP}`);
  }
}

Распространённые проблемы и решения

Document.Sign() / Document.Certify() выбрасывать исключение или зависать. Оба являются асинхронными — await вызов. Забывая await оставляет возвращённый промис неразрешённым, а запись происходит до завершения подписи.

Поздняя подпись одобрения делает сертификат недействительным. Подписывайте поэтапно: сначала сохраняйте сертифицированные байты (certifying.Save()), откройте их снова с Document.Open(), затем вызовите Sign() в этом вновь открытом документе — полное переписывание вместо инкрементального добавления нарушает сертификат /ByteRange дайджест.

VerifySignatures() reports coversWholeFile: false для первой подписи, но true для последней. Это ожидаемо для цепочки certify-then- sign: сертификат был подписан до того, как было добавлено одобрение, поэтому только подпись последней /ByteRange простирается до конца файла.

Расшифровка не удаётся с правильным закрытым ключом. Подтвердите the certificate передано в recipient соответствует точному сертификату, которым был зашифрован документ в Document.Save()’s recipients list — сертификат, переизданный с новой парой ключей, не сможет расшифровать данные, зашифрованные под старым.

Часто задаваемые вопросы

Можно ли зашифровать документ для более чем одного получателя?

Да — recipients в параметре encrypt Document.Save() принимает массив; соответствующий закрытый ключ любого получателя может открыть полученный файл.

В каком формате подписи генерирует Document.Sign()?

Передача subFilter: 'PAdES' в параметрах подписи создаёт подпись, совместимую с PAdES; при её отсутствии используется субфильтр подписи по умолчанию библиотеки.

Как проверить, сертифицирован ли документ, а не просто подписан?

Проверьте поле docMDP в SignatureReport, возвращаемом Document.VerifySignatures() — сертификатная подпись сообщает о решении о разрешении DocMDP; подпись только с одобрением этого не делает.

Применяются ли восстановленные Permissions после Document.Open() библиотекой?

Нет — opened.Permissions сообщает о флагах разрешений, записанных в зашифрованном файле, для проверки; их принудительное применение в приложении является ответственностью вызывающего.

См. также:

 Русский