Этот пост вдохновлен сообщением в блоге, обсуждением HN и расширением для Chrome. Конечный результат - zwBlocker: расширение, которое помогает обнаруживать символы нулевой ширины.

Все строится вокруг основной идеи: ваше имя (или адрес электронной почты, имя пользователя и т. д.) может быть невидимо скрыто в фрагменте текста, который вы копируете и публикуете где-то еще, идентифицируя вас как человека, который поделился им. .

Как?

Сообщение Тома описывает концепцию очень подробно, но основная идея заключается в использовании символов Юникода с нулевой шириной.

То есть, когда вы вставляете символ нулевой ширины в фрагмент текста, он не будет виден и не повлияет (или может не повлиять) на остальной текст. Однако эти символы нулевой ширины могут быть прочитаны машиной, и, используя серию этих символов нулевой ширины, мы можем закодировать невидимую информацию в любой фрагмент текста - например, при отправке электронного письма - и прочитать его позже, когда текст появляется в социальных сетях.

Что я могу сделать, чтобы этого избежать?

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

Подход лучше: в первую очередь не копируйте скрытые символы!

Примерно через 12 часов после первого обсуждения HN пользователь chpmrc опубликовал расширение для Chrome, чтобы помочь в этом! Это работает довольно просто - если вы подозреваете, что в тексте есть скрытые символы, вы открываете расширение Chrome, нажимаете кнопку и бум! Все символы нулевой ширины заменяются смайликами.

Это здорово, за исключением одного: я бы ни за что не вспомнил об этом! И я не один такой.

Лучшее решение

Было внесено много предложений, в том числе:

Удалите непечатаемые символы и отобразите количество удаленных символов, аналогично тому, как блокировщики рекламы отображают количество заблокированных рекламных объявлений. - kerkeslager

просканируйте буфер обмена на наличие символов нулевой ширины, беззвучно удалите их, а затем заново заполните буфер обмена. - Someone1234

и криво:

читать в Интернете исключительно в ASCII с символами UTF-8, вставленными с использованием их кодовой точки. - Флешман

Лично я думаю, что автоматическое удаление символов может привести к некоторым проблемам, особенно с поддержкой эмодзи, когда символы нулевой ширины могут использоваться для изменения способа отображения определенных эмодзи (изменение тона кожи и т. Д.)

Я также считаю, что манипулирование буфером обмена людей было бы рискованным маневром, особенно если люди хотят копировать символы нулевой ширины в законных целях. Неважно, реализовать было бы сложно.

На мой взгляд, идеальным решением было бы расширение, которое:

1. Тихо предупреждает о скрытых символах, подобно тому, как блокировщики рекламы показывают, сколько рекламы было заблокировано, но не удаляет их.

2. Громко предупреждает вас, когда вы выбрали текст со скрытыми символами. Таким образом, даже если вы забыли установить расширение, вы по-прежнему защищены.

Создание идеального решения

«Хорошо, а что нам делать, если существующие решения не соответствуют нашим потребностям?»
«Мы стараемся усерднее работать, доводим до конца то, что имеем, или сдаемся!»
«Нет! Мы тратим весь воскресный день (и большую часть понедельника) на создание нестандартного решения! »

Функционально нам нужно расширение для:

  • Ознакомьтесь с содержанием посещаемых нами страниц.
  • Редактировать содержимое посещаемых страниц.
  • При необходимости показывать всплывающий интерфейс.

К счастью, все это делает разработанное мной ранее расширение: Squish делает высокие твиты короче. Вы можете прочитать о том, как я создал Squish, в предыдущем сообщении в блоге, а код, стоящий за ним, можно найти на github.

Как…

Это будет очень кратко - оставьте комментарий, если хотите прочитать подробный пост о том, как это делается.

Начиная с кода Squish, я собираюсь удалить все рекламные изображения, затем обновить файл readme.md и манифест, чтобы вызвать наш новый проект: zwBlocker: Найти и уведомить пользователя о нулевом значении. ширина символов Юникода.

manifest.json

Squish работал только на «twitter.com», поэтому мы хотим изменить манифест, чтобы наше новое расширение получало доступ к каждой странице, которую мы посещаем. В Content-scripts измените «match» на:

"matches": ["<all_urls>"],

