MundoJSnode.jsAssinatura Digital de PDF no Node.js: Guia Prático

Assinatura Digital de PDF no Node.js: Guia Prático

Aprenda como assinar digitalmente PDFs com certificado A3 usando Node.js. Solução avançada e segura para NF-e em ambientes Windows e Linux. Otimize seu servidor para assinaturas digitais.

-

Aprenda como assinar PDFs digitalmente usando Node.js e certificados A1 (.pfx). Guia prático com exemplos usando node-forge, pdf-lib e node-signpdf.

O certificado digital A1 é amplamente utilizado em aplicações fiscais, como emissão de Notas Fiscais Eletrônicas (NF-e), por ser armazenado no formato .pfx ou .pem, facilitando sua integração com sistemas hospedados, sejam eles em Windows ou Linux. Diferente do certificado A3, o A1 não requer dispositivos físicos, o que o torna ideal para servidores.

Neste guia avançado, vamos abordar como realizar a assinatura digital de PDFs com certificado A1 usando Node.js. O foco será em implementações que funcionem tanto em servidores Windows quanto Linux.

Dica de Leitura: Se você está trabalhando com Node.js para implementar a assinatura digital de PDFs com certificado A1, também pode estar interessado em melhorar a qualidade e segurança do seu código. Confira nosso artigo sobre como instalar e configurar SonarQube para projetos Node.js para garantir que seu projeto atenda aos padrões de qualidade e segurança necessários.


1. Entendendo o Certificado A1

O certificado A1:

  • Armazenamento: Arquivo digital no formato .pfx ou .pem.
  • Portabilidade: Pode ser carregado diretamente em servidores.
  • Uso em NF-e: Atende às exigências da SEFAZ para emissão de documentos fiscais.

2. Ferramentas e Bibliotecas Necessárias

Bibliotecas

  1. node-signpdf: Para inserir a assinatura no PDF.
  2. node-forge: Para manipular e carregar o certificado digital.
  3. pdf-lib: Para preparar o PDF com campos de assinatura.

Instalando Dependências

npm install node-signpdf pdf-lib forge

3. Configuração do Ambiente

Certifique-se de que o certificado A1 está disponível no servidor em formato .pfx ou .pem. Além disso, mantenha a chave privada protegida.

VAI GOSTAR: Pacotes e ferramentas Node.js que deveria conhecer

Ambientes

  • Windows: Certifique-se de que o arquivo .pfx está acessível e que o servidor tem permissões adequadas para lê-lo.
  • Linux: Verifique as permissões de leitura no diretório onde o certificado está armazenado.

4. Preparação do PDF

Antes de assinar, é necessário adicionar um campo de assinatura ao PDF.

Código para Adicionar Campo de Assinatura

const { PDFDocument } = require('pdf-lib');
const fs = require('fs');

async function preparePDF(inputPath, outputPath) {
  // Leia o PDF existente
  const pdfBytes = fs.readFileSync(inputPath);

  // Carregue o PDF usando pdf-lib
  const pdfDoc = await PDFDocument.load(pdfBytes);

  // Adicione uma anotação de campo para assinatura
  const pages = pdfDoc.getPages();
  const firstPage = pages[0];
  firstPage.drawText('Assinado digitalmente:', {
    x: 50,
    y: 50,
    size: 12,
  });

  // Salve o PDF modificado
  const modifiedPdfBytes = await pdfDoc.save();
  fs.writeFileSync(outputPath, modifiedPdfBytes);
}

preparePDF('documento.pdf', 'documento-preparado.pdf');

5. Assinatura Digital Usando o Certificado A1

5.1. Carregando o Certificado

Utilize o node-forge para carregar o certificado e a chave privada.

Código para Carregar o Certificado

const forge = require('node-forge');
const fs = require('fs');

function loadCertificate(pfxPath, passphrase) {
  const pfxBuffer = fs.readFileSync(pfxPath);
  const p12Asn1 = forge.asn1.fromDer(pfxBuffer.toString('binary'));
  const p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, false, passphrase);

  // Extraia a chave privada e o certificado
  let privateKey, certificate;
  p12.safeContents.forEach((safeContent) => {
    safeContent.safeBags.forEach((safeBag) => {
      if (safeBag.type === forge.pki.oids.keyBag) {
        privateKey = forge.pki.privateKeyToPem(safeBag.key);
      } else if (safeBag.type === forge.pki.oids.certBag) {
        certificate = forge.pki.certificateToPem(safeBag.cert);
      }
    });
  });

  return { privateKey, certificate };
}

