golang

Получаем сертификат ЦРУ перебирая архивы

  • пятница, 19 мая 2023 г. в 00:00:19
https://habr.com/ru/articles/736016/

Когда-то давно передо мной стояла задача по поиску файлов на ресурсах, которые могли уже не работать или определённые данные с них были удалены. Тогда для этой цели я использовал веб архивы Common Crawl и самопальный инструмент для автоматизации взаимодействия с ним.

Сейчас мне понадобилось решить схожую задачу, но Common Crawl упал и пока не встаёт... Поэтому было принято решение допилить свой инструмент до уровня скоростного велосипеда с использованием Wayback Machine и поделиться небольшим опытом извлечения архивных данных.

Не погружаясь сильно в детали, далее, в общих чертах я опишу что используют сервисы для архивации, как мы можем этим пользоваться через API, а в конце мы сертифицируемся по-ЦРУшному используя инструмент GoGetCrawl.

Общие моменты

Для начала стоит упомянуть про общие моменты сервисов веб архивирования. Архивы хранятся в файлах WARC/ARC формата, затем с помощью CDX сервера мы можем исследовать данные файлы используя различные фильтры. Популярным инструментом, с помощью которого это осуществляется являться pywb.

Например, на скриншоте ниже можно увидеть результат запроса http://<server_addr>/cdx?url=https://twitter.com/internetarchive/ к CDX серверу:

alt
Источник https://support.archive-it.org/hc/en-us/articles/115001790023-Access-Archive-It-s-Wayback-index-with-the-CDX-C-API

Как видим в результате будут получены данные содержащие оригинальный URL (original), статус при его запросе (status code) на момент сбора данных (timestamp), тип файла (mimetype) и другие интересные параметры. Более детальное описание CDX сервера и используемых при запросах параметрах можно найти тут.

Помимо сервисов Wayback Machine и Common Crawl, которые мы рассмотрим далее существуют множество других. Но их архивы менее обширны и скорее носят локальный характер по стране или тематике. Некоторые из них можно посмотреть тут.

Извлекаем файлы из архивов

Думаю многие пользовались web-архивами через удобные интерфейсы. Сейчас я покажу как это сделать неудобно используя API на примере 2 популярных сервисов. К примеру мы хотим получить все JPEG файлы на cia.gov и его поддоменах, а затем скачать интересующий нас файл.

Wayback Machine

Работаем ручками с Wayback machine

Для осуществления нашей задачи на данном ресурсе мы используем следующий запрос:

https://web.archive.org/cdx/search/cdx?url=*.cia.gov/*&output=json&limit=10&filter=mimetype:image/jpeg&collapse=urlkey

