node-signpdf icon indicating copy to clipboard operation
node-signpdf copied to clipboard

Cloudflare blocks sign PDF

Open MichalY-WizSoft opened this issue 1 year ago • 20 comments

  • Generate PDF using JSPDF
  • Merge PDFs using PDF-MERGER
  • Add signature placeholder using pdflibAddPlaceholder
  • Sign the PDF
  • Try to upload to system -> Cloudflare blocks with WAF alerts
  • When switching to plainAddPlaceholder, the upload works but the signature is not visible in Adobe Reader
  • what the difrent and how to do not block and visible in Adobe Reader ?

Attachments

  • [signed_pdflib.pdf] - PDF signed with pdflibAddPlaceholder
  • [signed_plain.pdf] - PDF signed with plainAddPlaceholder
  • [cloudflare_block.png] - Screenshot of Cloudflare WAF block

signed_plain.pdf signed_pdflib.pdf cloudflare_block

const signPdf = async (pdfBuffer, signer) => {
    try {
        const pdfWithPlaceholder = await plainAddPlaceholder({
            pdfBuffer,
            reason: 'Digital Invoice Signature',
            contactInfo: 'Wizsoft',
            name: 'Wizsoft Digital Signature',
            location: 'Israel',
            signingTime: new Date().toISOString(),
            signatureLength: 8192,
            subFilter: 'adbe.pkcs7.detached',
            appName: 'Wizsoft Digital Signature System',
            widgetRect: [0, 0, 595, 842]
        });    
        return signpdf.sign(pdfWithPlaceholder, signer);
    } catch (err) {
        throw {message:`signature faild, error : ${err}`};
    }
}

const signPdfLib = async (pdfBuffer,  signer) =>{
    try {
        let pdfDoc = await PDFDocument.load(pdfBuffer);
        await pdflibAddPlaceholder({
            pdfDoc: pdfDoc,
            reason: 'Digital Invoice Signature',
            contactInfo: '',
            name: 'Digital Signature',
            location: 'Israel',
            signingTime: new Date().toISOString(),
            signatureLength: 8192,
            subFilter: 'adbe.pkcs7.detached',
        });
        pdfWithPlaceholder = await Buffer.from(await pdfDoc.save({useObjectStreams: false }), 'arraybuffer');
        return signpdf.sign(pdfWithPlaceholder, signer)                    
    } catch (err) {
        throw {message:`signature faild, error : ${err}`};
    }
}

MichalY-WizSoft avatar Jan 07 '25 08:01 MichalY-WizSoft

Have you spoken to cloudflare?

dhensby avatar Jan 07 '25 11:01 dhensby

I’m trying to contact them as well.

Previously, I used to work with : const { plainAddPlaceholder } = require('node-signpdf/dist/helpers'); However, I had to switch because I needed to upload a PDF version that wasn’t supported, and this library is now deprecated.

What has changed between the libraries? Is there an alternative way to create a VALID Adobe signature that is also visible in Adobe Reader, while still using plainAddPlaceholder in a way that Cloudflare does not block?

MichalY-WizSoft avatar Jan 07 '25 11:01 MichalY-WizSoft

We don't know specifically what cloudflare is blocking or what they don't like. Is it specifically to do with the content of the PDF? With the signature? With that particular instance of a signature?

I'm not intimately familiar with the exact differences, but I don't see why they should produce vastly different signatures that would make cloudflare think there's embedded PHP, command injections, etc in them.

Have you looked at the PDF files in a text editor to see what is different?

dhensby avatar Jan 07 '25 11:01 dhensby

I noticed that in pdflibAddPlaceholder, a long string with various characters is embedded in the signature.

How does this information help me?

image

MichalY-WizSoft avatar Jan 07 '25 11:01 MichalY-WizSoft

That stream doesn't look well formed to me, it should be binary data but it's made up of ASCII, which is unusual.

I suspect there's some encoding problem somewhere which is corrupting something. I don't know what exactly, you'll have to debug what is going on.

You aren't following the example for pdf-lib, so maybe that's a problem too?

const signPdfLib = async (pdfBuffer,  signer) =>{
    try {
        const pdfDoc = await PDFDocument.load(pdfBuffer);
       pdflibAddPlaceholder({
            pdfDoc: pdfDoc,
            reason: 'Digital Invoice Signature',
            contactInfo: '',
            name: 'Digital Signature',
            location: 'Israel',
            signingTime: new Date().toISOString(),
            signatureLength: 8192,
            subFilter: 'adbe.pkcs7.detached',
        });
        pdfWithPlaceholder = await pdfDoc.save();
        return signpdf.sign(pdfWithPlaceholder, signer)                    
    } catch (err) {
        throw {message:`signature faild, error : ${err}`};
    }
}

dhensby avatar Jan 07 '25 12:01 dhensby

If I follow the example, I encounter an error: "PDF expected as Buffer"

This happens because pdfDoc.save returns a Uint8Array, while signpdf.sign expects a Buffer.

Am I missing something in the process?

MichalY-WizSoft avatar Jan 07 '25 14:01 MichalY-WizSoft

Then do this

