За последние пару лет — и с тех пор, как я начал этот трудный путь в программирование; а именно разработка с полным стеком — я хотел проверить свои знания и свое «мастерство» в программировании. Я хотел сделать что-то своими руками, что было бы полезно для сообщества и потенциально могло бы решить некоторые проблемы, с которыми сталкиваются пользователи. Я не просто хотел сделать еще один список дел или приложение-калькулятор. На пути к своему первому потенциальному собеседованию с полным стеком мне нужно было заполнить свое портфолио некоторыми проектами, о которых стоит поговорить или рассказать потенциальному работодателю.

Много лет назад я хотел быть аналитиком по безопасности, а не инженером-программистом; или хотя бы пытаться работать в какой-либо сфере информационной безопасности. На самом деле я поступил в университет и получил степень в области кибербезопасности и обеспечения информации, попутно получив пару сертификатов отраслевого стандарта, связанных с информационной безопасностью. Теперь, когда я получил высшее образование, кажется, что я пошел в совершенно другом направлении, чем то, в котором я хотел быть, когда получал степень, что само по себе неплохо, но я просто хотел бы использовать свои возможности. степень за что-то хорошее. Когда я обдумывал проект, в котором использовалась бы витрина портфолио, я подумал, что было бы естественно посвятить один из моих проектов моему пути образования. Не похоже, что я собираюсь использовать его где-то еще! (Пока…) Итак, вот к чему это нас приводит: что такое Squrl?

Зачем Интернету нужен еще одинсокращатель URL-адресов?

Squrl означает Безопасный, быстрый URL-адрес, сервис сокращения URL-адресов и E2EE, созданный для решения проблемы конфиденциальности в существующих сервисах, которые предлагают сокращение URL-адресов: bit.ly, shorturl, tinyurl и т. д. , среди других крупных игроков в игре. Каждый из этих сервисов предлагает пару решений для сокращения URL-адресов, которые, на мой взгляд, могут быть чрезмерными с точки зрения проблемы, которую они пытаются решить: все они регистрируют большие объемы данных и информации для создания аналитики и количество кликов для ваших ссылок как уловка для сбора маркетинговых материалов для взаимодействия с определенным бизнесом. Каждая из этих ссылок или перенаправлений содержит большие объемы личной информации, которая раскрывает все виды личных данных для других, которые готовы приложить усилия для их поиска.

В 2016 году два исследователя безопасности обнаружили, что просто путем открытого сканирования и перебора доступных URL-токенов, используемых OneDrive и Google Диском, они могут наткнуться на живые и открыто редактируемые документы, содержащие личную информацию. Совершенно очевидно, что просто потому, что URL-адрес выглядит так, как будто его трудно найти в Интернете среди моря проиндексированных страниц со случайным URL-адресом, это не всегда так. Некоторые люди доверяют таким публичным ссылкам самые личные документы своей жизни. Крис Дейл написал отличную статью для Института SANS о том, какую личную и опасную информацию обычно могут включать общедоступные сокращенные URL-адреса.

Итак, что это значит? Люди слепо доверяют маркетинговым компаниям защищать себя и данные, которыми открыто делятся. Squrl стремится облегчить некоторую боль в отношении этой проблемы.

Технические сведения: процесс разработки безопасного средства сокращения URL

Создание сервисов сокращения URL-адресов не является относительно сложным проектом, если вы хотите попробовать. Я на самом деле призываю любого новичка научиться делать такие вещи, чтобы попытаться это сделать. (Я так многому научился!). Обычно мне требовалось около 3-4 недель программирования, чтобы собрать все это вместе с логикой шифрования, серверной частью и службами базы данных.