Чтобы найти на странице символы нулевой ширины, мы воспользуемся сценарием содержимого, который запускается после загрузки страницы: ”run_at”: “document_end”.

Прогулка по DOM в поисках этих надоедливых педерастов

Мы собираемся использовать treeWalker для поиска файлов zwc в DOM. Он создан с помощью фабричного метода document.createTreeWalker, который принимает функцию фильтрации, которую мы можем написать для идентификации интересующих нас узлов. Наша функция фильтрации выглядит так:

contentScript.js
...
function(node) {
  if(testForZeroWidthCharacters(node.nodeValue)){
    totalCount++;
    return NodeFilter.FILTER_ACCEPT;
  }
  else{
    //FILTER_SKIP should keep the children of this node in consideration.
    return NodeFilter.FILTER_SKIP;
  }
}
...

NodeFilter.FILTER_ACCEPT и FILTER_SKIP - константы, которые сообщают treeWalker, что нужно включить текущий узел или пропустить его. Здесь есть третья возможность FILTER_REJECT, которая игнорирует дочерние элементы текущего узла. Это значительно ускорило бы поиск по дереву, если бы мы могли быть уверены, что текстовые дочерние элементы не существуют, но мы не можем, поэтому не будем :).

totalCount - это глобальная переменная, которую я использую, чтобы отслеживать, сколько zwc мы нашли.

testForZeroWidthCharacters - моя собственная функция, основанная на коде chpmrc и выглядит так:

contentScript.js
...
var zwMatches = /[\u200B-\u200D\uFEFF]/g;
function testForZeroWidthCharacters(text){
  return text.match(zwMatches);
}
...

Регулярное выражение zwMatches находится вне функции, потому что я также написал функции для удаления и замены zwc с использованием того же регулярного выражения. Регулярное выражение заканчивается на g, что означает, что это глобальное регулярное выражение, и оно будет соответствовать ВСЕМ вхождениям, а не только первому. Очень важно при снятии и замене ZWC!

Захват выделенного текста

Я не знал этого, но оказалось, что вы можете использовать document.onselectionchange, чтобы отслеживать каждый раз, когда пользователь выделяет текст на странице. selection.toString() получил мне текст, включая любые возможные zwc, которые я мог затем передать моей функции регулярного выражения и отправить в фоновый скрипт, чтобы уведомить пользователя. Простой!

//catch selected text and send message to background page
document.onselectionchange = function() {
  var selection = document.getSelection();
  if(testForZeroWidthCharacters(selection.toString())){
    chrome.storage.sync.set({
      selectedText: selection.toString(),
      selectedTextClean:removeZeroWidthCharacters(selection.toString()),
      selectedTextEmoji:replaceZeroWidthCharacters(selection.toString()),
    },function(){});
    /* show message*/
    chrome.runtime.sendMessage({message: "warnUserOfZeroWidthChars", value:selection.toString()}, function(response) {
    });
  }
};

И остальное…

Остальная часть кода очень проста:

Передача сообщений между контент-скриптом и фоновой страницей с помощью chrome.runtime.sendMessage и onMessage.

Отображение уведомлений пользователю с использованием chrome.notifications.create и chrome.notifications.onButtonClicked.

Создайте новую вкладку с chrome.tabs.create. Передайте очищенный текст с помощью chrome.storage.sync.

Я избавлю вас от подробностей.

Заключение

Поприветствуйте zwBlocker: расширение Chrome, которое:

  • Тонко показывает количество символов нулевой ширины на странице.
  • Обнаруживает символы нулевой ширины в выделенном тексте и уведомляет пользователя.
  • Отфильтровывает символы нулевой ширины по запросу.

Результатом довольна - неплохо для рабочих выходных! Конечно, можно сделать улучшения. Не стесняйтесь оставлять комментарии здесь, в твиттере, а также создавать вопросы или пул-реквесты на github.

Я также хочу сказать спасибо создателям, которые вдохновили этот пост. Мне нравится видеть активное обсуждение и работать над такими вещами.

Я Эйдан Брин, и я руковожу консалтингом по программному обеспечению в Дублине, Ирландия. Если вам понравился этот пост, подумайте о том, чтобы подписаться на меня в твиттере или подписаться на мой личный список рассылки для получения обновлений реже, чем раз в месяц.