const signPdfLib = async (pdfBuffer,  signer) =>{
    try {
        const pdfDoc = await PDFDocument.load(pdfBuffer);
       pdflibAddPlaceholder({
            pdfDoc: pdfDoc,
            reason: 'Digital Invoice Signature',
            contactInfo: '',
            name: 'Digital Signature',
            location: 'Israel',
            signingTime: new Date().toISOString(),
            signatureLength: 8192,
            subFilter: 'adbe.pkcs7.detached',
        });
        pdfWithPlaceholder = await pdfDoc.save();
-        return signpdf.sign(pdfWithPlaceholder, signer)
+        return signpdf.sign(Buffer.from(pdfWithPlaceholder), signer)
    } catch (err) {
        throw {message:`signature faild, error : ${err}`};
    }
}

dhensby avatar Jan 08 '25 09:01 dhensby

Thank you for the quick response - I really appreciate it!

I’ve encountered an issue: if I don’t use pdfDoc.save({ useObjectStreams: false }), I get the following error: "No ByteRangeStrings found within PDF buffer."

MichalY-WizSoft avatar Jan 08 '25 10:01 MichalY-WizSoft

ok, and if you add that in?

dhensby avatar Jan 08 '25 10:01 dhensby

Yes,

The document was signed, but it’s still being blocked by Cloudflare. I suspected it (useObjectStreams: false) might be the cause.

MichalY-WizSoft avatar Jan 08 '25 10:01 MichalY-WizSoft

Is there a way to add a placeholder using plainAddPlaceholder so that the signature will be visible in Adobe Reader?

MichalY-WizSoft avatar Jan 08 '25 10:01 MichalY-WizSoft

Yep - it seems there's a compatibility issue with lib-pdf and this lib at the moment, then. Perhaps something changed under the hood with pdf-lib in a version and we've not kept up.

dhensby avatar Jan 08 '25 11:01 dhensby

If I use this function. the process completes successfully and Cloudflare does not block it. However, I do not receive the validation in Acrobat. I’ve attached an image of what I expect to see. Do you know why this is happening and how to fix it? Thank you in advance for your help!

const signPdfLib = async (pdfBuffer, signer) => {
    try {
        const pdfWithPlaceholder = await plainAddPlaceholder({
            pdfBuffer: pdfBuffer,
            reason: 'Digital Invoice Signature',
            contactInfo: 'Wizsoft',
            name: 'Wizsoft Digital Signature',
            location: 'Israel',
            signingTime: new Date().toISOString(),
            signatureLength: 8192,
            subFilter: 'adbe.pkcs7.detached',
            appName: 'Wizsoft Digital Signature System',
            widgetRect: [0, 0, 595, 842]
        });

        return signpdf.sign(pdfWithPlaceholder, signer);
    } catch (err) {
        throw {message:`signature faild, error : ${err}`};
    }
}

image

MichalY-WizSoft avatar Jan 08 '25 11:01 MichalY-WizSoft

I don't know why it is not showing, presumably because not all the signatures are valid? What does the signature pane say?

dhensby avatar Jan 08 '25 11:01 dhensby

The window doesn’t open—this is exactly the problem. It’s as if the document isn’t signed. Attached is an example document.

example.pdf

MichalY-WizSoft avatar Jan 08 '25 14:01 MichalY-WizSoft

@MichalY-WizSoft can you share the source file that you are trying to sign, not the one with the added signature?

vbuch avatar Feb 03 '25 06:02 vbuch

Thank you for your response. Attached is a file comparing the situation before and after signing:

Before signing – Not blocked by Cloudflare After signing – Blocked

before.pdf after.pdf

I would appreciate your assistance in understanding the reason for this.

MichalY-WizSoft avatar Feb 03 '25 07:02 MichalY-WizSoft

Hi @MichalY-WizSoft , I took a look at the files above. Here are my observations: 0. My Acrobat shows a signature panel in "after". There is a valid signature in it.

  1. The signature placeholder is not applied through incremental updates. This means that you did not apply it with plainAddPlaceholder (I was expecting that based on the discussion above)
  2. If "before" is the source file can you also give here the file with the added placeholder?
  3. "before" is PDF-1.6 while "after" is PDF-1.7
  4. Just from looking at the files in a text editor I don't see anything wrong with "after".

vbuch avatar Feb 11 '25 14:02 vbuch

Thank you for your response @vbuch

  1. Indeed, the signature is legal.
  2. Yes, I started it with pdflibAddPlaceholder.
  3. The after file is a file with a Placeholder and a signature, do you want just a Placeholder without a signature?
  4. The PDF version is probably changing because I read the DATA with PDFDocument.load and then save
  5. The document comes out properly signed - the only problem with it is that it is blocked by Cloudflare.

Since it was blocked, I tried with plainAddPlaceholder

When switching to plainAddPlaceholder, the upload works but the signature is not visible in Adobe Reader

Would you like me to attach a PDF with a signature not visible with plainAddPlaceholder ?

MichalY-WizSoft avatar Feb 17 '25 08:02 MichalY-WizSoft

@vbuch @dhensby

Can you help or give guidance on how to create a valid signature on PDF 1.6

Thank you

MichalY-WizSoft avatar Mar 16 '25 09:03 MichalY-WizSoft