На самом деле ваш стандартный отраслевой сокращатель URL состоит из 3 основных частей:

  1. Пользователь дает ссылку на ваш сервер. Вы можете решить, хотите ли вы дезинфицировать эту ссылку. Я настоятельно в некоторой степени рекомендую это сделать.
  2. Ссылка связана со случайным токеном, используемым для сокращенного URL-адреса, что-то вроде: exam.pl/5x3sQ. Эта информация хранится в базе данных.
  3. Когда внешний пользователь делает GET-запрос к вашему веб-серверу, используя указанный выше токен URL-адреса, сервер просто перенаправляет его на сохраненный URL-адрес в своей базе данных, в большинстве случаев используя простую переадресацию 302.

Уже из этого небольшого списка вы можете увидеть, где начинают подниматься вопросы конфиденциальности. При создании ссылки, если служба сокращения не предлагает защиты, все целевые ссылки потенциально могут быть сохранены в виде простого текста в базе данных. Во время создания ссылки информация о том, кто создал ссылку, когда, где и, возможно, почему, может быть определена с помощью этого простого действия. Теперь, когда ссылка создана и сохранена, если злоумышленник извне получит доступ к базе данных, из нее можно будет получить еще больше информации: как только пользователь попадет на страницу перенаправления, аналитика маркетинга / продаж, количество кликов, местоположение пользователя, IP-адрес. адреса, все, что можно собрать, будет собрано. Затем, когда пользователь прощается в последний раз, если сервер выполняет собственные 30-кратные перенаправления, то хост уже знает, где находится пункт назначения, и, скорее всего, зарегистрирует, кто получил доступ к этим ссылкам, как успешно перенаправленные агенты. Весь этот процесс и точно куда вы пытаетесь перейти, будут известны серверу. Что еще хуже, компания затем продает эту необработанную аналитическую информацию пользователям своего сервиса по цене подписки, чтобы создать больше таких ссылок…

Подумайте о том, как это повлияет на тех, кто пытается поделиться важной контактной информацией в Интернете или в социальных сетях, с ограничениями на количество символов в сообщениях и только с несколькими избранными децентрализованными людьми, которым необходимо знать? Что, если вы хотите гарантировать, что те, кто посещает ваш сайт, не станут добычей третьих лиц при использовании службы сокращения? Что, если вы создатель, который хотел бы распространять свой контент, будучи «скрытым на виду», используя некоторую защиту конфиденциальности?

Это основная основа, на которой построен этот проект, — стремление создать что-то, что обеспечивает конфиденциальность, защиту и анонимность. Давайте начнем с погружения в то, как выглядит подобный проект. Squrl на самом деле является программным обеспечением с открытым исходным кодом, которое вы можете использовать для своих нужд! Или, может быть, просто посмотреть, как что-то подобное работает. Просто имейте в виду, что лицензия GPL-3.

Squrl был создан с использованием стека MERN, чтобы помочь мне разобраться с React и Mongo. Это был мой первый «большой» CRUD-проект, который я продвигаю, и я подумал, что это отличный способ начать. С Mongo было очень приятно работать, и я определенно предпочитаю эту схему NoSQL на основе документов, а не вашу стандартную базу данных SQL. Я также воспринял это как прекрасную возможность изучить Tailwind, чтобы увидеть, на что это похоже, и мне это действительно очень нравится! Я думаю, что в конечном итоге я буду использовать его в будущих проектах.

Принимая во внимание то, что мы знаем выше о том, как работает обычный сокращатель URL-адресов, давайте посмотрим, как общий дизайн этого проекта подходит к этому.

Получение URL-адреса

Когда Squrl получает ссылку, происходит несколько вещей, обеспечивающих надлежащее сквозное шифрование. Для начала веб-страница по умолчанию использует HTTPS. Первое, что следует отметить, это то, что при каждом обновлении страницы приложение отправляет запрос на выборку к конечной точке API на сервере, чтобы сгенерировать ключ сеанса для заполнения поля HTML на внешнем интерфейсе строкой, управляемой энтропией. , который является просто причудливым способом создания более безопасного, действительно случайного токена, который мы можем использовать в качестве предложения серверу для хранения в нашей базе данных. Эта часть выполняется на стороне сервера, чтобы убедиться, что пользователи не могут редактировать или изменять ключ сеанса — и, в конечном итоге, пароль, необходимый для доступа к общедоступному маршруту — при попытке зашифровать данные. Затем сервер может проверить и предоставить ключ пользователю. К счастью, этот ключ является просто паролем, используемым для доступа к зашифрованным данным, и не отображает содержимое. С этим случайно сгенерированным sessionKey мы можем передать его в нашу функцию parseUrl(sessionKey), чтобы начать шифрование наших данных!

