Τεχνικό Άρθρο

Ταξινόμηση του τι άλλαξε σε PDF μετά την υπογραφή

Μια υπογραφή σε PDF δεν απαγορεύει μεταγενέστερες αλλαγές. Στερεώνει ένα εύρος bytes, και μια επαυξητική ενημέρωση προσθέτει νέα bytes μετά από αυτό, οπότε η υπογραφή παραμένει μαθηματικά έγκυρη ενώ το έγγραφο αποκτά νέο περιεχόμενο. Το αν αυτό το περιεχόμενο είναι αποδεκτό είναι ερώτημα πολιτικής, και το DocMDP είναι εκεί όπου ο συγγραφέας δηλώνει την πολιτική: καθόλου αλλαγές, μόνο συμπλήρωση φόρμας και υπογραφή, ή αυτά συν σχολιασμούς. Η επιβολή της σημαίνει ταξινόμηση του τι άλλαξε πραγματικά, που είναι αυτό που κάνει η AnalyzeModifications. Στρέψτε την σε μια προηγούμενη αναθεώρηση, και μετά διαβάστε την GetModificationLevel για τη συνολική ετυμηγορία και τους accessors ανά εύρημα για το επίπεδο, τον αριθμό αντικειμένου και την περιγραφή κάθε διαφοράς

Με αυτό στη θέση του, η επιβολή DocMDP συμπτύσσεται σε μια σύγκριση: είναι το υπολογισμένο επίπεδο στο ή κάτω από το επίπεδο που επιτρέπει η πολιτική

Διάγραμμα της κλίμακας επιπέδων τροποποίησης του PDFlibPas από mlNone έως mlUnclassified που δείχνει την επιβολή πολιτικής DocMDP ως μία σύγκριση σε Delphi
Η κλίμακα TPLModificationLevel εκτείνεται από mlNone έως mlUnclassified, και η επιβολή DocMDP ανάγεται στη σύγκριση του υπολογισμένου επιπέδου με την πολιτική

Γιατί ένα υπογεγραμμένο PDF αναμένεται να αλλάξει

Τρεις νόμιμες περιπτώσεις, και καλύπτουν τα περισσότερα από όσα θα δείτε. Ένας δεύτερος υπογράφων προσθέτει την υπογραφή του. Ένας παραλήπτης συμπληρώνει πεδία φόρμας που ο συγγραφέας άφησε ανοιχτά. Και υλικό μακροχρόνιας επικύρωσης προστίθεται: απαντήσεις OCSP και CRLs γραμμένες στο document security store του εγγράφου ώστε η υπογραφή να παραμένει επαληθεύσιμη αφού οι responders εξαφανιστούν. Το τελευταίο δεν απλώς επιτρέπεται, είναι αυτό που κάνει ένα καλά διαχειριζόμενο αρχείο σε υπογεγραμμένα έγγραφα επίτηδες

Έτσι το «το αρχείο μεγάλωσε μετά την υπογραφή» δεν κουβαλά πληροφορία. Το ερώτημα είναι πάντα τι προστέθηκε, και η απάντηση πρέπει να προέλθει από σύγκριση καταστάσεων εγγράφου και όχι από παρακολούθηση bytes. Η μηχανική της προσθήκης καλύπτεται στο άρθρο για τις επαυξητικές ενημερώσεις

Ταξινομήστε με το σχήμα του αντικειμένου, όχι με τη διαδρομή που το παρήγαγε

Ο ταξινομητής κοιτάζει τι είναι ένα αντικείμενο μετά την αλλαγή, και όχι ποια κλήση βιβλιοθήκης το δημιούργησε. Είναι σκόπιμο, γιατί η ανάλυση τρέχει σε αρχεία παραγμένα από άλλο λογισμικό, όπου δεν υπάρχει διαθέσιμη διαδρομή κλήσης προς εξέταση