// Exemplo de uso
const { privateKey, certificate } = loadCertificate('./certificado.pfx', 'SENHA_DO_CERTIFICADO');
console.log(privateKey, certificate);

5.2. Assinando o Hash do PDF

Código para Assinatura

const crypto = require('crypto');

function signData(dataToSign, privateKey) {
  const signer = crypto.createSign('RSA-SHA256');
  signer.update(dataToSign);
  return signer.sign(privateKey, 'base64');
}

// Exemplo de uso
const dataToSign = 'Hash do PDF'; // Substitua pelo hash real do PDF
const signature = signData(dataToSign, privateKey);
console.log('Assinatura:', signature);

6. Inserindo a Assinatura no PDF

Após gerar a assinatura, insira-a no PDF usando o node-signpdf.

Código para Inserir Assinatura

const { plainAddPlaceholder } = require('node-signpdf/dist/helpers');
const SignPdf = require('node-signpdf');
const fs = require('fs');

function signPDF(inputPath, outputPath, signature, certificate) {
  const pdfBuffer = fs.readFileSync(inputPath);

  // Adicione um placeholder para assinatura
  const pdfWithPlaceholder = plainAddPlaceholder({
    pdfBuffer,
    reason: 'Assinatura Digital Certificado A1',
  });

  // Assine o PDF
  const signer = new SignPdf();
  const signedPdf = signer.sign(pdfWithPlaceholder, {
    key: Buffer.from(privateKey),
    cert: Buffer.from(certificate),
    signature: Buffer.from(signature, 'base64'),
  });

  fs.writeFileSync(outputPath, signedPdf);
}

signPDF('documento-preparado.pdf', 'documento-assinado.pdf', signature, certificate);

7. Configuração para Servidores Windows e Linux

Windows

  • Certifique-se de que o arquivo .pfx está no diretório correto.
  • Use permissões adequadas para o usuário do serviço Node.js.

Linux

  • Configure as permissões do diretório para que o serviço Node.js possa acessar o arquivo.
  • Use caminhos absolutos ao carregar o certificado.

8. Validação e Testes

8.1. Validação do Certificado

Use ferramentas como o Adobe Acrobat ou validadores da SEFAZ para verificar a integridade do documento assinado.

8.2. Logs de Depuração

Adicione logs detalhados para depurar problemas:

console.log(‘Certificado carregado com sucesso.’);
console.log(‘Assinatura gerada:’, signature);
console.log(‘PDF assinado salvo em:’, outputPath);

9. Conclusão

Este guia apresenta um processo completo e avançado para assinar PDFs com o certificado digital A1 da SEFAZ em Node.js. O uso de um certificado A1 simplifica a implementação em servidores Windows e Linux, oferecendo flexibilidade e portabilidade.

Próximos Passos

  • Configure scripts para automação em um servidor Node.js.
  • Implemente autenticação para proteger o acesso ao certificado.
  • Realize testes extensivos com documentos fiscais reais.

Com estas etapas, você estará pronto para integrar assinaturas digitais com Node.js em ambientes de produção.

Como testar e validar a assinatura do PDF

1. Preparação

  1. Arquivos Necessários:
    • O PDF a ser assinado (ex.: input.pdf).
    • O certificado digital no formato .pfx (ex.: certificado.pfx) e sua senha.
  2. Dependências Instaladas:
    • Certifique-se de que o Node.js e as bibliotecas necessárias (node-signpdf) estão instalados:bashCopiar códigonpm install node-signpdf
  3. Código Configurado:
    • Verifique se o código aponta corretamente para os arquivos (input.pdf, certificado.pfx) e a senha está correta.

2. Execução

  1. Execute o código:bashCopiar códigonode seu_arquivo.js
  2. Verifique a saída:
    • O PDF assinado será salvo no diretório atual com o nome signed.pdf (ou o nome especificado no código).

3. Validação

  1. No Adobe Reader:
    • Abra o PDF assinado (signed.pdf).
    • Confira o status da assinatura:
      • Deve indicar Assinatura válida.
      • Verifique se aparece “O documento não foi alterado desde que a assinatura foi aplicada.”
  2. No Validador da ICP-Brasil:
    • Acesse o Validador da ICP-Brasil.
    • Faça o upload do PDF assinado.
    • Verifique se a assinatura está conforme as normas ICP-Brasil.
  3. Outros Validadores (Opcional):
    • Utilize o Certisign Verificador para testar compatibilidade.

