PDF 加密与加水印:两种密码、权限位、水印铺法与常见误区

一、结论先给

PDF 有且只有两种密码,很多人用错了一辈子。

用户密码(user password) 所有者密码(owner password)
也叫 打开密码、文档密码 权限密码、主密码
作用 打开就要输,不输打不开 打开不需要,改权限才需要
防的是 陌生人打开 陌生人修改/打印/复制
强度 真防 只是君子协定

最关键的一句话:只设"禁止打印/禁止复制"而不设打开密码,等于没防。权限位是写在文件里的一段声明,阅读器选择遵守而已——不遵守的软件直接忽略,一秒解锁全部权限。

所以真正的用法是:

要防外传  → 设打开密码(user password)+ AES-256
要防改     → 设权限密码(owner password)
要溯源     → 铺可见水印(姓名/工号/时间)
要威慑     → 水印 + 打开密码 一起上

二、加密:qpdf 一条命令搞定

sudo apt install qpdf

2.1 基础用法

# 设打开密码(256 位 AES)
qpdf --encrypt "打开密码" "" 256 -- input.pdf out.pdf
#                    ↑         ↑
#                用户密码   所有者密码(留空=随机生成)

# 两个都设(推荐)
qpdf --encrypt "user123" "owner456" 256 -- input.pdf out.pdf

# 只设权限密码(不设打开密码,打开即看)
qpdf --encrypt "" "owner456" 256 -- input.pdf out.pdf

中间那个 -- 不能省,否则以 - 开头的文件名会被当成参数。

2.2 权限位:细粒度控制

qpdf --encrypt "user123" "owner456" 256 \
  --print=full \
  --modify=none \
  --extract=n \
  --annotate=n \
  -- input.pdf out.pdf
参数 可选值 含义
--print full / low / none 高质量打印 / 低质量打印 / 禁止打印
--modify all / annotate / form / none 允许改 / 只填表单 / 禁止改
--extract y / n 能否复制文字、抽图
--annotate y / n 能否加批注
--assemble y / n 能否增删页
--form y / n 能否填表单
--accessibility y / n 屏幕阅读器能否读(建议 y,关了影响无障碍)

2.3 加密强度怎么选

参数 算法 兼容性 建议
40 RC4 40-bit 万能,包括很老的阅读器 别用,可被暴力秒破
128 RC4 128-bit 很好 一般场景够
256 AES-256 现代阅读器都支持(PDF 1.7+) 默认选这个
# 完整推荐写法
qpdf --encrypt "强密码" "owner密码" 256 \
  --print=low --modify=none --extract=n --accessibility=y \
  --input.pdf out.pdf

2.4 校验加密结果

# 看是否加密、用的什么算法
pdfinfo out.pdf | grep -i -E "encrypted|security"

# 详细看权限(qpdf 独有)
qpdf --show-encryption out.pdf

典型输出:

R = 6
P = -1852
User password = required
extract for accessibility: allowed
extract for any purpose: not allowed
print low resolution: allowed
print high resolution: not allowed
modify document: not allowed

R = 6 表示 AES-256(PDF 2.0 的加密修订版本),R = 5 也是 AES-256,R = 4 是 RC4 128-bit。

三、加水印:三种铺法

3.1 pdftk:最快的方案

sudo apt install pdftk-java     # 新版本是 java 实现

先做一张水印图(透明底 PNG):

# 用 ImageMagick 生成半透明斜向文字水印
magick -size 800x600 xc:none \
  -font "$(fc-match -f '%{file}' 'WenQuanYi Zen Hei')" \
  -pointsize 48 -fill 'rgba(0,0,0,0.18)' \
  -draw "rotate -30 text 80,400 '机密 · 仅供内部使用'" \
  watermark.png

三种铺法:

# 1) 单层水印(只盖在第一页)—— 封面场景
pdftk input.pdf stamp watermark.pdf output out.pdf

# 2) 多层水印(每页都盖)—— 最常用
pdftk input.pdf multistamp watermark.pdf output out.pdf

# 3) 背景水印(盖在内容下面,不遮字)
pdftk input.pdf background watermark.pdf output out.pdf
子命令 位置 覆盖
stamp 内容之上 仅第一页
multistamp 内容之上 每一页
background 内容之下 每一页

选择建议:要显眼的用 multistamp(比如"作废""样例"),要低调的用 background(比如公司名底纹)。

3.2 pikepdf:精细控制(Python)

from pikepdf import Pdf, Page, Rectangle
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
import io

# 注册中文字体(系统有的话)
pdfmetrics.registerFont(TTFont('WQY', '/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc'))

def make_watermark(text, pagesize=A4):
    buf = io.BytesIO()
    c = canvas.Canvas(buf, pagesize=pagesize)
    w, h = pagesize
    c.saveState()
    c.setFont('WQY', 32)
    c.setFillColorRGB(0, 0, 0, alpha=0.15)
    c.translate(w / 2, h / 2)
    c.rotate(30)
    # 平铺多行多列
    for row in range(-4, 5):
        for col in range(-3, 4):
            c.drawCentredString(col * 260, row * 150, text)
    c.restoreState()
    c.showPage()
    c.save()
    buf.seek(0)
    return Pdf.open(buf)