Τέσσερα σχήματα αναγνωρίζονται. Λεξικά information του document security store και σχετικά με επικύρωση, αντικείμενα cross-reference stream, η εγγραφή metadata του καταλόγου, και λεξικά υπογραφών που κουβαλούν εύρος bytes είναι υλικό μακροχρόνιου αρχείου. Ένα αντικείμενο που κουβαλά και τύπο πεδίου και τιμή πεδίου είναι συμπλήρωση φόρμας. Ένα αντικείμενο του οποίου ο τύπος είναι annotation, ή του οποίου το subtype είναι ένα από αυτά που αναφέρονται στον Πίνακα 168 του ISO 32000-2, είναι αλλαγή σχολιασμού. Όλα τα υπόλοιπα μένουν unclassified

Δέντρο αποφάσεων που εφαρμόζει το PDFlibPas σε κάθε αλλαγμένο αντικείμενο PDF, ταξινομώντας τις ενημερώσεις σε επίπεδα archive, συμπλήρωσης φόρμας, σχολιασμού ή unclassified
Κάθε αλλαγμένο αντικείμενο ταξινομείται από αυτό που είναι — security store, xref stream, πεδίο, annotation — ποτέ από την κλήση που το παρήγαγε

Οι αφαιρέσεις αντιμετωπίζονται πιο αυστηρά από τις προσθήκες. Ένα αφαιρεμένο αντικείμενο μπαίνει στη whitelist μόνο όταν το αντικείμενο στην παλιά πλευρά ήταν το ίδιο υλικό αρχείου, που καλύπτει τη συνηθισμένη περίπτωση αντικατάστασης ενός security store από νεότερο. Κάθε άλλη αφαίρεση μένει unclassified, γιατί η διαγραφή περιεχομένου από υπογεγραμμένο έγγραφο δεν είναι κάτι που εξουσιοδοτεί επίπεδο δικαιωμάτων. Οι διαφορές σε επίπεδο εγγράφου είναι ακόμα αυστηρότερες: μια αλλαγή στον αριθμό σελίδων πηγαίνει κατευθείαν σε unclassified χωρίς εξέταση μεμονωμένων αντικειμένων, αφού κανένα επίπεδο DocMDP δεν επιτρέπει προσθήκη ή αφαίρεση σελίδων

Η whitelist σφάλει προς την άρνηση

Αυτός είναι ο κανόνας σχεδιασμού που διέπει κάθε οριακή απόφαση. Μια αλλαγή ταξινομημένη λάθος ως επιτρεπτή είναι μια υπογραφή που επαληθεύεται πάνω σε περιεχόμενο που ο συγγραφέας δεν εξουσιοδότησε ποτέ. Μια αλλαγή ταξινομημένη λάθος ως unclassified είναι ένα έγγραφο που σημειώνεται και εξετάζεται από άνθρωπο. Τα δύο αυτά σφάλματα δεν είναι συμμετρικά, οπότε η whitelist παραμένει στενή και τα μη αναγνωρισμένα σχήματα πέφτουν σε unclassified αντί να μαντεύονται

Αυτό έχει μια πρακτική συνέπεια που αξίζει να προβλεφθεί: αρχεία από ασυνήθιστους παραγωγούς θα αναφέρουν μερικές φορές unclassified αλλαγές που, με εξέταση, είναι ακίνδυνες. Η σωστή απάντηση είναι να κοιτάξετε τη λεπτομέρεια ευρήματος και τον αριθμό αντικειμένου αντί να πλάτυνετε τη whitelist, γιατί μια whitelist που μεγαλώνει για να σιγήσει μεμονωμένες αναφορές παύει να είναι έλεγχος ασφαλείας

uses
  PDFlibrary, PDFlibCompare;

var
  Pdf: TPDFlib;
  I, Level: Integer;