Мы удостоверяемся, что ссылка, предоставленная пользователем, действительно является действительным Web URI, и убедитесь, что длина URI не превышает 2083 символов. Это максимальный предел длины URL для Internet Explorer и Edge. Несмотря на то, что это максимальная длина для URL-адресов, вопреки RFC 2616, возможно, захочется сказать, что это также ограничение длины для URI Squrl. Это ограничение также в основном предназначено для снижения вероятности превышения размера документа MongoDB BSON в 16 МБ на файл. Я сохранил возможность анализировать URI вместо стандартных URL-адресов, чтобы их можно было использовать для ссылок приложений или вызовов URI, связанных с сервером. В конце концов, нет необходимости проверять, был ли изменен URI перед отправкой или нет. Эта обработанная строка в любом случае будет закодирована в кодировке UTF-8 во время шифрования, и я оставлю на усмотрение пользователя, действительно ли принудительно шифровать часть бесполезных данных. Возможно, в будущем я соединю это приложение с одним из моих собственных серверных проектов. 😉 Все URL-адреса являются URI, но не все URI являются URL-адресами. Начиная с этой части, я буду упрощать и называть все URI просто ссылками. После того, как эти проверки выполнены, parseUrl(sessionKey) затем отправляет запрос на выборку к конечной точке /generate-url, передавая ключ сеанса и ссылку в виде обычного текста, чтобы попытаться выполнить шаг шифрования.

Шифрование данных

Теперь мы подошли к сути этой статьи: шифрование ссылки в базе данных, определение этого проекта. В качестве краткого обзора я сделал блок-схему, подробно описывающую, как это работает, когда проверенный запрос достигает конечной точки /generate-url:

Вот следующие шаги, которые происходят при шифровании полученной информации о ссылке (dbinteract.js):

  1. Используя энтропию, CSPRNG создает рандомизированный 32-битный ключ сеанса и представляется как секретный пароль для предстоящей функции вывода ключа. (и как способ доступа к защищенному содержимому ссылки Squrl!)
  2. Генерируются два рандомизированных массива 128-битных слов, содержащие как соль, так и IV для начальных общих шагов шифрования как для функций шифрования, так и для функций дешифрования. Примечание. Они должны оставаться одинаковыми на обоих концах для обеспечения точного обмена информацией.
  3. Затем соль, IV и сеансовый ключ передаются в алгоритм хеширования PBKDF2 для создания хешированного ключа.
  4. Затем хешированный ключ и текстовая ссылка передаются в алгоритм шифрования AES-256-CBC для создания окончательной зашифрованной ссылки, которая будет храниться в базе данных на стороне клиента. *
  5. Наряду с зашифрованной ссылкой создается еще один 32-битный сгенерированный ключ CSPRNG, который сравнивается с текущим URL-маршрутом, который указывает на местоположение записи в базе данных после проверки ее отсутствия, чтобы загрузить окончательный документ в базу данных. Это общедоступный токен URL для перенаправления.

* = Хранящиеся зашифрованные данные также содержат соль и IV, встроенные в них для легкого доступа к функции расшифровки.

После того, как сервер проверит все и успешно вставит документ в базу данных, мы получим строку, указывающую на зашифрованную ссылку, которая должна выглядеть примерно так: https://squrl.dev/Te-K26, которую затем можно сократить до squrl.dev/Te-K26, если записи DNS вашей серверной части поддерживают настройку голый домен — что имеет смысл, учитывая, что это служба сокращения URL-адресов.

Записи базы данных