wm = make_watermark('机密 内部资料')
src = Pdf.open('input.pdf')
for page in src.pages:
    # as_xobject 会复用同一份对象,不会把文件撑大
    page.add_overlay(wm.pages[0].as_xobject())
src.save('out.pdf')

as_xobject() 是关键:直接 add_overlay(wm.pages[0]) 会给每页嵌一份完整水印对象,100 页的文件会涨好几 MB;用 xobject 则只存一次。

3.3 用现成工具

命令行强大但要装环境,偶尔用一次不值当。浏览器里做也行,PDF 加密加水印工具 支持设密码 + 铺文字水印,文件不出本机——对要外发又含敏感信息的 PDF,这个"不上传"本身就是一半的安全性。

四、五个真实误区

误区 1:设了"禁止打印"就安全了

权限位是声明,不是加密。大量工具(包括 qpdf --decrypt)在有权限密码的情况下能解开,没有权限密码时更是直接忽略。真正防打开只能用 user password。

误区 2:加水印能防截图

不能。水印的作用是溯源和威慑——对方知道截图里带着他的名字/工号,动手前要掂量。技术上一张截图就绕过了。

误区 3:密码设得简单没关系

PDF 密码可以被离线暴力破解(hashcat 有专门的模式),40-bit RC4 在现代 GPU 上是秒级。所以:

  • 一定要用 256 位 AES
  • 密码至少 12 位,混合大小写数字符号
  • 别用公司名+年份这类可猜的组合

可以用 哈希计算 生成一段随机串当密码(比如取 SHA256 的前 16 位)。

误区 4:加密和压缩能同时一次搞定

顺序很重要:先压缩,再加密。加密后的 PDF 内容流是密文,Ghostscript 之类的工具读不出图像,压不动。

gs -sDEVICE=pdfwrite -dPDFSETTINGS=/ebook -sOutputFile=small.pdf input.pdf
qpdf --encrypt "pwd" "owner" 256 -- small.pdf final.pdf

误区 5:加密后元数据还留着敏感信息

文件名改了,但 PDF 的元信息里可能还写着作者真名、公司名、原始路径。

# 看元数据
pdfinfo out.pdf
exiftool out.pdf

# 清元数据
exiftool -all= -overwrite_original out.pdf
qpdf --linearize out.pdf clean.pdf     # qpdf 也会顺带丢弃部分元数据

五、解开自己文档的密码

仅限你自己拥有、忘记了密码的文档。 别人加密的文件不在讨论范围内。

# 知道打开密码,去掉密码方便自己用
qpdf --decrypt --password='你的密码' input.pdf plain.pdf

# 知道权限密码,解除权限限制
qpdf --decrypt --password='owner密码' input.pdf plain.pdf

# 批量
for f in *.pdf; do
  qpdf --decrypt --password='pwd' "$f" "plain-${f}" 2>/dev/null || echo "跳过(密码不符): $f"
done

六、一条完整的外发流程

给客户发一份"能看、不能随便改、能溯源"的 PDF:

#!/usr/bin/env bash
set -euo pipefail
IN=$1; NAME=$2
OUT="out/${IN%.pdf}-外发.pdf"

mkdir -p out

# 1) 压缩(先压,后面加密了就压不动)
gs -sDEVICE=pdfwrite -dPDFSETTINGS=/ebook -dNOPAUSE -dBATCH -dQUIET \
   -sOutputFile=/tmp/small.pdf "$IN"

# 2) 生成带客户名的水印(溯源)
magick -size 800x600 xc:none -pointsize 40 \
  -fill 'rgba(0,0,0,0.16)' \
  -draw "rotate -30 text 100,420 '仅提供给 ${NAME}'" /tmp/wm.png
cairosvg /dev/null 2>/dev/null || true
magick /tmp/wm.png /tmp/wm.pdf

# 3) 铺水印(每页,内容之上)
pdftk /tmp/small.pdf multistamp /tmp/wm.pdf output /tmp/wm.pdf.out.pdf

# 4) 加密(打开密码 + AES-256 + 低质量打印 + 禁改)
qpdf --encrypt "打开密码" "owner密码" 256 \
  --print=low --modify=none --extract=n --accessibility=y \
  -- /tmp/wm.pdf.out.pdf "$OUT"

# 5) 清元数据
exiftool -all= -overwrite_original "$OUT" 2>/dev/null || true

# 6) 校验
echo "页数: $(pdfinfo "$OUT" | awk '/^Pages/{print $2}')"
echo "大小: $(du -h "$OUT" | cut -f1)"
qpdf --show-encryption "$OUT" | head -3

七、几条纪律

  1. 要防打开就一定要设 user password,只设权限等于没防。
  2. 一律用 256 位 AES,40/128 位的 RC4 已经不够看。
  3. 先压缩再加密,顺序反了就压不动。
  4. 水印用 as_xobject() 复用,别每页嵌一份。
  5. 发之前清元数据(exiftool -all=)。
  6. 密码要长且随机,别用公司名+年份。
  7. 水印是威慑不是技术防护,别指望它挡住截图。

八、延伸阅读

👉 相关在线工具:PDF 加密加水印 · PDF 合并 · 图片水印 · 哈希计算,免登录、浏览器内处理。

还有 65 个免费在线工具

纯前端实现,不用注册,数据不上传服务器。

浏览全部工具