begin
  Pdf := TPDFlib.Create(nil);
  try
    Pdf.LoadFromFile('contract-countersigned.pdf', '');
    if Pdf.AnalyzeModifications('contract-as-signed.pdf', '') < 0 then
      raise Exception.Create('the earlier revision could not be loaded');

    // Το TPLModificationLevel διατάσσεται mlNone, mlLTAUpdates,
    // mlFormFilling, mlAnnotations, mlUnclassified· ο getter
    // επιστρέφει το ordinal του
    Level := Pdf.GetModificationLevel;
    // Η επιβολή DocMDP είναι πλέον μία σύγκριση με την πολιτική
    if Level > Ord(mlFormFilling) then
      for I := 0 to Pdf.GetModificationFindingCount - 1 do
        Report.Add(Format('object %d, level %d: %s',
          [Pdf.GetModificationFindingObjNum(I),
           Pdf.GetModificationFindingLevel(I),
           Pdf.GetModificationFindingDetail(I)]));
  finally
    Pdf.Free;
  end;
end;

Το συνολικό επίπεδο είναι το μέγιστο πάνω από όλα τα ευρήματα, που είναι η μόνη υπερασπίσιμη συγκέντρωση: ένα έγγραφο με ενενήντα εννιά προσθήκες archive και μία unclassified αλλαγή είναι μια unclassified αλλαγή

Από κάτω: δακτυλικά αποτυπώματα, όχι κρυπτογραφικά hashes

Η μηχανή σύγκρισης που εκθέτει η CompareWith, και πάνω στην οποία χτίστηκε η ανάλυση τροποποιήσεων, ταυτοποιεί αντικείμενα με ένα δακτυλικό αποτύπωμα του κανονικοποιημένου σώματός τους χρησιμοποιώντας μη κρυπτογραφικό hash 64-bit αντί για SHA-256. Είναι μια σταθμισμένη επιλογή. Αυτό που χρειάζεται η δομική σύγκριση είναι ντετερμινισμός: το ίδιο σώμα αντικειμένου πρέπει πάντα να παράγει το ίδιο αποτύπωμα μέσα σε μια εκτέλεση. Δεν χρειάζεται αντίσταση σε συγκρούσεις, γιατί ένας επιτιθέμενος που ελέγχει και τις δύο πλευρές της σύγκρισης έχει ήδη κερδίσει με άλλα μέσα, και η πληρωμή για πλήρες κρυπτογραφικό hash πάνω σε κάθε αντικείμενο σε έγγραφο εκατομμυρίων αντικειμένων είναι πραγματικό κόστος χωρίς όφελος

Δύο κανόνες κανονικοποίησης έχουν μεγαλύτερη σημασία από την επιλογή hash. Οι έμμεσες αναφορές διπλώνονται σε token κράτησης θέσης αντί να αναπτύσσονται στο αναφερόμενο περιεχόμενο: η ανάπτυξη θα αντέγραφε το σώμα ενός κοινόχρηστου αντικειμένου σε κάθε παραπέμποντα, οπότε μια μικρή επεξεργασία σε έναν κοινόχρηστο περιγραφέα γραμματοσειράς θα ακύρωνε το αποτύπωμα κάθε αντικειμένου που τον φτάνει, και η αναφορά θα ήταν αδύνατη να διαβαστεί. Και οι ίδιοι οι αριθμοί αντικειμένων εξαιρούνται από το αποτύπωμα, γιατί μια επανεγγραφή μπορεί να αλλάξει την αρίθμηση αντικειμένων χωρίς καμία σημασιολογική αλλαγή

Η αντιστοίχιση τρέχει μετά σε δύο περάσματα, ευθυγραμμίζοντας πρώτα με αποτύπωμα και ζευγαρώνοντας το υπόλοιπο με αριθμό αντικειμένου ώστε να ταυτοποιούνται αλλαγές και όχι προσθήκη συν αφαίρεση. Οι φτηνοί έλεγχοι έρχονται πρώτοι παντού: μια διαφορά αριθμού σελίδων αναφέρεται πριν αρχίσει οποιαδήποτε διάσχιση αντικειμένων

