Skip to main content Link Search Menu Expand Document (external link)

Security

Master PDF security features including encryption, password protection, and permission controls to protect sensitive documents.


Learning Objectives

By the end of this article, you’ll be able to:

  • Add password protection to PDFs
  • Configure user and owner passwords
  • Set document permissions
  • Control printing, copying, and editing
  • Understand encryption levels
  • Implement security best practices

PDF Security Basics

PDF security provides:

  • Encryption - Protects document content
  • Password Protection - Controls who can open the document
  • Permissions - Controls what users can do with the document

Basic Password Protection

User Password (Document Open)

using Scryber.Components;
using Scryber.PDF;
using System.IO;

var doc = Document.ParseDocument("template.html");

// Require password to open
doc.RenderOptions.SecurityOptions = new PDFSecurityOptions
{
    UserPassword = "secretpassword"
};

doc.SaveAsPDF(stream);

User Password:

  • Required to open the document
  • Encrypts the content
  • Users must enter password to view

Owner Password (Permissions)

// Owner password allows changing permissions
doc.RenderOptions.SecurityOptions = new PDFSecurityOptions
{
    OwnerPassword = "adminpassword"
};

// Document can be opened without password
// But permissions can only be changed with owner password

Both Passwords

// Most secure: both passwords
doc.RenderOptions.SecurityOptions = new PDFSecurityOptions
{
    UserPassword = "viewpassword",      // Required to open
    OwnerPassword = "adminpassword"     // Required to change permissions
};

Document Permissions

Common Permissions

doc.RenderOptions.SecurityOptions = new PDFSecurityOptions
{
    OwnerPassword = "admin123",

    // Printing permissions
    AllowPrinting = true,
    AllowHighQualityPrinting = true,

    // Content permissions
    AllowCopying = false,
    AllowAccessibility = true,

    // Editing permissions
    AllowAnnotations = false,
    AllowFormFilling = false,
    AllowDocumentAssembly = false,

    // Modification permissions
    AllowModification = false
};

Permission Descriptions

Permission Description
AllowPrinting Allow document printing
AllowHighQualityPrinting Allow high-resolution printing
AllowCopying Allow copying text and graphics
AllowAccessibility Allow screen readers (should be true)
AllowAnnotations Allow adding comments and annotations
AllowFormFilling Allow filling form fields
AllowDocumentAssembly Allow inserting/deleting/rotating pages
AllowModification Allow document modification

Security Profiles

Read-Only Document

// Users can view and print, but not modify
doc.RenderOptions.SecurityOptions = new PDFSecurityOptions
{
    OwnerPassword = "admin123",
    AllowPrinting = true,
    AllowCopying = false,
    AllowAnnotations = false,
    AllowFormFilling = false,
    AllowModification = false,
    AllowAccessibility = true  // Important for accessibility
};

Confidential Document

// Password required, no printing or copying
doc.RenderOptions.SecurityOptions = new PDFSecurityOptions
{
    UserPassword = "confidential",
    OwnerPassword = "admin123",
    AllowPrinting = false,
    AllowCopying = false,
    AllowAnnotations = false,
    AllowAccessibility = true  // Still allow screen readers
};

Form Document

// Allow form filling only
doc.RenderOptions.SecurityOptions = new PDFSecurityOptions
{
    OwnerPassword = "admin123",
    AllowPrinting = true,
    AllowCopying = false,
    AllowFormFilling = true,
    AllowAnnotations = false,
    AllowModification = false,
    AllowAccessibility = true
};

Practical Examples

Example 1: Secure Invoice Generator

using Scryber.Components;
using Scryber.PDF;
using System;
using System.IO;

public class SecureInvoiceGenerator
{
    private readonly string _ownerPassword;

    public SecureInvoiceGenerator(string ownerPassword)
    {
        _ownerPassword = ownerPassword;
    }

    public void GenerateInvoice(Invoice invoice, Stream output)
    {
        var doc = Document.ParseDocument("invoice-template.html");

        // Set metadata
        doc.Info.Title = $"Invoice {invoice.Number}";
        doc.Info.Author = invoice.CompanyName;

        // Configure security
        doc.RenderOptions.SecurityOptions = new PDFSecurityOptions
        {
            OwnerPassword = _ownerPassword,

            // Allow printing invoice
            AllowPrinting = true,
            AllowHighQualityPrinting = true,

            // Prevent copying (protect pricing/details)
            AllowCopying = false,

            // Prevent modification
            AllowAnnotations = false,
            AllowModification = false,
            AllowDocumentAssembly = false,

            // Allow accessibility
            AllowAccessibility = true
        };

        // Bind data
        doc.Params["invoice"] = invoice;

        // Generate
        doc.SaveAsPDF(output);

        Console.WriteLine($"Secure invoice {invoice.Number} generated");
    }
}

