Java와 타임스탬프를 사용하여 PDF 서명하는 방법
계약서, 청구서 또는 중요한 문서를 변조로부터 보호해야 할 때, PDF 서명 방법을 안전하게 하는 것이 최우선 과제가 됩니다. 이 가이드에서는 GroupDocs.Signature for Java를 사용하여 PDF에 디지털 서명과 신뢰할 수 있는 타임스탬프를 추가하는 방법을 알아봅니다. 이 방법은 오프라인에서도 작동하며, 최대 500 MB 파일까지 확장 가능하고 몇 줄의 코드만 필요합니다.
빠른 답변
- Java에서 PDF 서명을 간소화하는 라이브러리는? GroupDocs.Signature for Java.
- 인터넷 연결이 필요합니까? 타임스탬프 기관에만 필요합니다; 암호화 서명은 로컬에서 실행됩니다.
- 테스트용으로 자체 서명 인증서를 사용할 수 있나요? 예,
keytool로 생성합니다. - 크기 제한이 있나요? 라이브러리는 전체 파일을 메모리에 로드하지 않고도 최대 500 MB PDF에 서명할 수 있습니다.
- GroupDocs가 지원하는 포맷 수는? DOCX, XLSX, PPTX, HTML 및 이미지 등을 포함해 50개 이상의 입력 및 출력 포맷을 지원합니다.
Java로 PDF에 서명하는 방법
PDF를 로드하고, 인증서로 DigitalSignature를 구성한 뒤, 필요에 따라 RFC 3161 준수 TSA에서 타임스탬프를 첨부하고 sign()을 호출합니다. Signature 객체는 서명된 파일을 디스크에 기록하고, 작업 성공 여부와 경고 목록을 포함하는 SignResult를 반환합니다. 이 엔드‑투‑엔드 흐름은 몇 줄의 Java 코드만으로 해시, 인증서 검증 및 타임스탬프 검색을 자동으로 처리합니다.
디지털 서명이 중요한 이유 (그리고 타임스탬프가 필요한 이유)
디지털 서명은 진위(누가 서명했는지)와 무결성(문서가 변경되지 않았음)을 보장합니다. 타임스탬프를 추가하면 특정 시점에 서명이 존재했음을 증명하여, 서명 인증서가 이후에 만료되거나 폐기되더라도 보호됩니다. 이 둘을 함께 사용하면 부인 방지를 제공하며, 이는 법률, 금융 및 규제 워크플로에 필수적입니다.
GroupDocs.Signature for Java 설정
통합 방법
선호하는 빌드 도구를 선택하세요:
Maven 사용자용pom.xml에 의존성을 추가합니다:
The following Maven coordinates pull the latest stable release of GroupDocs.Signature for Java.
<dependency>
<groupId>com.groupdocs</groupId>
<artifactId>groupdocs-signature</artifactId>
<version>23.12</version>
</dependency>
Gradle 사용자용build.gradle에 다음 라인을 추가합니다:
Gradle은 Maven Central에서 라이브러리를 해결합니다.
implementation 'com.groupdocs:groupdocs-signature:23.12'
직접 다운로드(선호하는 경우)
GroupDocs.Signature for Java releases 페이지로 이동하여 JAR 파일을 다운로드합니다. 프로젝트의 클래스패스에 수동으로 추가합니다. 전체 API 참조는 GroupDocs.Signature Documentation을 확인하세요. 최신 빌드는 Latest Version & Releases에서 확인할 수 있습니다.
팁: Maven이나 Gradle은 버전 업그레이드와 전이적 의존성을 자동화하여 새로운 보안 패치가 릴리스될 때 시간을 절약해 줍니다.
라이선스 설정
GroupDocs는 세 가지 라이선스 옵션을 제공합니다:
- 무료 체험 – 워터마크 없이 모든 기능을 평가합니다. Download Trial Version
- 임시 라이선스 – 개발용 30일 전체 접근 키.
- 상업용 라이선스 – 프로덕션 준비 완료, 무제한 사용. Buy License
질문이 있으면, 커뮤니티가 활발히 활동하는 GroupDocs Forum을 이용하세요.
기본 초기화
Signature는 메모리 내 단일 PDF 파일을 나타내는 GroupDocs.Signature의 최상위 객체입니다. 인스턴스를 생성하면 모든 읽기/쓰기 작업이 이를 통해 흐릅니다.
import com.groupdocs.signature.Signature;
String filePath = "YOUR_DOCUMENT_DIRECTORY/sample.pdf";
final Signature signature = new Signature(filePath);
PDF에 디지털 서명을 추가하는 Java 단계별 가이드
프로세스는 순차적입니다: 클래스를 가져오고, 파일 경로를 설정하고, Signature 객체를 생성하고, 선택적 타임스탬프와 함께 DigitalSignature를 구성하고, SignOptions를 정의한 뒤 서명하고 저장합니다.
Step 1: 필요한 클래스 가져오기
다음 import 문을 통해 서명 구성, 위치 지정 및 타임스탬프 기능에 접근할 수 있습니다.
import com.groupdocs.signature.Signature;
import com.groupdocs.signature.domain.enums.HorizontalAlignment;
import com.groupdocs.signature.domain.enums.VerticalAlignment;
import com.groupdocs.signature.domain.signatures.PdfDigitalSignature;
import com.groupdocs.signature.domain.structs.TimeStamp;
import com.groupdocs.signature.options.sign.DigitalSignOptions;
Step 2: 파일 경로 정의
입력 PDF, 인증서(PFX) 및 출력 위치에 대한 경로를 설정합니다. 인증서 파일은 개인 키를 포함하고 있으므로 안전하게 보관하세요.
String filePath = "YOUR_DOCUMENT_DIRECTORY/sample.pdf";
String certificatePath = "YOUR_DOCUMENT_DIRECTORY/certificate.pfx";
String outputFilePath = "YOUR_OUTPUT_DIRECTORY/digitallySignedTimeStamp.pdf";
Step 3: Signature 객체 초기화
Signature는 모든 서명 작업의 진입점입니다. 이를 생성하면 PDF가 메모리로 로드되고 API가 추가 작업을 위해 준비됩니다.
final Signature signature = new Signature(filePath);
Step 4: 서명 속성 및 타임스탬프 구성
DigitalSignature는 PDF에 삽입될 암호화 봉인입니다. 신뢰할 수 있는 기관의 타임스탬프를 첨부할 수도 있습니다.
PdfDigitalSignature pdfDigitalSignature = new PdfDigitalSignature();
pdfDigitalSignature.setContactInfo("Contact Information");
pdfDigitalSignature.setLocation("Location Info");
pdfDigitalSignature.setReason("Signing Reason");
// Configure the TimeStamp with URL, User Id, and Password
TimeStamp timeStamp = new TimeStamp("https://freetsa.org/tsr", "User Id", "Password");
pdfDigitalSignature.setTimeStamp(timeStamp);
- ContactInfo – 예:
john.doe@company.com - Location – 예:
New York Office - Reason – 예:
Contract Approval
데모에서는 무료 타임스탬프 기관인 FreeTSA를 사용합니다. 실제 운영에서는 가용성과 법적 효력을 보장하는 상업용 TSA를 선택하세요.
Step 5: 디지털 서명 옵션 구성
SignOptions는 인증서, 시각적 외관 및 디지털 서명의 배치 설정을 집계합니다.
DigitalSignOptions options = new DigitalSignOptions(certificatePath);
options.setPassword("YourCertificatePassword"); // Certificate password
options.setSignature(pdfDigitalSignature); // Attach the PdfDigitalSignature object
// Specify signature alignment (where it appears on the page)
options.setVerticalAlignment(VerticalAlignment.Bottom);
options.setHorizontalAlignment(HorizontalAlignment.Right);
Step 6: 문서 서명 및 저장
SignResult는 서명 작업 결과를 제공하며, 성공 여부와 경고를 포함합니다.
try {
SignResult signResult = signature.sign(outputFilePath, options);
System.out.println("Document signed successfully!");
System.out.println("Output: " + outputFilePath);
} catch (Exception e) {
throw new RuntimeException("Error during signing process: " + e.getMessage());
}
피해야 할 일반적인 함정
1. 인증서 문제
문제: “Invalid certificate” 오류.
해결: keytool -list -v -keystore your.pfx로 비밀번호를 확인합니다.
keytool -list -v -keystore certificate.pfx -storetype PKCS12
2. 타임스탬프 서비스 타임아웃
문제: TSA에 연결 시 네트워크 타임아웃.
해결: 연결 테스트(curl -I https://freetsa.org/tsr)를 수행하고, 재시도 로직을 추가하거나 대체 TSA를 구성합니다.
new File(outputFilePath).getParentFile().mkdirs();
3. 파일 권한 문제
문제: 저장 중 “Access denied”.
해결: 출력 디렉터리가 존재하고 애플리케이션에 쓰기 권한이 있는지 확인합니다.
keytool -genkeypair -alias mykey -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore certificate.pfx -validity 365
4. 대용량 PDF 메모리 문제
문제: 큰 파일에서 OutOfMemoryError.
해결: JVM 힙을 늘리세요(-Xmx4g) 또는 파일을 배치로 처리합니다.
5. 서명 위치 오류
문제: 서명이 기존 콘텐츠와 겹침.
해결: 먼저 정렬 설정을 테스트하고, 픽셀 단위 정확한 배치를 위해 좌표 기반 옵션을 사용합니다.
인증서 관리 팁
개발용 인증서 획득
테스트용으로 Java의 keytool을 사용해 자체 서명 인증서를 생성합니다.
String certPassword = System.getenv("CERT_PASSWORD");
인증서 모범 사례
- 비밀번호를 절대 하드코딩하지 마세요 – 환경 변수를 사용합니다.
- 인증서를 만료 전에 교체하세요.
- 개인 키를 안전한 하드웨어(HSM)에 저장하세요 – 고보안 앱용.
- 인증서를 보호된 위치에 백업하세요.
- 서명 전에 인증서를 검증하세요 – 만료되거나 폐기된 인증서를 잡아냅니다.
보안 모범 사례
1. 개인 키 보호
프로젝트 디렉터리 외부에 인증서를 저장하고, 환경별 설정을 사용하며, 엔터프라이즈 배포 시 HSM을 고려합니다.
2. 입력 PDF 검증
서명 전에 손상 여부, 기존 서명, 크기 제한 및 콘텐츠 준수 여부를 확인합니다.
3. 감사 로그 구현
타임스탬프, 사용자, 문서 이름 및 상태와 함께 모든 서명 작업을 기록합니다.
try {
SignResult result = signature.sign(outputFilePath, options);
logger.info("Document signed: " + filePath + " by " + signerEmail);
} catch (Exception e) {
logger.error("Signing failed: " + filePath + " - " + e.getMessage());
// Handle appropriately
}
4. 신뢰할 수 있는 타임스탬프 기관 사용
로컬 시스템 시간에 의존하지 말고, 항상 RFC 3161‑준수 TSA에서 타임스탬프를 요청하세요.
5. 오류 처리 구현
예외를 잡되 민감한 세부 정보를 노출하지 않도록 합니다.
try {
signature.sign(outputFilePath, options);
} catch (Exception e) {
// Log detailed error internally
logger.error("Signing error: " + e.getMessage(), e);
// Return generic error to client
throw new ApplicationException("Unable to sign document. Please try again.");
}
실제 사용 사례 및 적용 분야
- 계약 관리 시스템 – 직원들이 NDA 및 계약서를 전자적으로 서명하고, 타임스탬프를 통해 각 계약이 정확히 언제 수락되었는지 증명합니다.
- 재무 문서 처리 – 청구서와 구매 주문을 일괄 서명하여 규제 기관을 위한 변경 불가능한 감사 추적을 제공합니다.
- 교육 자격 검증 – 대학은 위변조 방지 성적표를 발행하고 QR 코드 링크를 통해 즉시 검증할 수 있습니다.
- 소프트웨어 라이선스 관리 – 디지털 서명 및 타임스탬프가 포함된 라이선스 인증서를 생성하여 위조를 방지합니다.
- 규제 준수(FDA 21 CFR Part 11 등) – 의료기기 업체가 SOP 및 검증 보고서를 서명하고, 타임스탬프가 부인 방지 요구 사항을 충족합니다.
성능 고려 사항 및 최적화
메모리 관리
대용량 PDF를 배치로 처리하고, Signature 객체를 즉시 닫으며, 필요 시 힙 크기를 늘립니다.
타임스탬프 네트워크 최적화
HTTP 연결을 풀링하고, 지수 백오프 재시도를 구현하며, 연속 서명을 위해 타임스탬프를 캐시합니다.
배치 처리 모범 사례
// Pseudo‑code: process a list of PDFs in parallel, limiting to 5 concurrent TSA calls
스레드를 과도하게 생성하지 마세요; 5‑10개의 동시 서명이 처리량과 TSA 부하의 균형을 맞춥니다.
디스크 I/O 최적화
임시 파일에 SSD를 사용하고, 읽기/쓰기 사이클을 최소화하며, 각 서명 실행 후 임시 아티팩트를 정리합니다.
문제 해결 가이드
오류: “Invalid certificate password”
해결: keytool -list -keystore your.pfx로 비밀번호를 확인합니다.
ExecutorService executor = Executors.newFixedThreadPool(5);
List<Future<SignResult>> futures = new ArrayList<>();
for (String pdfPath : pdfPaths) {
futures.add(executor.submit(() -> {
try (Signature sig = new Signature(pdfPath)) {
return sig.sign(outputPath, options);
}
}));
}
// Wait for all to complete
for (Future<SignResult> future : futures) {
SignResult result = future.get();
// Process result
}
executor.shutdown();
오류: “Timestamp authority not responding”
해결: TSA URL을 테스트하고, 방화벽 규칙을 확인하며, 대체 TSA 로직을 추가합니다.
keytool -list -v -keystore certificate.pfx -storetype PKCS12
오류: “PDF is already signed”
해결: 먼저 기존 서명을 감지하고, 카운터 서명을 추가하거나 새 사본에 서명합니다.
오류: 저장 시 “Access denied”
해결: 출력 디렉터리가 존재하고, 앱에 쓰기 권한이 있으며, 다른 프로세스가 파일을 잠그고 있지 않은지 확인합니다.
TimeStamp timeStamp;
try {
timeStamp = new TimeStamp("https://freetsa.org/tsr", "", "");
} catch (Exception e) {
// Fallback to alternative TSA
timeStamp = new TimeStamp("https://alternate-tsa.com/tsr", "", "");
}
오류: OutOfMemoryError
해결: JVM 힙을 늘리거나, PDF를 더 작은 배치로 처리하거나, 매우 큰 파일의 경우 스트리밍 API로 전환합니다.
결론 및 다음 단계
이제 Java로 PDF 파일에 서명하는 방법과 신뢰할 수 있는 타임스탬프를 추가하고 일반적인 함정을 피하는 방법을 알게 되었습니다. 다음 단계로는:
- 다중 당사자 계약을 위해 여러 서명 필드를 추가합니다.
- GroupDocs.Signature를 사용해 프로그래밍 방식으로 서명을 검증합니다.
- 서명의 시각적 외관을 맞춤화합니다(이미지, 텍스트, 위치 지정).
- 큐와 모니터링을 갖춘 견고한 배치 서명 서비스를 구축합니다.
자주 묻는 질문
Q: 디지털 서명과 전자 서명의 차이점은 무엇인가요?
A: 디지털 서명은 암호화 알고리즘을 사용해 신원을 검증하고 변조를 감지하는 반면, 전자 서명은 타이핑한 이름처럼 간단할 수 있습니다.
Q: PDF에 서명하려면 인터넷 연결이 필요합니까?
A: 타임스탬프 서비스에만 필요하고, 암호화 서명 자체는 로컬에서 실행됩니다.
Q: 서명된 PDF를 나중에 편집할 수 있나요?
A: 수정이 이루어지면 서명이 무효화되며, PDF 뷰어는 문서가 변경되었다는 경고를 표시합니다.
Q: 서명된 PDF를 어떻게 검증하나요?
A: 대부분의 PDF 리더가 자동으로 검증합니다; 프로그래밍 방식으로는 GroupDocs.Signature의 검증 API를 사용해 상태, 서명자 세부 정보 및 타임스탬프 유효성을 확인합니다.
Q: 서명 후 인증서가 만료되면 어떻게 되나요?
A: 삽입된 타임스탬프가 서명이 인증서가 유효한 동안 생성되었음을 증명하여 법적 효력을 유지합니다.
Q: 이를 클라우드 스토리지(S3, Azure Blob 등)와 함께 사용할 수 있나요?
A: 예—PDF를 임시 위치에 다운로드하고 서명한 뒤, 서명된 버전을 클라우드에 다시 업로드합니다.
Q: 파일 크기 제한이 있나요?
A: 라이브러리는 전체 파일을 메모리에 로드하지 않고도 최대 500 MB PDF를 처리합니다; 더 큰 파일은 스트리밍이 필요할 수 있습니다.
Q: 상업용으로 GroupDocs.Signature를 사용하려면 비용이 얼마나 되나요?
A: 배포 유형에 따라 가격이 다르며, 최신 요금은 GroupDocs 영업팀에 문의하세요. 평가용 무료 체험 및 임시 라이선스도 제공됩니다.
Q: Linux 서버에서도 작동하나요?
A: 물론입니다. GroupDocs.Signature for Java는 플랫폼에 독립적이며 JRE가 설치된 모든 OS에서 실행됩니다.
마지막 업데이트: 2026-09-05
테스트 환경: GroupDocs.Signature 23.9 for Java
작성자: GroupDocs
관련 튜토리얼
- Java에서 디지털 인증서 검증 방법 - 코드 예제와 함께하는 완전 가이드
- GroupDocs.Signature를 사용한 Java에서 PDF 프로그래밍 방식 서명 방법
- GroupDocs와 함께 Java에서 PDF에 이미지 서명 추가
File outputFile = new File(outputFilePath);
outputFile.getParentFile().mkdirs(); // Create directories if needed
if (!outputFile.canWrite() && outputFile.exists()) {
throw new IOException("Cannot write to " + outputFilePath);
}