Diff αναθεωρήσεων PDF δύο περασμάτων στο PDFlibPas: πρώτα έλεγχος αριθμού σελίδων, αποτυπώματα 64-bit, ευθυγράμμιση αποτυπωμάτων και μετά ζευγάρωμα με αριθμό αντικειμένου
Η μηχανή σύγκρισης αποτυπώνει κανονικοποιημένα σώματα αντικειμένων, αναφέρει πρώτα διαφορές αριθμού σελίδων, και μετά αντιστοιχίζει με αποτύπωμα και αριθμό αντικειμένου

Μια παγίδα: η αυτοσύγκριση δεν εγγυάται πανομοιότυπο αποτέλεσμα

Το φυσικό πρώτο test για μια μηχανή diff είναι να συγκρίνει ένα αρχείο με τον εαυτό του και να ισχυριστεί ότι το αποτέλεσμα είναι πανομοιότυπο. Ο ισχυρισμός αυτός δεν ισχύει εδώ, και ο λόγος είναι διδακτικός. Η δημόσια διαδρομή φόρτωσης και η χαμηλότερου επιπέδου διαδρομή φόρτωσης εγγράφου δεν ρυθμίζουν την αποκωδικοποίηση ταυτοίχως, οπότε το ίδιο αρχείο φορτωμένο μέσω των δύο διαδρομών μπορεί να παράγει αποτυπώματα που διαφέρουν για κάποια αντικείμενα. Η μηχανή δεν κάνει λάθος· οι δύο φορτώσεις παρήγαγαν πραγματικά διαφορετικές καταστάσεις στη μνήμη

Αντί να συμπιεστούν βίαια οι δύο διαδρομές μαζί, η σημασιολογία σύγκρισης διατυπώνεται στενά: η ανάλυση συγκρίνει την τρέχουσα κατάσταση του εγγράφου με μια προηγούμενη αναθεώρηση, και αναφέρει πανομοιότυπο μόνο όταν τα δύο σύνολα αποτυπωμάτων συμπίπτουν ακριβώς. Αυτό είναι το ερώτημα που θέτουν πραγματικά οι χρήστες, και δεν απαιτεί οι δύο loaders να είναι εναλλάξιμοι. Όταν σχεδιάζετε μια λειτουργία σύγκρισης, ο ορισμός του τι σημαίνει «το ίδιο» είναι μεγαλύτερο μέρος της δουλειάς από τον υπολογισμό της

Πού να το χρησιμοποιήσετε

Δύο σημεία. Σε μια αναφορά επικύρωσης, δίπλα στον έλεγχο υπογραφών, ώστε ένας εξεταστής να βλέπει όχι μόνο αν η υπογραφή είναι κρυπτογραφικά άθικτη αλλά τι έγινε στο έγγραφο μετά· η πλευρά υπογραφών καλύπτεται στην υπογραφή και επικύρωση PAdES. Και σε μια πύλη εισόδου, όπου ένα έγγραφο που φτάνει από έξω ελέγχεται με το αντίγραφο που στείλατε, ώστε μια επιστρεφόμενη σύμβαση με προστιθέμενο σχολιασμό να αντιμετωπίζεται διαφορετικά από μία με επεξεργασμένη σελίδα

Μια επιφύλαξη στο εύρος. Αυτή η ανάλυση σας λέει τι άλλαξε ανάμεσα σε δύο αναθεωρήσεις της ίδιας γενεαλογίας εγγράφου. Δεν σας λέει αν το ορατό περιεχόμενο είναι παραπλανητικό, αν το appearance stream ενός πεδίου φόρμας ταιριάζει με την τιμή του, ή αν κείμενο κρυμμένο κάτω από ένα overlay εξακολουθεί να υπάρχει στο content stream. Αυτά χρειάζονται ξεχωριστή μεταχείριση, και η πλευρά αφαίρεσης περιεχομένου καλύπτεται στο άρθρο για την πραγματική redaction. Τα σημεία εισόδου ανάλυσης και σύγκρισης τεκμηριώνονται στη σελίδα προϊόντος losLab PDF Developer Library