PDF 잠금 해제·비밀번호 제거 완벽 가이드 2026

PDF 잠금 해제·비밀번호 제거: 원리부터 실무까지

PDF 암호화 방식(사용자 암호 vs 소유자 암호), 온라인·오프라인 도구, 법적 고려사항을 종합적으로 분석하고 각 상황별 최적 솔루션을 제시합니다.

1. PDF 암호화 유형 및 제거 난이도

암호화 유형목적제거 난이도법적 허용
사용자 암호 (User Password)파일 열기 제한중간비추천
소유자 암호 (Owner Password)인쇄/복사/편집 제한낮음대부분 허용
40-bit RC4구식 암호화매우낮음매우 쉬움
128-bit RC4중간 보안낮음대부분 허용
256-bit AES높은 보안높음매우 어려움

2. 온라인 도구 (무료, 설치 불필요)

도구비용시간지원보안추천
ILovePDF무료5초128-bit중간가장 인기
SmallPDF무료6초128-bit중간빠름
PDFUnlock무료2초128-bit낮음간단
Sejda무료4초256-bit높음안전
PDF2Go무료5초128-bit중간신뢰
PDF Candy무료4초128-bit중간다기능

3. 데스크톱 소프트웨어

소프트웨어비용시간지원추천
Adobe Acrobat Pro월 $9.993초모든 암호화전문가
Foxit PhantomPDF월 $9.994초대부분기업
PDF-XChange Editor일회 $752초128-bit개인
Preview (macOS)무료1초소유자 암호macOS

4. CLI 도구 (배치 처리)

4.1 qpdf (가장 강력)

#!/bin/bash

# qpdf로 소유자 암호 제거 (사용자 암호 불필요)
qpdf --decrypt input.pdf output.pdf

# 사용자 암호로 파일 해제
qpdf --password=mypassword --decrypt input.pdf output.pdf

# 배치 처리
for file in *.pdf; do
    qpdf --decrypt "$file" "unlocked_$file"
done

# 진행 상황 표시
for file in *.pdf; do
    echo "처리 중: $file"
    qpdf --decrypt "$file" "unlocked_$file" && echo "✓ $file"
done

4.2 pdftk (간단)

#!/bin/bash

# pdftk로 소유자 암호 제거
pdftk input.pdf output output.pdf

# 사용자 암호로 해제
pdftk input.pdf input_pw mypassword output output.pdf

# 배치 처리
for file in *.pdf; do
    pdftk "$file" output "unlocked_$file"
done

4.3 Ghostscript (고급)

#!/bin/bash

# Ghostscript로 암호 제거 후 재저장
gs -sDEVICE=pdfwrite -dNOPAUSE -dBATCH    -sOutputFile=output.pdf    input.pdf

# 사용자 암호 필요 시
gs -sDEVICE=pdfwrite -dNOPAUSE -dBATCH    -sInputPassword=mypassword    -sOutputFile=output.pdf    input.pdf

5. Python 라이브러리

5.1 pikepdf (권장)

import pikepdf

# 소유자 암호 제거 (가장 간단)
with pikepdf.open('input.pdf') as pdf:
    pdf.save('output.pdf')

# 사용자 암호로 해제
with pikepdf.open('input.pdf', password='mypassword') as pdf:
    pdf.save('output.pdf')

# 배치 처리
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor

def unlock_pdf(pdf_file):
    try:
        with pikepdf.open(pdf_file) as pdf:
            output_file = pdf_file.parent / f"unlocked_{pdf_file.name}"
            pdf.save(output_file)
        return f"✓ {pdf_file.name}"
    except Exception as e:
        return f"✗ {pdf_file.name}: {e}"

pdf_files = list(Path('/home/user/pdfs').glob('*.pdf'))

with ThreadPoolExecutor(max_workers=4) as executor:
    results = list(executor.map(unlock_pdf, pdf_files))

for result in results:
    print(result)

5.2 PyPDF2

from PyPDF2 import PdfReader, PdfWriter

# 소유자 암호 제거
reader = PdfReader('input.pdf')
writer = PdfWriter()

# 모든 페이지 복사
for page in reader.pages:
    writer.add_page(page)

# 암호 제거 후 저장
with open('output.pdf', 'wb') as f:
    writer.write(f)

# 사용자 암호로 해제 (더 복잡함)
def unlock_with_password(input_pdf, password, output_pdf):
    reader = PdfReader(input_pdf)
    
    if reader.is_encrypted:
        if not reader.decrypt(password):
            raise ValueError("암호가 잘못됨")
    
    writer = PdfWriter()
    for page in reader.pages:
        writer.add_page(page)
    
    with open(output_pdf, 'wb') as f:
        writer.write(f)

unlock_with_password('input.pdf', 'mypassword', 'output.pdf')

5.3 qpdf Python 바인딩

import subprocess
import os

def unlock_pdf_qpdf(input_pdf, output_pdf, password=None):
    """qpdf를 사용한 암호 제거 (가장 안정적)"""
    
    cmd = ['qpdf']
    
    if password:
        cmd.extend([f'--password={password}'])
    
    cmd.extend(['--decrypt', input_pdf, output_pdf])
    
    try:
        result = subprocess.run(cmd, capture_output=True, text=True, check=True)
        print(f"✓ {input_pdf} → {output_pdf}")
        return True
    except subprocess.CalledProcessError as e:
        print(f"✗ 오류: {e.stderr}")
        return False

# 사용
unlock_pdf_qpdf('input.pdf', 'output.pdf')

6. 암호화 방식 진단 및 제거

6.1 암호화 유형 확인

from PyPDF2 import PdfReader
import subprocess

