Comments 106
Для больших текстов можно иногда добавлять второй пробел.Лишний пробел довольно легко заметить в тексте, даже не читая его, просто при беглом просмотре. Если только он не попадает на конец строки.
Добавить пару пробелов в уникальной для юзера комбинации и всё. А для длинных текстов и небольшого количества клиентов — даже одного. Даже если кто придерётся, что текст кривой — всегда можно сослаться на залипший пробел (кстати при перекосе пробела на старой клаве такое случается, как и при слишком задранной скорости автоповтора).
Вообще-то суть не в том, чтобы показать, что текст скопировали. А именно уличить того, кто его копирует. Смысл просто менять букву или пробел добавлять?
Чтобы подставить кого-то другого нужно как минимум:
1. Знать о том, что эта система вообще существует (т.е. это должен быть кто-то из очень своих)
2. Знать о том, какая комбинация кому соответствует (т.е. это должен быть кто-то из админов)
Собственно в любой случае тут уже не сработает никакой из вариантов предложенных в статье или комментариях.
один пробел: 100 вариантов.
2 пробела: ~10000
Опечатка (например довольно типичная — замена 2х соседних букв местами): ~300..400
Опечатка (замена символа): ~6000..7000
Подсчёты крайне приблизительные, но порядок прикинуть позволяют.
И 100 слов — это очень мало. В этом комментарии их примерно 40.
один пробел: 100 вариантов.Два пробела — примерно в два раза меньше, т.к. перестановка (обмен местами) двух пробелов ничего не меняет.
2 пробела: ~10000
А идею с дополнительными пробелами (в т.ч. кодируемыми разными символами) я одобряю.
При такой ёмкости можно даже применить избыточное кодирование с восстановлением.
Вариант, работающий на 146%: перенабрать текст вручную (или использовать OCR).
Я кстати думал, как можно было бы бороться с этим. От OCR можно защититься опечатками, небольшими изменениями пунктуации (дефис вместо тире, запятая вместо точки с запятой, знаки сноски, арабские/римские цифры в списках, кавычки).
С перенабором вручную уже сложнее — для фингерпринта понадобится тоже ручная работа. Можно фингерпринтить синонимами и парафразами. Выделить достаточное количество участков в тексте и задать для них варианты замены. Потом кодировать уникальный ID с помощью комбинации замен.
Если текст направлен ограниченному количеству человек, можно вставить в середине предложение, в котором будут меняться синонимы слов в зависимости от пользователя. Затем по синонимам вычислять id пользователя. Еще лучше пораскидать таких слов по всему тексту в «случайном» порядке.
Работает только для ну очень ограниченного количестваНе знаю, что за ограниченное количество, но 40 синонимов хватит на 1 трлн человек. Ну либо 1 млрд + 8 бит на подпись.
2. Нам не нужны синонимы «от балды». Нужны синонимы именно для слов из текста, т.е. обязательно придётся использовать определённый набор слов.
3. Их нужно согласовывать с остальным текстом, что немного муторно делать автоматически.
Т.е. в целом использовать можно, но слишком сложно (imho)
А теперь для эксперимента подберём синонимы для этого комментария:
(Так|ну)(ведь)? не для одного (и того же|же|) слова (40|сорок) синонимов(. а для|. Для) любых (слов)? (по одному синониму на (одно)? слово). Под синонимами (можно подразумевать ←→ даже) перестановку (слов ← или → частей предложения). Думаю, (40|сорок) (, в зависимости от (размера|длины) текста, наберётся (достаточно|очень) быстро|СТАРЫЙ_ВАРИАНТ)
Итог: без проблем подобрал 13.58 синонимов даже к такому небольшому тексту. Этого хватит, чтобы найти одного пользователя из 12 тысяч. Это как-то плохо сочетается с «Работает только для ну очень ограниченного количества».
2. Как разрешать подобные варианты?
любых (слов)? (по одному синониму на (одно)? слово).И это всего одно предложение. В длинном тексте это уже станет изрядной проблемой.
Конечно же, варианты не должны храниться на диске, а должны автоматически генерироваться при открытии страницы пользователем.
2. Как разрешать подобные варианты?А что здесь не так? Все фразы корректны. Ничего разрешать не нужно. Примеры:
- Так не для одного же слова 40 синонимов. Для любых (по одному синониму на слово).
- Так не для одного же слова 40 синонимов. Для любых (по одному синониму на одно слово).
- Так не для одного же слова 40 синонимов. Для любых слов (по одному синониму на слово).
- Так не для одного же слова 40 синонимов. Для любых слов (по одному синониму на одно слово).
На то они и синонимы, что не влияют на остальные части текста. Т. е. синонимы нужно подбирать так, чтобы они не могли ничего сломать. В моём случае так и подобрано.
1. Если у нас просто набор синонимов, который автоматически подставляется при подходящем случае — то возникает
* проблема использования таких слов там, где замена не предполагается
* проблема наличия в любом языке слов, имеющих больше одного смысла (решается очень внимательным подбором синонимов)
* проблема словоформ. в англицком она ещё решаема, но в русском всё может быть очень сложно.
А вообще предполагается, что найти синонимы придётся 1 раз, так и вычислить крысу. Если 40 — много, то 4 текста по 10 синонимов.
Если же это защита интеллектуального произведения, то найти 40 синонимов значительно легче, чем написать статью/книгу. Здесь уже можно и каждый раз подбирать.
В случае же книги (да и для любых реально больших текстов) как раз более простые и автоматические методы более эффективны (imho). Вероятность там что-то заметить сильно меньше, а места для сокрытия — больше.
Это вы ещё не вспомнили 'вариант омега' про радиоигру разведок: помните точку в конце предложения?
Например, вы можете предположить, что ваш терминал попытается их отобразить (мой нет!).
Н<200b>апример, в э<200b>то пред<200b>ложение я вст<200b>авил де<200b>сять про<200b><200b>белов н<200b>улевой ширины, вы эт<200b>о замет<200b>или?
Для тех кому интересно(Vim).
Еще вот так их можно найти (если знать что они там есть!):
Двойной клик выделяет кусок текста, ограниченный пробелами.
Стандартный маковский тоже вполне справляется:
Например, вот так выглядит «скрытая» информация в Telegram:
Эффект блокнота :)
Во-первых любой нормальный rich-edit это покажет, во-вторых (вытекающее из первого) — ненадежно — символы могут быть потеряны при копировании или очистке и т.д.
Кодирование есть куда проще — знаками пунктуации. Тире и дефисов в юникоде штук 5, замена точек на точку с запятой и т.д.
Имея 5 вариантов — это уже 5 бит — 2^5 пользователей.
Никто на это не обратит внимание, как на похожие по начертанию символы или что-то еще. Все привыкли, что типографика всегда страдает.
Имея 5 вариантов — это уже 5 бит — 2^5 пользователей.
Ух ты! Целых 32 пользователя!:)
Если у тире пять вариантов, то одно тире в предложении даёт возможность идентифицировать 5 пользователей, два — 25 и так далее.
Но если тире в тексте больше одного, то их подозрительное различие будет визуально заметно. То же с пробелами разной ширины.
Кроме того, можно составить текст так, чтобы там были по смыслу определенная типографика, а дальше — играться.
Так удалось вычислить инсайдера или нет?
Если дочитать статью до конца, то вопрос отпадет.
Концовка мягковато описана. С учётом "любви к нему" и усилий по вычислению, я прямо ждал ту картинку "он не сделал бекап и дропнул базу", ну или хотя бы что-то более суровое ("нашли его с группой товарищей и заставили вслух читать число пи до 1000 знака!"), чем просто забанили.
стандартный Windows cmd.exe
Однако для того, чтобы обезопаситься от утечек, многие из них каждому адресату отправляли тексты романов с некоторыми уникальными изменениями — лишний пробел между словами, запятая сдвинутая вправо, использование буквы «ё» там, где у других буква «е», и всё такое прочее. Не сказать, что утечки были массовой проблемой, но возможно в т.ч. потому, что получатели знали о возможном «фингерпринтстве», а инсайдеры более одного раза не могли предать чужое доверие.
deleted
Так многие и делают, особенно на мобилах, бо скриншот — одно нажатие кнопок, а копипаста — та ещё затея.
const zeroWidthSpace = '';
const zeroWidthNonJoiner = '';
const zeroWidthJoiner = '';
const zeroWidthNoBreakSpace = '';
const binaryToZeroWidth = binary => (
binary.split('').map((binaryNum) => {
const num = parseInt(binaryNum, 10);
if (num === 1) {
return zeroWidthSpace;
} else if (num === 0) {
return zeroWidthNonJoiner;
}
return zeroWidthJoiner;
}).join(zeroWidthNoBreakSpace);
);
Плюс, как уже заметили выше есть еще одинаковые символы в разных языках.
Т.е. даже если применять преобразование бинарного в… то гораздо оптимальнее преобразовывать в 4-, 8-, 16-ричный код (используя больше символов). Так меньше символов на тот же объем информации потребуется.
Подумал, что косяк переводчика, но нет, на хромиумовских браузерах таки пробела не видно.
Нашел инсайдера, который сливает данные? Просто прекрасно, теперь можно управлять сливаемыми данными! Т.е. тупо отправлять дезу, периодически проверяя, что на других сайтах именно деза с правильным отпечатком имени. И теперь начинается настоящая шпионская игра! Особенно для того, чтобы инсайдер не заметил изменения отношения и «все осталось как есть» (с доступом к архиву правильных записей, как вариант).
Вот это условие на первый взгляд вообще лишено смысла
if (char === '') {
return '1';
} else if (char === '') {
return '0';
}
<!DOCTYPE html>
<html lang="ru">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="Keywords" content="refining" /><meta name="abstract" content="refining" /><meta name="description" content="refining" /><meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Чистильщик</title>
</head>
<body style="text-align:center;margin:0;">
<div>
<textarea id='trash' type="text" style="width:90%;height:400px; text-align:center;"></textarea>
</div>
<button style="width:180px;height:60px;font: bold 20px/1.5 cursive; text-align:center;" id="_button">старт</button>
<br/><br/>
<div id="resultation"></div>
<script>
function refining(){
rG1='';
trash=String(document.getElementById('trash').value);
var sG1=new Array();
for(i=0;i<trash.length;i++){sG1[i]=trash[i].replace(/[^а-яА-яa-zA-Z_0-9-—!"№%?*()\[\]+=@#$%^&*{}:;"'?><.,|\ \\\/\n\ ]/g, '\█');};
for(i=0;i<sG1.length;i++){rG1+=sG1[i];};
document.getElementById('resultation').innerHTML=rG1;
};
document.getElementById('_button').onclick=refining;
</script>
</body>
</html>
Также такой текст очень неудобно слушать. Вот прочитайте написанный в посте текст вслух: так он и читается скринридером:
«Н апример, в э то пред ложение я вст авил де сять про белов н улевой ширины, вы эт о замет или?»
P. S. Сам символ озвучивается при посимвольном чтении, как «Пробел нулевой ширины».
Получается надо текст писать картинкой и тогда есть хоть какой то вариант не спалится, хотя и с картинкой можно опростоволоситься.
©Opera 12.16
При копировании я всегда снимаю оформление и выполняю подмену UTF-8 на ASCII.
Мне кажется что игра с пробелами (1 или 2), замена сходных букв кириллицы на латиницу, а также передача не чисто имени, а уникального ID даст больше эффекта и скрытности.
Да. Есть расширение для Chrome: https://chrome.google.com/webstore/detail/replace-zero-width-charac/lgaiigbekmcejmhenhhleeaicbcjjddi
Код здесь: https://github.com/chpmrc/zero-width-chrome-extension
echo "Например, в это предложение я вставил десять пробелов нулевой ширины, вы это заметили?" | iconv -c -t cp1251 | iconv -f cp1251
Все не 8-битные символы идут в сад.
Можно пойти дальше. рандомно подставлять похожие символы из других кодовых таблиц, добавлять-убирать пробелы перед знаками пунктуации…
Осторожнее с копипастом: фингерпринтинг текста непечатаемыми символами