Теперь, когда ссылка хранится в базе данных, давайте посмотрим, какие данные действительно хранятся на сервере! В конце концов, весь смысл этого проекта в том, чтобы быть прозрачным, верно?

Когда ссылка зашифрована и сохранена, цель состоит в том, чтобы доставить пользователя туда, куда ему нужно, сохраняя при этом абсолютно НАИМЕНЬШИЙ объем данных об этом пользователе. В конце концов, анонимность также является основным арендатором этого проекта.

На самом деле, есть только две вещи, которые крайне необходимы для работы Squrl: urlRoute и encryptedUrl. Эти двое составляют основу всего проекта. Я также считаю, что мы довольно подробно рассмотрели их в приведенных выше текстах, поэтому я не буду их здесь описывать, но без них мы не смогли бы маршрутизироваться! Так что еще? Ну, мы также хотели бы отслеживать некоторую другую информацию, когда публикуем что-то в Интернете.

  • userAgent: общая строка, встречающаяся в браузерах, которая предоставляет неидентифицируемую информацию о браузере, обращающемся к службе. К счастью, эта информация не уникальна и не может быть использована для поиска кого-либо только по ней. На самом деле, эта струна может быть любой, какой душе угодно, если вы того пожелаете!
  • _id : Само собой разумеется, действует как UUID записи в базе данных.
  • createdAt и updatedAt : также не требующие пояснений, но стандартные практические поля базы данных, хранящиеся в формате UTC.
  • __v : поле, сгенерированное Mongoose, относящееся к ключу версии документа. По сути, статус внутренней редакции документа.

Это вся информация, которая известна серверу. Остальное - загадка! (намеренно, конечно...)

Зашифрованные ссылки! Ура! Что теперь?…

Большой! Итак, вы заходите в свой веб-браузер, вводите только что сгенерированную новую причудливую ссылку Squrl, squrl.dev/Te-K26, нажимаете ввод, и кажется, что вас приветствует экран с запросом пароля вместо предпочтительного места назначения. Минуточку… Я думал, это меня перенаправит? Ведь не об этом ли этот проект?! …

Да, но это просто особенность шифрования предоставленной ссылки. На самом деле Squrl требует два параметра в каждом запросе для успешной «аутентификации» на сервере. Один из них — это сокращенный URL-адрес, который становится общедоступной ссылкой, а другой — секретный «пароль» — сеансовый ключ, необходимый для успешного получения доступа к ссылке и перенаправления в нужное место. Используя приведенный выше пример, мы можем ввести: squrl.dev/Te-K26+3dvQ_2, указав как общедоступный маршрут, так и сеансовый ключ со знаком плюс в середине (+) — при условии, что они совместимы — это станет действительным «золотым ключом». ', которая приведет к успешному перенаправлению! Если внешний пользователь попытается перейти на общедоступный маршрут без сеансового ключа, указанного в ссылке, он будет перенаправлен на страницу с просьбой ввести правильный пароль для получения доступа.

Большой! Ссылка зашифрована! Теперь нам нужно убедиться, что люди могут попасть туда, где им нужно, после получения зашифрованной ссылки, но сначала давайте посмотрим на экран пароля, который запрашивал, если пользователи не предоставили действительный ключ сеанса.

Экран пароля

При попытке получить доступ к ссылке, к которой у пользователей нет доступа, или просто не предоставляя ключ сеанса с общедоступным URL-маршрутом, например. при переходе к squrl.dev/Te-K26 пользователи будут перенаправлены к файлу password.ejs, где им будет предоставлена ​​возможность указать известную информацию о «пароле», которая будет правильно перенаправлена ​​в соответствующее безопасное место.

Это в первую очередь позволяет пользователям незаметно делиться ссылкой с другими на открытом форуме, публично, а также в безопасности. Тем не менее, генератор ссылок будет нести ответственность за то, чтобы ключ сеанса не был предоставлен публике! (Конечно, если они того пожелают. Некоторые ссылки предназначены для общего доступа!)

Расшифровка данных и перенаправление

