Я работаю над реализацией, в которой наша система генерирует файл PDF для загрузки пользователем. Ключом нашего процесса и системы является то, что этот PDF-файл не должен изменяться пользователем или программой на компьютере пользователя (по крайней мере, не без злого умысла), так как файл может быть загружен в систему позже, где нам нужно сделатьубедитесь, что файл находится в исходном состоянии, сравнивая его хеш-значение.
Мы думали, что достигли этого, сначала отключив все разрешения (CanModify, CanAssembleDocument и т. Д.), А затем зашифровав документ с помощью пароля владельца. Это предотвратило изменение файла всеми читателями, к которым у нас был доступ. Теперь выясняется, что один из наших пользователей изменяет PDF-файл, как только он открывает файл в Acrobat Reader и «сохраняет как» документ в новый PDF-файл. Мы не можем воспроизвести это с одной и той же версией читателя (2015.006.30497), но он может это делать каждый раз.
Альтернатива подписи документа PDF для нас не вариант, по крайней мере, не с PKI или какой-либо видимойподпись, которую пользователи могут видеть в своем читателе. Если есть какая-то невидимая опция подписи, это было бы замечательно, но я не знаю, как.
Ниже кода, который мы используем для блокировки PDF. В целях тестирования мы отключили ВСЕ разрешения, но безрезультатно. Мы используем PDFBox 2.0.11.
Любые предположения, какие есть варианты, чтобы лучше заблокировать файл для модификации?
public static byte[] SealFile(byte[] pdfFile, String password) throws IOException
{ PDDocument doc =PDDocument.load(pdfFile);
ByteArrayOutputStream bos= new ByteArrayOutputStream();
byte[] returnvalue =null;
int keyLength = 256;
AccessPermission ap = new AccessPermission();
//Disable all
ap.setCanModifyAnnotations(false);
ap.setCanAssembleDocument(false); .
ap.setCanFillInForm(false);
ap.setCanModify(false);
ap.setCanExtractContent(false);
ap.setCanExtractForAccessibility(false);
ap.setCanPrint(false);
//The user password is empty ("") so user can read without password. The admin password is
// set to lock/encrypt the document.
StandardProtectionPolicy spp = new StandardProtectionPolicy(password, "", ap);
spp.setEncryptionKeyLength(keyLength);
spp.setPermissions(ap);
doc.protect(spp);
doc.save(bos);
doc.close();
bos.flush();
return bos.toByteArray();
}
Это приводит к свойствам Adobe:
Редактировать (решение): ==========
Как предлагается@mkl (все благодарности этому человеку) мы смогли решить проблему с помощью флага appendOnly, который является частью функциональности AcroForm. Оказалось, что флаг signatureExists не требовался для решения нашей проблемы. (и после прочтения спецификации не применимо)
Ниже приведено решение, которое мы реализовали:
/*
* This method is used to add the 'appendOnly flag' to the PDF document. This flag is part of
* the AcroForm functionality that instructs a PDF reader that the file is signed and should not be
* modified during the 'saved as' function. For full description see PDF specification PDF 32000-1:2008
* (https://www.adobe.com/content/dam/acom/en/devnet/pdf/pdfs/PDF32000_2008.pdf)
* paragraph 12.7.2 Interactive Form Dictionary
*/
public static void addAcroFormSigFlags(PDDocument pdfDoc) {
PDDocumentCatalog catalog = pdfDoc.getDocumentCatalog();
PDAcroForm acroForm = catalog.getAcroForm();
if (acroForm == null) {
acroForm = new PDAcroForm(pdfDoc);
catalog.setAcroForm(acroForm);
}
// AppendOnly:
// If set, the document contains signatures that may be invalidated if the
// file is saved (wirtten) in a way that alters its previous contents, as
// opposed to an incremental update. Merely updating the file by appending
// new information to the end of the previous version is safe (see h.7,
// "Updating Example"). Conforming readers may use this flag to inform a
// user requesting a full save that signatures will be invalidated and
// require explicit confirmation before continuing with the operation
acroForm.setAppendOnly(true);
// SignatureExists: (Currently not used by us)
// If set, the document contains at least one signature field. This flag
// allows a conforming reader to enable user interface items (such as menu
// items or pushbuttons) related to signature processing without having to
// scan the entire document for the presence of signature fields.
// acroForm.setSignaturesExist(true);
// flag objects that changed (in case a 'saveIncremental' is done hereafter)
catalog.getCOSObject().setNeedToBeUpdated(true);
acroForm.getCOSObject().setNeedToBeUpdated(true);
}