def detect_encryption_type(pdf_file):
    """PDF 암호화 유형 감지"""
    
    # PyPDF2로 확인
    reader = PdfReader(pdf_file)
    
    result = {
        "file": pdf_file,
        "is_encrypted": reader.is_encrypted,
        "encryption_method": "Unknown"
    }
    
    if reader.is_encrypted:
        # qpdf로 상세 정보 확인
        try:
            qpdf_output = subprocess.run(
                ['qpdf', '--check', pdf_file],
                capture_output=True,
                text=True
            ).stdout
            
            if '40-bit' in qpdf_output:
                result["encryption_method"] = "40-bit RC4 (Very Weak)"
            elif '128-bit' in qpdf_output or 'RC4' in qpdf_output:
                result["encryption_method"] = "128-bit RC4 (Weak)"
            elif 'AES' in qpdf_output and '256' in qpdf_output:
                result["encryption_method"] = "256-bit AES (Strong)"
            elif 'AES' in qpdf_output:
                result["encryption_method"] = "128-bit AES (Medium)"
            
            # 암호화 유형
            if 'User password' in qpdf_output:
                result["has_user_password"] = True
            if 'Owner password' in qpdf_output:
                result["has_owner_password"] = True
        
        except Exception as e:
            result["error"] = str(e)
    
    return result

# 사용
info = detect_encryption_type('input.pdf')
print(f"파일: {info['file']}")
print(f"암호화됨: {info['is_encrypted']}")
print(f"암호화 방식: {info['encryption_method']}")

6.2 자동 제거

def auto_unlock_pdf(input_pdf, output_pdf, common_passwords=None):
    """자동으로 PDF 잠금 해제 시도"""
    
    import pikepdf
    
    # 기본 비밀번호 리스트
    if common_passwords is None:
        common_passwords = [
            '', '123456', 'password', 'admin', '12345678',
            'qwerty', '123123', '1q2w3e4r', '666666', '000000'
        ]
    
    # 1. 암호 없이 시도
    try:
        with pikepdf.open(input_pdf) as pdf:
            pdf.save(output_pdf)
        print(f"✓ 암호 없이 해제 성공")
        return True
    except Exception as e:
        print(f"암호 필요: {e}")
    
    # 2. 일반 비밀번호로 시도
    for password in common_passwords:
        try:
            with pikepdf.open(input_pdf, password=password) as pdf:
                pdf.save(output_pdf)
            print(f"✓ 비밀번호 '{password}'로 해제 성공")
            return True
        except:
            pass
    
    print(f"✗ 자동 해제 실패")
    return False

auto_unlock_pdf('input.pdf', 'output.pdf')

7. 법적 고려사항

언제 PDF 잠금 해제가 합법인가?

상황합법성설명
자신의 파일✓ 합법소유자 암호 제거는 항상 가능
회사 문서 (승인)✓ 합법관리자 승인이 있으면 가능
개인정보보호법 대상△ 주의GDPR/HIPAA 등 규제 확인
저작권 보호 콘텐츠✗ 불법DMCA, EU 저작권법 위반
타인의 파일 (미승인)✗ 불법권한 없이 제거 시 사이버 범죄

8. 성능 비교

방법시간(100MB)메모리추천
ILovePDF5초-개인
PDFUnlock2초-빠름
qpdf CLI1초30 MB배치
pikepdf1.5초80 MBPython
Adobe Acrobat3초450 MB전문가
Ghostscript2초60 MB고급

9. 배치 처리 (대량 파일)

#!/usr/bin/env python3

from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
import subprocess
import time

def unlock_batch(input_dir, output_dir, num_workers=4):
    """대량 PDF 잠금 해제"""
    
    Path(output_dir).mkdir(exist_ok=True)
    pdf_files = list(Path(input_dir).glob('*.pdf'))
    
    print(f"🔓 {len(pdf_files)}개 파일 해제 시작 ({num_workers} workers)")
    
    def unlock_single(pdf_file):
        try:
            output_file = Path(output_dir) / pdf_file.name
            
            # qpdf 사용 (가장 안정적)
            subprocess.run([
                'qpdf', '--decrypt',
                str(pdf_file), str(output_file)
            ], check=True, capture_output=True)
            
            return f"✓ {pdf_file.name}"
        except Exception as e:
            return f"✗ {pdf_file.name}: {e}"
    
    start_time = time.time()
    
    with ThreadPoolExecutor(max_workers=num_workers) as executor:
        results = list(executor.map(unlock_single, pdf_files))
    
    elapsed = time.time() - start_time
    successful = sum(1 for r in results if r.startswith("✓"))
    
    print(f"
✅ 완료")
    print(f"  성공: {successful}/{len(pdf_files)}")
    print(f"  시간: {elapsed:.1f}초 ({len(pdf_files)/elapsed:.1f} 파일/초)")
    
    return results

# 사용
results = unlock_batch('/home/user/locked_pdfs', '/home/user/unlocked_pdfs')

10. FAQ

  • 가장 빠른 방법? qpdf CLI (1초)
  • 가장 안전한 온라인 도구? Sejda (256-bit AES 지원)
  • Python에서 추천? pikepdf (가장 안정적)
  • 배치 처리 최고? qpdf + ThreadPoolExecutor
  • 타인의 PDF 해제 가능? 법적으로 문제 될 수 있음
  • 256-bit AES 제거? 거의 불가능 (무작정 공격 필요)
  • 사용자 암호 제거? 소유자 암호 필요한 경우 어려움

11. 관련 자료

댓글

이 블로그의 인기 게시물

르무통 신발 단점: 구매 전에 꼭 알아야 할 정보

국민연금 예상수령액 조회 방법 및 계산법

국민연금 납부증명서 발급 방법 쉽게 정리