Анализ ссылок в PDF часто требуется, когда нужно быстро проверить документ на наличие внешних ссылок, внутренних переходов или потенциально опасных URI, не открывая файл в графическом редакторе. Это удобно при автоматической обработке больших наборов файлов, аудите безопасности или подготовке метаданных для архива.
Внутри PDF ссылки хранятся как аннотации типа /Link с действием /URI (или /GoTo для внутренних переходов). Чтобы увидеть их, достаточно «заглянуть» в структуру файла, не рендеринг страниц. Ниже описаны проверенные способы сделать это с помощью общедоступных инструментов и библиотек.
- Почему анализ ссылок без открытия файла полезен
- Как PDF хранит ссылки
- Инструменты командной строки
- 1. qpdf
- 2. mutool (из пакета mupdf)
- 3. poppler‑utils (pdftotext, pdfinfo)
- 4. strings + grep
- Использование библиотек на Python
- PyPDF2 (или pypdf)
- pikepdf
- Пошаговый пример: извлечение ссылок с помощью qpdf
- Ограничения и возможные проблемы
- Практические советы по выбору метода
- Типичные ошибки и как их избежать
- Когда стоит обратиться к специалисту
- Практический итог
Почему анализ ссылок без открытия файла полезен
- Экономит время при обработке десятков или сотен документов.
- Позволяет интегрировать проверку в скрипты и CI/CD‑ pipelines.
- Снижает риск случайного выполнения вредоносного кода, если ссылка ведет на исполняемый файл.
- Работает даже с повреждёнными PDF, которые не открываются в обычных просмотрщиках.
Как PDF хранит ссылки
Ссылка в PDF представлена аннотацией (/Annots) на странице. Основные поля:
- /Subtype /Link – тип аннотации.
- /A – словарь действия. Для внешней ссылки содержит /S /URI и /URI со значением адреса.
- /Rect – прямоугольник, где ссылка кликабельна (не обязателен для анализа).
- Убедитесь, что утилита qpdf установлена. В большинстве дистрибутивов Linux она доступна в репозиториях (sudo apt install qpdf или sudo dnf install qpdf). На macOS — brew install qpdf, на Windows — скачайте бинарник с официального сайта.
- Откройте терминал и перейдите в каталог с PDF‑файлом.
- Выполните команду:
- В выводе вы увидите блоки типа:
- Некоторые ссылки хранятся в виде именованных действий (/Named) или JavaScript‑действий, которые не содержат прямого URI. Их обнаружение требует более сложного анализа словаря действия.
- В PDF могут использоваться относительные ссылки или ссылки на встроенные файлы (/EF). Они не будут выглядеть как обычные веб‑адреса.
- Сжатые потоки объектов могут скрывать текстовые метки; однако утилиты вроде qpdf и pikepdf автоматически распаковывают объекты перед выводом.
- Защищённые паролем документы требуют указания пароля при открытии; без него большинство библиотек вернут ошибку.
- Большие файлы с тысячами аннотаций могут замедлять работу простых скриптов; в таких случаях удобно пользоваться потоковой обработкой (например, pikepdf.Pdf.open с итерацией по страницам).
- Для быстрой проверки одного‑двух файлов достаточно strings + grep.
- Если нужно получить точный список с номерами страниц и гарантированно не пропустить аннотации — используйте qpdf или mutool info.
- Когда требуется дальнейшая обработка (фильтрация, экспорт, изменение ссылок) — выбирайте Python‑библиотеку (pikepdf предпочтительнее из‑за лучшей поддержки шифрования и возможности редактирования).
- Для интеграции в серверные скрипты без дополнительных зависимостей подойдёт вызов qpdf через subprocess и парсинг его вывода.
- Пропуск ссылок из-за регистра: некоторые PDF записывают /uri в нижнем регистре. При использовании grep добавляйте флаг -i или ищите оба варианта.
- Ложные срабатывания на текст внутри шрифтов: метод strings может выдать URL, которые являются частью названия шрифта или метаданных. Проверяйте контекст — настоящая ссылка обычно находится рядом с /S /URI.
- Неучёт относительных путей: если документ содержит ссылки вида ../files/doc.pdf, их следует рассматривать как потенциально опасные при открытии в той же директории.
- Игнорирование зашифрованных файлов: многие скрипты молча завершаются с ошибкой. Всегда обрабатывайте исключения и inform пользователя о необходимости ввода пароля.
- Предположение, что все ссылки безопасны: даже если ссылка ведёт на известный домен, она может перенаправлять на вредоносный ресурс через HTTP‑редирект. Для полной оценки требуется отдельная проверка целевого URL.
- использовать изолированную среду (песочницу) для загрузки и открытия PDF;
- проверять не только наличие URI, но и содержимое встроенных файлов, JavaScript и запускаемых действий;
- применять специализированные инструменты форензического анализа (например, peepdf, pdfid или коммерческие решения).
- Установить одну из предложенных утилит (qpdf — самый универсальный вариант).
- Запустить команду извлечения URI и сохранить результат в файл или переменную.
- При необходимости фильтровать список по домену, удалять дубликаты или экспортировать в CSV.
- Если работаете с защищёнными документами — указать пароль при открытии через библиотеку.
- В случае подозрения на вредоносный контент выполнить дополнительную проверку в изолированной среде.
Некоторые документы используют именованные действия (/Named) или ссылки на другие страницы (/GoTo). Для большинства практических задач достаточно искать /URI.
Инструменты командной строки
Ниже перечислены утилиты, которые позволяют вывести аннотации или сырые объекты PDF без запуска графического интерфейса.
1. qpdf
Утилита qpdf умеет преобразовывать PDF в формат, близкий к постскрипту, и выводить объекты в читаемом виде.
Пример извлечения всех URI:
qpdf —show-objects=all файл.pdf | grep -A2 -B2 ‘/URI’
Команда выводит объекты, содержащие строку /URI, вместе с контекстом, что позволяет увидеть сам адрес и окружающие поля.
2. mutool (из пакета mupdf)
mutool draw может отрисовать страницы, но mutool info выводит структуру документа, включая аннотации.
Пример:
mutool info -F файл.pdf | grep -i ‘/uri’
Флаг -F заставляет вывести полный список объектов в формате, удобном для grep.
3. poppler‑utils (pdftotext, pdfinfo)
Некоторые версии pdftotext с флагом -layout могут вывести ссылки в виде обычного текста, если они помечены как обычный текст. Однако надежнее использовать pdfdetach или pdfimages для извлечения встроенных файлов, а для аннотаций — mutool или qpdf.
4. strings + grep
Самый простой, но менее надёжный способ — поиск строк, начинающихся с http:// или https:// в бинарном файле.
strings файл.pdf | grep -E ‘https?://[^ ]+’
Этот метод находит любые URL, включая те, что находятся в потоках содержимого, шрифтах или метаданных, поэтому может дать ложные срабатывания. Его удобно применять для быстрой предварительной проверки.
Использование библиотек на Python
Если нужен более гибкий анализ (фильтрация по домену, проверка валидности URI, экспорт в CSV), удобно воспользоваться Python‑библиотеками, которые работают с объектной моделью PDF.
PyPDF2 (или pypdf)
Библиотека умеет перебирать страницы и аннотации. Пример кода:
import sys
from pypdf import PdfReader
def extract_uri(pdf_path):
reader = PdfReader(pdf_path)
uris = set()
for page_num, page in enumerate(reader.pages, start=1):
annots = page.get(‘/Annots’, [])
for annot in annots:
obj = annot.get_object()
if obj.get(‘/Subtype’) == ‘/Link’:
action = obj.get(‘/A’)
if action and action.get(‘/S’) == ‘/URI’:
uri = action.get(‘/URI’)
if uri:
uris.add((page_num, uri))
return uris
if __name__ == ‘__main__’:
if len(sys.argv) != 2:
print(‘Usage: python extract_links.py file.pdf’)
sys.exit(1)
links = extract_uri(sys.argv[1])
for page, uri in links:
print(f’Страница {page}: {uri}’)
Скрипт выводит номер страницы и найденный URI. Он работает с большинством стандартных PDF, но не поддерживает зашифрованные файлы без указания пароля.
pikepdf
Библиотека на базе QPDF позволяет напрямую читать объекты и удобно фильтровать их по типу.
import sys
import pikepdf
def extract_uri_pikepdf(pdf_path):
with pikepdf.Pdf.open(pdf_path) as pdf:
uris = set()
for page_num, page in enumerate(pdf.pages, start=1):
annots = page.get(‘/Annots’, [])
for annot in annots:
with annot.open() as obj:
if obj.get(‘/Subtype’) == pikepdf.Name(‘/Link’):
action = obj.get(‘/A’)
if action and action.get(‘/S’) == pikepdf.Name(‘/URI’):
uri = action.get(‘/URI’)
if uri:
uris.add((page_num, str(uri)))
return uris
if __name__ == ‘__main__’:
if len(sys.argv) != 2:
print(‘Usage: python extract_links_pikepdf.py file.pdf’)
sys.exit(1)
for page, uri in extract_uri_pikepdf(sys.argv[1]):
print(f’Страница {page}: {uri}’)
pikepdf корректно обрабатывает зашифрованные документы (при предоставлении пароля) и позволяет изменять или удалять найденные ссылки.
Пошаговый пример: извлечение ссылок с помощью qpdf
qpdf —show-objects=all документ.pdf | grep -B1 -A1 ‘/URI’
…
<>
>>
…
Значение в скобках после /URI — искомый адрес. Если нужно получить только чистые URL, можно дополнительно обработать вывод:
qpdf —show-objects=all документ.pdf |
sed -n ‘s/.*\/URI (\([^)]*\)).*/\1/p’ |
sort -u
Ограничения и возможные проблемы
Практические советы по выбору метода
Типичные ошибки и как их избежать
Когда стоит обратиться к специалисту
Если анализ ссылок является частью расследования инцидента безопасности, рекомендуется:
Для обычных задач аудита или метаданных достаточно методов, описанных выше.
Практический итог
Главный принцип: ссылки в PDF находятся в аннотациях типа /Link с действием /URI. Чтобы увидеть их без открытия файла в графическом просмотрщике, достаточно «заглянуть» в внутреннюю структуру документа при помощи утилит, которые умеют выводить объекты (qpdf, mutool) или библиотек, работающих с объектной моделью (pikepdf, PyPDF2). Выбор инструмента зависит от требуемой точности, необходимости дальнейшей обработки и наличия защиты файла.
Конкретные следующие шаги:
После выполнения этих действий вы будете точно знать, какие ссылки содержит PDF‑документ, и сможете принять обоснованное решение о дальнейшей обработке, архивации или блокировке файла.
