Как Cloudflare защищает email
Как опубликовать адрес электронной почты на сайте, не боясь, что в него тут же начнут валиться горы спама?
В большинстве случаев эту задачу решают так: вставка адреса картинкой; написание особым способом, который читатели сайта смогут расшифровать (не всегда); форма для ввода текста письма. Разберём плюсы и минусы каждого.
Вставка адреса картинкой
[+] большинство ботов не читают тексты с картинки
[-] оформление картинки нужно как-то вписать в контекст
[-] картинку нужно хранить и беречь
[-] не получится создать письмо по нажатию на картинку
Написание особым способом
[+] скорее всего боты не смогут понять что это адрес электронной почты
[-] как и некоторые посетители сайта: help 911 (собака) mail com (замените пробелы на точки)
[-] боты всё же умеют разбирать большинство таких “шифровок”
Форма для ввода текста письма
[+] ваша почта явно не указана
[-] форма ввода текста — источник для спама (популярные капчи тоже разгадываются)
[-] разработка и поддержка формы ввода письма
[-] люди могут не хотеть писать в некую форму, не зная получит ли нужный человек письмо
Есть ли способ замаскировать почту так, чтобы и посетителям было удобно и боты на неё не обращали внимания?
Cloudflare Email Address Obfuscation позволяет подменять адреса на html-страничках таким образом, чтобы они перестали быть понятными ботам.
[email protected] -> 472f222b37697e7676072a262e2b6924282a
Откройте исходный код страницы и убедитесь, что там нет адреса электронной почты!
Если интересно как работает этот способ и как сделать аналогичное решение у себя, читайте дальше.
В основе лежит шифр Вернама — система симметричного шифрования, изобретённая в 1917 году сотрудником AT&T Гилбертом Вернамом. В нём используется булева функция «Исключающее ИЛИ» (bitwise xor). Шифр Вернама является примером системы с абсолютной криптографической стойкостью. При этом он считается одной из простейших криптосистем.
Для создания зашифрованной строки: генерируется случайное символ-число(секрет), берется последовательность символов, которые нужно зашифровать и к каждому из них применяется “исключающее ИЛИ” с секретом.
Рассмотрим на примере выше, как из email получилась такая строка:
- сгенерировали случайное число из диапазона печатных символов ASCII c 65 по 90 символ (A-Z): получилось 71 (это символ G) имеет значение 47 в шестнадцатеричной системе счисления
- записали 47 в результат
- затем применили к первой букве шифруемой строки исключающее ИЛИ, символ “h” имеет код 104, применив к нему XOR и 71 получаем 47, это в шестнадцатеричной системе будет 2f
- записываем 2f в результат
… применяем шаги 3 и 4 к оставшимся символам
Х. получаем 472f222b37697e7676072a262e2b6924282a
func encode(a string) (s string) {
b := int64(65 + rand.Intn(35))
s += strconv.FormatInt(b, 16)
for _, d := range []rune(a) {
r := strconv.FormatInt(b^int64(d), 16)
if len(r)%2!=0 {
r = "0"+r
}
s += r
}
return
}
Для процесса расшифровки действуем в обратном порядке:
- считываем первые два символа, это будет 47, из которого после преобразования из шестнадцатеричной системы в десятичную получаем 71 — это будет наш ключ
- считываем следующие два символа, это будет 2f, преобразуем к десятичной системе и получаем 47
- применяем к 47 XOR 71, таким образом получаем 104, а это код буквы h
- считываем следующие два символа, это будет 22, преобразуем к десятичной системе и получаем 34
- применяем к 34 XOR 71, таким образом получаем 101, а это код буквы e
… и так далее.
func decode(a string) (s string) {
r, _ := strconv.ParseInt(a[0:2], 16, 0)
for n := 4; n < len(a)+2; n += 2 {
i, _ := strconv.ParseInt(a[n-2:n], 16, 0)
s += string(i ^ r)
}
return
}
Остаётся добавить код на страницу и email будет в относительной безопасности:
<a href="#"><span class="__email__" data-class="472f222b37697e7676072a262e2b6924282a">[email protected]</span></a>
<script type="text/javascript">
Array.from(document.getElementsByClassName("__email__")).forEach(
function(l, index, array) {
var a = l.getAttribute("data-class");
if (a) {
var s = '';
var r = parseInt(a.substr(0, 2), 16);
for (var j = 2; a.length - j; j += 2) {
var c = parseInt(a.substr(j, 2), 16) ^ r;
s += String.fromCharCode(c);
}
l.parentNode.href = "mailto:"+s;
l.parentNode.innerText = s;
}
}
);
</script>