Процесс расшифровки в конечном счете (как и следовало ожидать) является процессом шифрования, но в обратном порядке. Перед получением зашифрованного URL-адреса с сервера выполняются различные проверки, например проверка правильности маршрута URL-адреса и сеансового ключа, которые были предоставлены при выполнении запроса к базе данных. Как только они будут подтверждены, сервер отправит файл redirector.ejs тем, кто точно предоставит правильный маршрут связи иключ сеанса. Этот файл представляет собой расшифровщик на стороне клиента, обеспечивающий окончательное перенаправление содержимого.

Вы могли заметить, что файл redirector на самом деле заканчивается на .ejs! Разве это расширение не обычно используется при рендеринге на стороне сервера? Что означает, что на самом деле это не100% сквозное шифрование на стороне клиента!?…

Нет, на самом деле EJS — это просто язык шаблонов, созданный для возможности встроенного динамического JavaScript в HTML. Способ передачи (внедрения) переменных шаблона и информации в HTML без необходимости жесткого кодирования того, что и куда следует. Это позволяет нам указать серверу обслуживатьдинамический HTML, который будет включать зашифрованный URL-адрес и необходимый сеансовый ключ. Это нерендеринг на стороне сервера, он просто помещается в шаблон и предоставляется непосредственно пользователю без компиляции на сервере. Сервер по-прежнему не знает, куда направляется пользователь, он просто дает ему ключи и карту и сообщает пользователю, куда идти и как достичь цели.

Взглянув на файл redirector.ejs, мы можем увидеть, где шаблон применяется в функции расшифровки:

<%=url%> и <%=key%> — это точки внедрения EJS, которые просто загружают зашифрованный URL-адрес и ключ сеанса, необходимые для функции расшифровки, и передаются клиенту. Давайте посмотрим, как работает функция расшифровки:

  1. Вставьте зашифрованный URL-адрес и ключ сеанса в функцию расшифровки.
  2. Функция PBKDF2 выполняется снова с использованием того же сеансового ключа, IV и соли (собранной из зашифрованного URL-адреса источника, помните, как соль и IV внедряются в данные) для создания точной копии исходного хешированного ключа, используемого в исходная функция шифрования.
  3. Затем фактическиезашифрованные данные URL-адреса передаются в функцию расшифровки на стороне клиента вместе с хешированным ключом для создания полностью расшифрованного вывода URL-адреса с использованием запрошенных зашифрованных данных, прошедших проверку подлинности (открытый маршрут и ключ сеанса). из базы данных.
  4. Клиент локального браузера выполняет перенаправление window.location.assign вместо вашего классического перенаправления 30X с сервера.

Вы также можете увидеть, что <%=nonce%> применяется в паре мест, это используется, чтобы избежать использования директивы unsafe-inline при управлении вашей Политикой безопасности контента. По сути, это позволяет только CSP браузера запускать код, который содержит только одноразовый номер и ничего больше, чтобы предотвратить атаки повторного воспроизведения.

Подведение итогов

Вот и все! Это действительно все, что нужно для создания зашифрованного сервиса сокращения URL-адресов. Пользователи могут продолжать шифровать все виды данных URI/URL с помощью этой службы, и база данных никогда не узнает, что куда идет, и особенно кто куда идет.

Это приложение было установлено и настроено в дроплете Digital Ocean с использованием HTTPS-сервера Express и SSL-сертификата Let’s Encrypt. В настоящее время я сам управляю серверной частью; запуск патчей и обновлений. Дайте мне знать в комментариях, если вы хотите увидеть еще один пост о настройке чего-то подобного для всех моих бэкэнд-людей, использующих Express.

Если у вас есть какие-либо вопросы или проблемы, пожалуйста, не стесняйтесь открывать проблему в репозитории. Отправка PR также приветствуется, если вы хотите внести свой вклад или исправить какие-либо проблемы. Я надеюсь, что скоро смогу поделиться здесь новыми разбивками по проектам. Спасибо за прочтение!