Se o PDF não for reconhecido como válido, revise os seguintes pontos:

  • Certificado: Certifique-se de que o .pfx contém a chave privada e a cadeia de certificação completa.
  • Carimbo de Tempo: Verifique se o PDF possui um carimbo de tempo (opcional, mas recomendado).
  • Formato de Assinatura: Confirme que segue o padrão PAdES.

VAI GOSTAR: Mundo do Web Scraping com Node.js e Puppeteer

Fontes de referências, estudos e pesquisas.

Para aprofundar seu conhecimento sobre assinatura digital de PDFs utilizando certificados digitais no Node.js, especialmente no contexto de Nota Fiscal de Serviço Eletrônica (NFSe), seguem algumas referências úteis:

Artigos e Tutoriais:

  1. Assinatura Digital via JavaScript: Este repositório no GitHub demonstra como implementar a assinatura digital de documentos utilizando JavaScript, o que pode ser adaptado para Node.js. GitHub
  2. Assine documentos com assinaturas digitais usando a API REST no Node.js: Este artigo detalha como utilizar a API REST do GroupDocs.Signature Cloud para assinar documentos PDF e DOCX em Node.js. GroupDocs Blog
  3. Como instalar um certificado SSL no Node.js: Embora focado em certificados SSL, este tutorial fornece insights sobre a configuração de certificados em ambientes Node.js, o que é relevante para o uso de certificados digitais. SSL Dragon

Bibliotecas e Repositórios no GitHub:

  1. ns-nfe-node: Biblioteca em Node.js para emissão de Nota Fiscal Eletrônica (NFe) utilizando a API da NS Tecnologia. GitHub
  2. client-nodejs: Cliente oficial da API NFe.io para Node.js, facilitando a integração com serviços de emissão de notas fiscais. GitHub
  3. NFe-NodeJS: Repositório que demonstra a emissão de Nota Fiscal Eletrônica para Node.js utilizando a REST API da WebmaniaBR®. GitHub
  4. autenticacao-ICP-Brasil: Instruções para autenticar um token/certificado A1/A3 no site, apresentando o e-CPF ou e-CNPJ, com exemplos em PHP e Node.js. GitHub

Documentação Oficial:

  • NFe.io – Documentação para Desenvolvedores: Documentação oficial da NFe.io, incluindo bibliotecas para Node.js e exemplos de uso. NFe.io
  • GroupDocs.Signature Cloud SDK para Node.js: Documentação oficial do SDK, útil para implementar assinaturas digitais em diversos formatos de documentos.

Considerações Importantes:

  • Certificado Digital A3: Este tipo de certificado requer atenção especial devido ao seu armazenamento em dispositivos físicos, como tokens USB ou smart cards. A integração com Node.js pode demandar o uso de bibliotecas específicas para comunicação com esses dispositivos, como PKCS#11.
  • Ambientes Windows e Linux: A configuração e uso de certificados digitais podem variar entre sistemas operacionais. Certifique-se de instalar os drivers e middlewares adequados fornecidos pelo fabricante do certificado para cada ambiente.

Estas referências fornecerão uma base sólida para implementar a assinatura digital de PDFs em Node.js, especialmente no contexto de NFSe, utilizando certificados digitais A3.

PODE GOSTAR: Entrevista de técnica sobre Node.js: Perguntas e respostas

LEIA TAMBÉM: Livros e cursos grátis para DevOps e DevSecOps

VAI GOSTAR

Perguntas Frequentes (FAQ): Assinatura Digital no Node.js

Qual a diferença entre usar um Certificado A1 e um A3 no servidor?

O Certificado A1 é um arquivo digital em formato de software (geralmente .pfx ou .p12). Ele pode ser hospedado e lido diretamente pelo Node.js em servidores em nuvem (AWS, DigitalOcean, Heroku) através do File System (fs). Já o certificado A3 fica armazenado em hardware (Tokens USB ou Cartões). Para usar um A3, você precisa de um servidor físico local com o dispositivo plugado, tornando a escalabilidade em nuvem praticamente impossível sem middlewares específicos.

É seguro deixar o arquivo .pfx e a senha dentro do projeto Node.js?