// Usage
var generator = new SecureInvoiceGenerator("owner-pass-2024");
using (var output = new FileStream("invoice.pdf", FileMode.Create))
{
    generator.GenerateInvoice(invoice, output);
}

Example 2: Confidential Report with Password

public class ConfidentialReportGenerator
{
    public void GenerateReport(ReportData data, string password, Stream output)
    {
        var doc = Document.ParseDocument("report-template.html");

        // Set metadata
        doc.Info.Title = $"{data.Classification} Report - {data.Title}";
        doc.Info.Author = data.Department;
        doc.Info.Subject = "Confidential Information";

        // High security configuration
        doc.RenderOptions.SecurityOptions = new PDFSecurityOptions
        {
            // Both passwords required
            UserPassword = password,
            OwnerPassword = GenerateOwnerPassword(data.ReportId),

            // Minimal permissions
            AllowPrinting = false,        // No printing
            AllowCopying = false,         // No copying
            AllowAnnotations = false,     // No annotations
            AllowFormFilling = false,     // No forms
            AllowModification = false,    // No modifications
            AllowDocumentAssembly = false, // No assembly
            AllowAccessibility = true     // Allow screen readers
        };

        // Bind data
        doc.Params["report"] = data;

        // Generate
        doc.SaveAsPDF(output);

        LogSecureDocumentCreation(data.ReportId, data.Classification);
    }

    private string GenerateOwnerPassword(string reportId)
    {
        // Generate secure owner password based on report ID
        return Convert.ToBase64String(
            System.Text.Encoding.UTF8.GetBytes($"owner-{reportId}-{DateTime.Now.Year}")
        );
    }

    private void LogSecureDocumentCreation(string reportId, string classification)
    {
        Console.WriteLine($"[SECURITY] Confidential report generated: {reportId}");
        Console.WriteLine($"[SECURITY] Classification: {classification}");
        Console.WriteLine($"[SECURITY] Timestamp: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
    }
}

// Usage
var generator = new ConfidentialReportGenerator();
using (var output = new FileStream("confidential-report.pdf", FileMode.Create))
{
    generator.GenerateReport(reportData, "SecretPassword123!", output);
}

Example 3: Dynamic Security Based on Classification

public class ClassificationBasedGenerator
{
    public void GenerateDocument(
        DocumentData data,
        SecurityClassification classification,
        Stream output)
    {
        var doc = Document.ParseDocument("template.html");

        // Set metadata
        doc.Info.Title = data.Title;
        doc.Info.Subject = $"{classification} Information";

        // Configure security based on classification
        doc.RenderOptions.SecurityOptions = GetSecurityOptions(classification, data.DocumentId);

        // Bind data
        doc.Params["document"] = data;

        // Generate
        doc.SaveAsPDF(output);
    }

    private PDFSecurityOptions GetSecurityOptions(
        SecurityClassification classification,
        string documentId)
    {
        switch (classification)
        {
            case SecurityClassification.Public:
                // No restrictions
                return null;

            case SecurityClassification.Internal:
                // Basic protection
                return new PDFSecurityOptions
                {
                    OwnerPassword = $"internal-{documentId}",
                    AllowPrinting = true,
                    AllowCopying = true,
                    AllowModification = false,
                    AllowAccessibility = true
                };

            case SecurityClassification.Confidential:
                // Medium protection
                return new PDFSecurityOptions
                {
                    UserPassword = GenerateUserPassword(documentId),
                    OwnerPassword = GenerateOwnerPassword(documentId),
                    AllowPrinting = true,
                    AllowCopying = false,
                    AllowModification = false,
                    AllowAnnotations = false,
                    AllowAccessibility = true
                };

            case SecurityClassification.Secret:
                // High protection
                return new PDFSecurityOptions
                {
                    UserPassword = GenerateUserPassword(documentId),
                    OwnerPassword = GenerateOwnerPassword(documentId),
                    AllowPrinting = false,
                    AllowCopying = false,
                    AllowModification = false,
                    AllowAnnotations = false,
                    AllowFormFilling = false,
                    AllowDocumentAssembly = false,
                    AllowAccessibility = true
                };

            default:
                throw new ArgumentException($"Unknown classification: {classification}");
        }
    }

    private string GenerateUserPassword(string documentId)
    {
        // Generate user password (in production, use proper key management)
        return Convert.ToBase64String(
            System.Text.Encoding.UTF8.GetBytes($"view-{documentId}")
        );
    }

