Jak zabezpieczyć i podpisać dokumenty PDF w TypeScript

Jak zabezpieczyć i podpisać dokumenty PDF w TypeScript

Ten przewodnik pokazuje, jak szyfrować, certyfikować, podpisywać i weryfikować dokumenty PDF przy użyciu Aspose.PDF FOSS dla TypeScript. Document.Save() i Document.Open() obsługują szyfrowanie kluczem publicznym do certyfikatów odbiorcy, podczas gdy Document.Certify(), Document.Sign() i Document.VerifySignatures() obsługują cyfrowe podpisy w stylu PAdES. Wymaga Node.js 22 lub nowszego.

Przewodnik krok po kroku

Krok 1: Zainstaluj pakiet

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

Zweryfikuj instalację, importując klasę Document w nowym pliku TypeScript — ta linia powinna zostać rozwiązana bez błędu po zainstalowaniu pakietu:

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

Krok 2: Importuj wymagane klasy

Importuj Document, aby otworzyć, zapisać, podpisać i zweryfikować plik; kroki podpisywania i szyfrowania poniżej przekazują zwykłe obiekty opcji, więc nie są potrzebne dodatkowe importy:

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

Krok 3: Szyfrowanie dokumentu przy użyciu certyfikatów odbiorcy

Document.Save() przyjmuje opcję encrypt zawierającą jeden lub więcej recipients, z których każdy jest identyfikowany certyfikatem (ciąg PEM lub bajty DER), algorithm oraz współdzielonym 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
  },
});

Krok 4: Otwórz zaszyfrowany dokument

Przekaż opcję recipient do Document.Open() z dopasowanym kluczem prywatnym i certyfikatem lub pakietem 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)

Krok 5: Certyfikuj i podpisz dokument

Document.Certify() i Document.Sign() są oba asynchroniczne i przyjmują tożsamość (certificate + privateKey) oraz opcje opisujące pole podpisu, wygląd i powód. Certyfikacja powinna odbywać się najpierw, na całym pliku; dalsze podpisy zatwierdzające są dodawane kolejno po tym:

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');
}

Krok 6: Weryfikacja podpisów

Document.VerifySignatures() jest asynchroniczne i zwraca jeden SignatureReport na pole podpisu, każdy raportujący kryptograficzne integrity, ważność signature oraz czy 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}`);
  }
}

Typowe problemy i rozwiązania

Document.Sign() / Document.Certify() rzucać lub zawieszać. Oba są asynchroniczne — await wywołanie. Zapominając await pozostawia zwróconą obietnicę nierozwiązaną, a zapis odbywa się przed zakończeniem podpisywania.

Późniejszy podpis zatwierdzający unieważnia certyfikację. Podpisuj stopniowo: najpierw zapisz certyfikowane bajty (certifying.Save()), otwórz je ponownie przy użyciu Document.Open(), a następnie wywołaj Sign() w tym ponownie otwartym dokumencie — zapis pełnego przepisania zamiast przyrostowego dopisania psuje certyfikację /ByteRange skrótu.

VerifySignatures() reports coversWholeFile: false dla pierwszego podpisu, ale true dla ostatniego. Jest to oczekiwane w łańcuchu certyfikuj-następnie-podpisz: certyfikacja została podpisana przed dołączeniem zatwierdzenia, więc tylko najnowszy podpis /ByteRange rozciąga się do końca pliku.

Deszyfrowanie nie powodzi się przy prawidłowym kluczu prywatnym. Potwierdź certificate przekazany do recipient odpowiada dokładnemu certyfikatowi, do którego dokument został zaszyfrowany w Document.Save()’s recipients lista — certyfikat ponownie wydany z nową parą kluczy nie odszyfruje danych zaszyfrowanych przy użyciu starego.

Najczęściej zadawane pytania

Czy dokument może być zaszyfrowany dla więcej niż jednego odbiorcy?

Tak — recipients w opcji encrypt Document.Save() przyjmuje tablicę; dowolny prywatny klucz pasujący do odbiorcy może otworzyć powstały plik.

Jaki format podpisu generuje Document.Sign()?

Przekazanie subFilter: 'PAdES' w opcjach podpisu generuje podpis zgodny z PAdES; pominięcie go powoduje użycie domyślnego podfiltru podpisu biblioteki.

Jak sprawdzić, czy dokument jest certyfikowany, a nie tylko podpisany?

Sprawdź pole docMDP w SignatureReport zwróconym przez Document.VerifySignatures() — podpis certyfikujący zgłasza werdykt uprawnienia DocMDP; podpis jedynie zatwierdzający tego nie robi.

Czy odzyskane Permissions po Document.Open() są wymuszane przez bibliotekę?

Nie — opened.Permissions zgłasza flagi uprawnień zapisane w zaszyfrowanym pliku do wglądu; wymuszanie ich w aplikacji jest odpowiedzialnością wywołującego.

Zobacz także

 Polski