Não é uma boa prática deixar o arquivo de certificado exposto no repositório ou a senha escrita em hardcode (direto no arquivo .js). O ideal é armazenar o caminho do arquivo e a senha do certificado em variáveis de ambiente (arquivos .env) ou usar gerenciadores de segredos profissionais, como o AWS Secrets Manager ou HashiCorp Vault, para evitar que chaves da empresa vazem via GitHub.

A assinatura feita no Node.js tem validade legal?

Sim, desde que o certificado digital (A1) utilizado pertença à raiz da ICP-Brasil (Infraestrutura de Chaves Públicas Brasileira) e esteja dentro da validade. O processo criptográfico demonstrado gera uma assinatura válida e reconhecida juridicamente, desde que não ocorra a quebra da cadeia de confiança. O Adobe Reader e a SEFAZ vão identificar o Hash PAdES corretamente.

Por que minha assinatura aparece como “Desconhecida” no Adobe Reader?

Isso acontece porque o Adobe Reader verifica se ele “confia” na raiz que emitiu o certificado. Como muitos certificados do Brasil são atrelados à Autoridade Certificadora (AC) Raiz Brasileira, e esta não vem pré-instalada por padrão em alguns Adobe Readers estrangeiros, a assinatura é exibida como válida, mas “identidade não verificada”. Basta orientar o usuário a confiar manualmente na cadeia da ICP-Brasil no próprio Adobe.

Ramos da Informática
Ramos da Informáticahttps://ramosdainformatica.com.br
Ramos da Informática é um hub de comunidade dedicado a linguagens de programação, banco de dados, DevOps, Internet das Coisas (IoT), tecnologias da Indústria 4.0, cibersegurança e startups. Com curadoria de conteúdos de qualidade, o projeto é mantido por Ramos de Souza Janones.

Mais recentes

Como aprender a programar, um guia definitivo

Última atualização em 23/04/2026. Guia completo sobre: Como aprender a programar. Espero que este “guia” ou “manifesto”, como prefiro chamar, seja...

Stream Deck para Desenvolvedores: o Console de Comando do Futuro

Esqueça os streamers. Descubra como o Stream Deck se tornou o hardware essencial para Engenheiros de IA e Full...

Como Usar o Skills in Chrome no Brasil: Tutorial Completo de IA

A inteligência artificial já faz parte do nosso fluxo de trabalho, mas ter que reescrever os mesmos prompts repetidamente...

Context Engineering: Como Arquitetar Dados para LLMs e RAG

Na edição desta newsletter intitulada “Engenharia de Prompt: Não é só mais uma buzzword“: https://www.linkedin.com/pulse/engenharia-de-prompt-n%C3%A3o-%C3%A9-s%C3%B3-mais-uma-buzzword-de-souza-janones-tpkxf tratei sobre o tema...
E-Zine Dev

Evolua para Sênior

Estratégias de Node.js, arquitetura Limpa e IA que nunca publicamos no blog. Junte-se a +10.000 devs.

Assinar Gratuitamente Zero spam. Cancele quando quiser.

Aprender Idiomas com Google Tradutor: Na Prática

O Google está lançando um novo recurso experimental com tecnologia de IA no Google Tradutor, projetado para ajudar as...

Comunidades Internacionais de Desenvolvedores

Descubra as melhores comunidades internacionais de devs para 2026: GitHub, Stack Overflow, Discord e mais. Comparativo de salários Brasil vs. exterior e guia de carreira remota.

Mais Lidos

Observabilidade no Node.js: Como Usar o diagnostics_channel

Bem-vindo a este tutorial avançado sobre como usar o...

ChatGPT para Desenvolvedores: Como Programar com IA

Treinado com textos da web, ChatGPT usa inteligência artificial...

SQL WHERE 1: O que é e por que usar o truque do WHERE 1=1?

Entenda o que significa WHERE 1 (ou WHERE 1=1)...

Guia SQL: Gerenciamento de Usuários, Permissões e Roles

Aprenda a gerenciar permissões no MySQL, PostgreSQL e SQL...
E-Zine Dev

Evolua para Sênior

Estratégias de Node.js, arquitetura Limpa e IA que nunca publicamos no blog. Junte-se a +10.000 devs.

Assinar Gratuitamente Zero spam. Cancele quando quiser.

Você vai gostarrelacionados
Continue aprendendo

E-Zine Dev Ramos

Quer dominar arquitetura e IA?

Junte-se a +10.000 profissionais. Receba semanalmente estratégias de Node.js, React e IA que nunca publicamos no blog.

Assinar Gratuitamente Zero spam. Cancele quando quiser.