    private string GenerateOwnerPassword(string documentId)
    {
        // Generate owner password (in production, use proper key management)
        return Convert.ToBase64String(
            System.Text.Encoding.UTF8.GetBytes($"admin-{documentId}")
        );
    }
}

public enum SecurityClassification
{
    Public,
    Internal,
    Confidential,
    Secret
}

Encryption Levels

40-bit Encryption (PDF 1.3)

// Weak encryption - for legacy compatibility only
// Not recommended for sensitive data

128-bit Encryption (PDF 1.4+)

// Standard encryption - good for most uses
doc.RenderOptions.PDFVersion = PDFVersion.PDF14;
doc.RenderOptions.SecurityOptions = new PDFSecurityOptions
{
    UserPassword = "password"
};

256-bit AES Encryption (PDF 1.7+)

// Strong encryption - recommended for sensitive data
doc.RenderOptions.PDFVersion = PDFVersion.PDF17;
doc.RenderOptions.SecurityOptions = new PDFSecurityOptions
{
    UserPassword = "strongpassword"
};

Security Best Practices

Password Strength

// ❌ Weak passwords
UserPassword = "12345"
UserPassword = "password"

// ✅ Strong passwords
UserPassword = "Tr0ng!P@ssw0rd2024"  // 8+ chars, mixed case, numbers, symbols

Password Management

// ❌ Hard-coded passwords
doc.RenderOptions.SecurityOptions = new PDFSecurityOptions
{
    OwnerPassword = "admin123"  // Hard-coded!
};

// ✅ Secure password management
var ownerPassword = Configuration["Security:OwnerPassword"];
doc.RenderOptions.SecurityOptions = new PDFSecurityOptions
{
    OwnerPassword = ownerPassword
};

Accessibility

// ✅ Always allow accessibility
doc.RenderOptions.SecurityOptions = new PDFSecurityOptions
{
    AllowAccessibility = true,  // Important for screen readers
    // ... other permissions
};

Try It Yourself

Exercise 1: Security Profiles

Create security profiles for:

  • Public documents (no restrictions)
  • Internal documents (basic protection)
  • Confidential documents (password + restrictions)
  • Test each profile

Exercise 2: Password Generator

Build a password generator that:

  • Creates strong passwords
  • Stores passwords securely
  • Retrieves passwords for verification
  • Rotates passwords periodically

Exercise 3: Permission Tester

Create a tool that:

  • Generates PDFs with different permissions
  • Tests each permission in PDF viewer
  • Documents viewer compatibility
  • Verifies security works as expected

Common Pitfalls

❌ Weak Passwords

// Too simple
UserPassword = "pass"
OwnerPassword = "admin"

Solution:

// Strong passwords
UserPassword = "Tr0ng!Us3rP@ss2024"
OwnerPassword = "Adm!nP@ssw0rd#2024"

❌ Disabling Accessibility

// Blocks screen readers
AllowAccessibility = false

Solution:

// Always allow accessibility
AllowAccessibility = true

❌ Security with PDF/A

// PDF/A doesn't allow encryption
doc.RenderOptions.Conformance = PDFConformance.PDFA2B;
doc.RenderOptions.SecurityOptions = new PDFSecurityOptions
{
    UserPassword = "password"  // ❌ Will fail!
};

Solution:

// No security with PDF/A
doc.RenderOptions.Conformance = PDFConformance.PDFA2B;
doc.RenderOptions.SecurityOptions = null;  // ✅

Security Checklist

  • Appropriate security profile chosen
  • Strong passwords used (8+ characters)
  • Owner password set
  • Permissions configured appropriately
  • AllowAccessibility set to true
  • PDF version supports encryption level
  • Passwords stored securely (not hard-coded)
  • Tested in PDF viewers
  • Compliance checked (no encryption with PDF/A)

Best Practices

  1. Strong Passwords - 8+ characters, mixed case, numbers, symbols
  2. Secure Storage - Never hard-code passwords
  3. Owner Password - Always set to protect permissions
  4. Accessibility - Always allow (set to true)
  5. Test Thoroughly - Verify in multiple PDF viewers
  6. Document Policy - Clear security classification system
  7. Audit Trail - Log security-related operations
  8. Regular Review - Update passwords periodically

Security Limitations

PDF Security is NOT:

  • Unbreakable (password-protected PDFs can be cracked)
  • DRM (doesn’t prevent screenshots)
  • Perfect protection (determined users can bypass)

PDF Security IS:

  • A deterrent for casual users
  • Compliance with basic security requirements
  • Protection for basic confidentiality

For high security needs, consider:

  • Secure transmission channels (HTTPS, SFTP)
  • Access control at distribution level
  • Watermarks for traceability
  • Digital signatures for authenticity

Next Steps

  1. Optimization & Performance - File size and speed optimization
  2. Production & Deployment - Production configuration
  3. Practical Applications - Real-world examples

Continue learning → Optimization & Performance