Где:

  • /cdx/search/cdx - endpoint CDX сервера,

  • url=*.cia.gov/* - исследуемый URL,

  • filter=mimetype:image/jpeg - фильтрация по MIME типу JPEG файла,

  • output=json - требуем результат в формате JSON,

  • limit=10 - ограничиваемся 10 результатами,

  • collapse=urlkey - получаем уникальные URL (без этого много дубликатов).

В результате мы получаем 10 найденных изображений в архиве. Из интересного, помимо URLов, ответ содержит MIME тип файлов (полезно если не используется фильтрация), и статус код при доступе к объекту на момент составления архива:

[["urlkey","timestamp","original","mimetype","statuscode","digest","length"],
["gov,cia)/++theme++contextual.agencytheme/images/aerial-analysis-btn.jpg", "20150324125120", "https://www.cia.gov/++theme++contextual.agencytheme/images/aerial-analysis-btn.jpg", "image/jpeg", "200", "OJRFXPWOPZQGPRIZZQZOTRSZKAVLQLKZ", "3845"],
["gov,cia)/++theme++contextual.agencytheme/images/aerial_cropped.jpg", "20160804222651", "https://www.cia.gov/++theme++contextual.agencytheme/images/Aerial_Cropped.jpg", "image/jpeg", "200", "3WII7DZKLXM4KSQ5UTEKO5EL7H5VTB35", "196685"],
["gov,cia)/++theme++contextual.agencytheme/images/background-launch.jpg", "20140121032437", "https://www.cia.gov/++theme++contextual.agencytheme/images/background-launch.jpg", "image/jpeg", "200", "3C4G73473VYPOWDNA4VJUV4Q7EC3IXN4", "44501"],
["gov,cia)/++theme++contextual.agencytheme/images/background-video-panel.jpg", "20150629034524", "https://www.cia.gov/++theme++contextual.agencytheme/images/background-video-panel.jpg", "image/jpeg", "200", "CQCUYUN5VTVJVN4LGKUZ3BHWSIXPSCKC", "71813"],
["gov,cia)/++theme++contextual.agencytheme/images/bannerheads/an-1.jpg", "20130801151047", "https://www.cia.gov/++theme++contextual.agencytheme/images/bannerheads/an-1.jpg", "image/jpeg", "200", "GPSEAEE23C53TRGHLMBXHWQYNB3EGBCZ", "14858"],
["gov,cia)/++theme++contextual.agencytheme/images/bannerheads/an-2.jpg", "20130801150245", "https://www.cia.gov/++theme++contextual.agencytheme/images/bannerheads/an-2.jpg", "image/jpeg", "200", "L6P2MNAAMZUMHUEHJFGXWEUQCHHMK2HP", "15136"],
["gov,cia)/++theme++contextual.agencytheme/images/bannerheads/an-3.jpg", "20130801151656", "https://www.cia.gov/++theme++contextual.agencytheme/images/bannerheads/an-3.jpg", "image/jpeg", "200", "ODNXI3HZETXVVSEJ5I2KTI7KXKNT5WSV", "19717"],
["gov,cia)/++theme++contextual.agencytheme/images/bannerheads/an-4.jpg", "20130801150219", "https://www.cia.gov/++theme++contextual.agencytheme/images/bannerheads/an-4.jpg", "image/jpeg", "200", "X7N2EIYUDAYWMX7464LNTHBVMTEMZUVN", "20757"],
["gov,cia)/++theme++contextual.agencytheme/images/bannerheads/banner-benefits-background.jpg", "20150510022313", "https://www.cia.gov/++theme++contextual.agencytheme/images/bannerheads/banner-benefits-background.jpg", "image/jpeg", "200", "VZJE5XSAQWBD6QF6742BH2N3HOTSCZ4A", "12534"],
["gov,cia)/++theme++contextual.agencytheme/images/bannerheads/chi-diversity.jpg", "20130801150532", "https://www.cia.gov/++theme++contextual.agencytheme/images/bannerheads/CHI-diversity.jpg", "image/jpeg", "200", "WJQOQPYJTPL2Y2KZBVJ44MVDMI7TZ7VL", "6458"]]

Далее, чтобы получить доступ к архивированному файлу, мы берем один из результатов выше и используем следующий запрос:

https://web.archive.org/web/20150324125120id_/https://www.cia.gov/++theme++contextual.agencytheme/images/aerial-analysis-btn.jpg

Где:

  • /web - endpoint сервера с файлами,

  • 20230502061729id_ - timestamp полученный в предыдущем запросе + id_,

  • https://company.habr.com/images/lanit.jpg - url файла из предыдущего запроса.

Common Crawl

Работаем ручками с Common Crawl

В случае с данным сервисом задача немного отяжеляется тем, что он перегружен, и сейчас пользоваться CDX сервером Common Crawl крайне затруднительно. Тем не менее я опишу как это делается.

Для начала нам необходимо выбрать версию архива (Common Crawl обновляет архивы раз в месяц или два). К примеру мы выбрали версию за Март\Апрель 2023, в этом случае аналогичный запрос будет выглядеть следующим образом:

https://index.commoncrawl.org/CC-MAIN-2023-14-index?url=*.cia.gov/*&output=json&limit=10&filter=mimetype:image/jpeg&collapse=urlkey

Как и ожидалось, сервера Common Crawl на момент написания статьи всё ещё перегружены и 504 Gateway Time-out-ают меня 😥. Поэтому далее я покажу пример экстракции файла с ответом на другой запрос, который у меня есть под рукой:

{"urlkey": "com,tutorialspoint)/accounting_basics/accounting_basics_tutorial.pdf", "timestamp": "20230320100841", "url": "http://www.tutorialspoint.com/accounting_basics/accounting_basics_tutorial.pdf", "mime": "application/pdf", "mime-detected": "application/pdf", "status": "200", "digest": "2JQ2AQ3HQZIMXHB5CJGSADUGOHYBIRJJ", "length": "787172", "offset": "102849414", "filename": "crawl-data/CC-MAIN-2023-14/segments/1679296943471.24/warc/CC-MAIN-20230320083513-20230320113513-00267.warc.gz"}
{"urlkey": "com,tutorialspoint)/add_and_subtract_whole_numbers/pdf/subtracting_of_two_2digit_numbers_with_borrowing_worksheet10_1.pdf", "timestamp": "20230326185123", "url": "https://www.tutorialspoint.com/add_and_subtract_whole_numbers/pdf/subtracting_of_two_2digit_numbers_with_borrowing_worksheet10_1.pdf", "mime": "application/pdf", "mime-detected": "application/pdf", "status": "200", "digest": "T4OQARBGDQ2Z3ZMJ57MWZTUIBCFR65QG", "length": "120114", "offset": "1156945883", "filename": "crawl-data/CC-MAIN-2023-14/segments/1679296946445.46/warc/CC-MAIN-20230326173112-20230326203112-00412.warc.gz"}
{"urlkey": "com,tutorialspoint)/add_and_subtract_whole_numbers/pdf/subtracting_of_two_2digit_numbers_with_borrowing_worksheet10_2.pdf", "timestamp": "20230322123716", "url": "https://www.tutorialspoint.com/add_and_subtract_whole_numbers/pdf/subtracting_of_two_2digit_numbers_with_borrowing_worksheet10_2.pdf", "mime": "application/pdf", "mime-detected": "application/pdf", "status": "200", "digest": "EJJMOG5QPWIV7YXADIFOPML45UTJKYWW", "length": "118702", "offset": "1159004265", "filename": "crawl-data/CC-MAIN-2023-14/segments/1679296943809.76/warc/CC-MAIN-20230322114226-20230322144226-00733.warc.gz"}
{"urlkey": "com,tutorialspoint)/add_and_subtract_whole_numbers/pdf/subtracting_of_two_2digit_numbers_with_borrowing_worksheet10_3.pdf", "timestamp": "20230324124641", "url": "https://www.tutorialspoint.com/add_and_subtract_whole_numbers/pdf/subtracting_of_two_2digit_numbers_with_borrowing_worksheet10_3.pdf", "mime": "application/pdf", "mime-detected": "application/pdf", "status": "200", "digest": "AOTDOZIAULAYGY3AOMD7662BJBEPYKWJ", "length": "210009", "offset": "1172608792", "filename": "crawl-data/CC-MAIN-2023-14/segments/1679296945282.33/warc/CC-MAIN-20230324113500-20230324143500-00254.warc.gz"}
{"urlkey": "com,tutorialspoint)/adding_and_subtracting_decimals/pdf/addition_with_money_worksheet8_1.pdf", "timestamp": "20230330141211", "url": "https://www.tutorialspoint.com/adding_and_subtracting_decimals/pdf/addition_with_money_worksheet8_1.pdf", "mime": "application/pdf", "mime-detected": "application/pdf", "status": "200", "digest": "MOODQKFMHRVSZK4UOZO3E6H2MGHTK2VW", "length": "226484", "offset": "1136155166", "filename": "crawl-data/CC-MAIN-2023-14/segments/1679296949331.26/warc/CC-MAIN-20230330132508-20230330162508-00514.warc.gz"}
{"urlkey": "com,tutorialspoint)/adding_and_subtracting_decimals/pdf/addition_with_money_worksheet8_2.pdf", "timestamp": "20230330112743", "url": "https://www.tutorialspoint.com/adding_and_subtracting_decimals/pdf/addition_with_money_worksheet8_2.pdf", "mime": "application/pdf", "mime-detected": "application/pdf", "status": "200", "digest": "ZYCDOJ2JTPPWFTCNYEIXCWKEJQXTA7UD", "length": "226957", "offset": "1167440233", "filename": "crawl-data/CC-MAIN-2023-14/segments/1679296949181.44/warc/CC-MAIN-20230330101355-20230330131355-00035.warc.gz"}

Если приглядеться, то можно заметить что CDX сервер CommonCrawl возвращает нам немного другой JSON, с отличными параметрами от тех что мы видели у Wayback Machine

Теперь, для того чтобы скачать файл мы используем filename выбранного объекта на хранилище (data.commoncrawl.org):

https://data.commoncrawl.org/crawl-data/CC-MAIN-2023-14/segments/1679296949181.44/warc/CC-MAIN-20230330101355-20230330131355-00035.warc.gz

Однако перейдя по данной ссылке вместо нужного нам объекта будет скачан громоздкий скомпрессированный архив. Для получения доступа к необходимому нам файлу мы добавляем следующий заголовок к запросу Range: bytes=1170209543-1170219812. С помощью данного заголовка мы указываем начало и конец смещения файла в архиве. Начало смещения указано в параметре offset объекта, а для вычисления конца добавляем к нему length.

В curl итоговый запрос будет выглядеть следующим образом:

curl -H "Range:bytes=1167440233-1167667190"  "https://data.commoncrawl.org/crawl-data/CC-MAIN-2023-14/segments/1679296949181.44/warc/CC-MAIN-20230330101355-20230330131355-00035.warc.gz" --output test.warc.gz

В результате мы получим сжатый gzip WARC файл, декомпрессировав который мы увидим следующее содержимое:

    WARC/1.0
    WARC-Type: response
    WARC-Date: 2023-03-30T11:27:43Z
    WARC-Record-ID: <urn:uuid:23aaef68-3bb3-4849-a7b8-f81d3b6b603c>
    Content-Length: 276765
    Content-Type: application/http; msgtype=response
    WARC-Warcinfo-ID: <urn:uuid:09066de6-1a53-44c9-80ef-921880273b06>
    WARC-Concurrent-To: <urn:uuid:916a7a96-01a0-4826-acdc-77a44863736f>
    WARC-IP-Address: 192.229.210.176
    WARC-Target-URI: https://www.tutorialspoint.com/adding_and_subtracting_decimals/pdf/addition_with_money_worksheet8_2.pdf
    WARC-Payload-Digest: sha1:ZYCDOJ2JTPPWFTCNYEIXCWKEJQXTA7UD
    WARC-Block-Digest: sha1:FDUUFO3APTHN55CYNDVRD3CNPYA5NOVT
    WARC-Identified-Payload-Type: application/pdf

    HTTP/1.1 200 OK
    Accept-Ranges: bytes
    Access-Control-Allow-Origin: *
    Access-Control-Allow-Origin: *;
    Cache-Control: max-age=2592000
    Content-Type: application/pdf
    Date: Thu, 30 Mar 2023 11:27:43 GMT
    Etag: "4373e-5c8329dce0d40"
    Expires: Sat, 29 Apr 2023 11:27:43 GMT
    Last-Modified: Wed, 28 Jul 2021 17:50:05 GMT
    Server: Apache/2.4.52 (Ubuntu)
    Vary: User-Agent
    X-Frame-Options: SAMEORIGIN
    X-Version: OCT-10 V1
    X-XSS-Protection: 1; mode=block
    Content-Length: 276286

    %PDF-1.5
    %µµµµ
    <-остаток файла...->

Убрав WARC заголовки и сохранив файл, остаётся только наслаждаться скачанным нами содержимым...

GoGetCrawl и сертификат ЦРУ

Стоит сказать, что на данный момент уже существует небольшое количество инструментов для взаимодействия с архивами. Но беглым взглядом я не нашел ни одного, который помимо добычи URL, смог бы скачать файл и с лёгкостью интегрироваться в другие Go проекты!
Исходя из этого я обновил своё устаревшее решение, сделав небольшой рефакторинг и добавив Wayback Machine в качестве второго источника архивных данных.

К делу

А теперь мы идём добывать сертификат с помощью GoGetCrawl. Использовать его можно несколькими способами, описанными тут. Не надо ничего компилировать и устанавливать, и поэтому для удобства:

  • Можно скачать последний релиз. И использовать бинарник следующим образом:

gogetcrawl file *.cia.gov/* --dir ./ --ext pdf

Немного подождав мы должны получить заветный файл, если ждать скучно или файла нет можно посмотреть что происходить добавив флаг -v.

  • Либо использовать Docker:

docker run uranusq/gogetcrawl url *.cia.gov/* --ext pdf

В результате этой команды мы должны увидеть URL с PDF файлом. Более подробно про команды и возможные аргументы можно почитать использовав флаг -h.

  • Вариант установки для Go-нщиков:

go install github.com/karust/gogetcrawl@latest

Поздравляю

Мы получили наш заветный сертификат 🫢. Для тех у кого его ещё нет, он выглядит следующим образом:

image alt
Награда за квиз, который мы даже не прошли? 🤔

Так и не до конца поняв: что это и к чему оно там - я сразу поспешил поделиться этой возможностью с вами.

Опен-сорс

Для тех кто пользуется Go и хочет стать архивмагом есть возможность использования GoGetCrawl в своих проектах:

go get github.com/karust/gogetcrawl

Например, минимальная программа, которая покажет нам все страницы example.com и его поддоменов со статусом 200 выглядит следующим образом:

package main

import (
	"fmt"

	"github.com/karust/gogetcrawl/common"
	"github.com/karust/gogetcrawl/wayback"
)

func main() {
	// Конфигурируем запрос на 10 страниц со статусом 200
	config := common.RequestConfig{
		URL:     "*.example.com/*",
		Filters: []string{"statuscode:200"},
		Limit:   10,
	}

	// Устанавливаем таймаут и попытки для запросов
	wb, _ := wayback.New(15, 2)

	// Используем конфиг для взамодействия с CDX сервером
	results, _ := wb.GetPages(config)

	for _, r := range results {
		fmt.Println(r.Urlkey, r.Original, r.MimeType)
	}
}    

На странице проекта есть ещё примеры использования с добычей файлов и CommonCrawl.

PS

Надеюсь никто не был закликбейчен, и все получили наслаждение от обладания новым сертификатом. Возможно существуют иные сервисы с веб-архивами, помимо описанных в статье, которые можно использовать в таком же ключе? Дайте знать в комментариях.