(Эта статья была представлена в виде доклада на Spam Conference 2003 года. В ней описывается работа, которую я проделал для улучшения алгоритма, описанного в статье «План по борьбе со спамом», а также мои планы на будущее.)
Первое открытие, которое я хотел бы здесь представить, — это алгоритм ленивых вычислений для научных статей. Просто пишите всё, что хотите, и не ссылайтесь ни на какие предыдущие работы, и возмущенные читатели сами пришлют вам ссылки на все статьи, которые вам следовало процитировать. Я открыл этот алгоритм после того, как «План по борьбе со спамом» [1] попал на Slashdot.
Фильтрация спама — это подраздел классификации текстов, хорошо развитой области, но первыми статьями именно о байесовской фильтрации спама, по-видимому, были две работы, представленные на одной и той же конференции в 1998 году: одна — Пантеля и Лина [2], а другая — группы из Microsoft Research [3].
Когда я узнал об этих работах, я был немного удивлен. Если люди занимались байесовской фильтрацией еще четыре года назад, почему же ей не пользовались все подряд? Прочитав статьи, я понял причину. Фильтр Пантеля и Лина был более эффективным из двух, но он улавливал всего 92% спама при 1,16% ложных срабатываний.
Когда я попробовал написать байесовский спам-фильтр, он отловил 99,5% спама менее чем с 0,03% ложных срабатываний [4]. Всегда тревожно, когда два человека, проводя один и тот же эксперимент, получают совершенно разные результаты. В данном случае это особенно тревожно, поскольку эти два набора чисел могут приводить к противоположным выводам. У разных пользователей разные требования, но я думаю, что для многих показатель фильтрации 92% при 1,16% ложных срабатываний означает, что фильтрация неприемлема, тогда как 99,5% при менее чем 0,03% ложных срабатываний — что вполне приемлема.
Так почему же мы получили настолько разные цифры? Я не пытался воспроизвести результаты Пантеля и Лина, но, судя по статье, вижу пять факторов, которые, вероятно, объясняют эту разницу.
Во-первых, они обучали свой фильтр на очень малом объеме данных: 160 спам-писем и 466 обычных писем. На таких небольших наборах данных эффективность фильтра все еще должна расти. Так что их показатели могут даже не отражать точную эффективность их алгоритма, не говоря уже о байесовской фильтрации спама в целом.
Но я считаю, что самое важное отличие, пожалуй, заключалось в том, что они проигнорировали заголовки сообщений. Любому, кто работал над спам-фильтрами, это решение покажется противоестественным. И тем не менее, в самых первых фильтрах, которые я пытался написать, я тоже игнорировал заголовки. Почему? Потому что мне хотелось сохранить задачу чистой и простой. Тогда я мало знал о заголовках писем, и они казались мне полными случайного мусора. Здесь кроется урок для разработчиков фильтров: не игнорируйте данные. Казалось бы, этот урок слишком очевиден, чтобы о нем упоминать, но мне пришлось усваивать его несколько раз.
В-третьих, Пантель и Лин применяли стемминг к токенам, то есть сводили, например, и «mailing», и «mailed» к корню «mail». Возможно, они чувствовали себя вынужденными делать это из-за небольшого размера своего корпуса, но если так, то это разновидность преждевременной оптимизации.
В-четвертых, они иначе рассчитывали вероятности. Они использовали все токены, тогда как я использую только 15 самых значимых. Если вы берете все токены, вы рискуете пропустить более длинный спам — тот, где кто-то рассказывает историю своей жизни вплоть до момента, когда он разбогател на какой-нибудь схеме сетевого маркетинга. К тому же такой алгоритм спамерам было бы легко обмануть: достаточно добавить большой кусок случайного текста, чтобы уравновесить спам-слова.
Наконец, они не делали смещения против ложных срабатываний. Я считаю, что у любого алгоритма фильтрации спама должна быть удобная ручка регулировки, которую можно повернуть, чтобы снизить долю ложных срабатываний ценой некоторого снижения процента отсева спама. Я делаю это за счет удвоения веса вхождений токенов в корпусе легитимных писем.
Я не считаю хорошей идеей относиться к фильтрации спама как к прямолинейной задаче классификации текстов. Вы можете использовать методы классификации текстов, но решения могут и должны отражать тот факт, что этот текст — электронное письмо, и спам в частности. Электронная почта — это не просто текст; у нее есть структура. Фильтрация спама — это не просто классификация, потому что ложные срабатывания намного хуже ложных пропусков, и к ним следует относиться как к ошибке совершенно иного рода. И источник ошибок здесь — не просто случайная вариативность, а живой человек, спамер, активно работающий над тем, чтобы обойти ваш фильтр.
Токены
Еще один проект, о котором я услышал после статьи на Slashdot, — это CRM114 Билла Йеразиниса [5]. Это контрпример к только что упомянутому мной принципу проектирования. Это чисто текстовый классификатор, но настолько поразительно эффективный, что ему удается фильтровать спам практически идеально, даже не подозревая, что он занимается именно этим.
Как только я понял, как устроен CRM114, стало очевидно, что рано или поздно мне придется перейти от фильтрации на основе отдельных слов к подобному подходу. Но сначала, подумал я, посмотрю, как далеко я смогу зайти с отдельными словами. И ответ таков: на удивление далеко.
В основном я работал над более умной токенизацией. На текущем спаме мне удалось достичь показателей фильтрации, приближающихся к CRM114. Эти методы по большей части ортогональны подходу Билла; оптимальное решение могло бы объединять и то, и другое.
В «Плане по борьбе со спамом» используется очень простое определение токена. Буквы, цифры, дефисы, апострофы и знаки доллара считаются составными символами, а все остальное — разделителями токенов. Регистр я также игнорировал.
Теперь у меня более сложное определение токена: регистр сохраняется.
Восклицательные знаки являются составными символами.
Точки и запятые считаются составными, если они стоят между двумя цифрами. Это позволяет сохранять ip-адреса и цены неповрежденными.
Диапазон цен вроде $20-25 дает два токена: $20 и $25.
Токены, встречающиеся в строках To, From, Subject и Return-Path, или внутри URL, помечаются соответствующим образом. Например, «foo» в строке Subject становится «Subject*foo». (Звездочкой может быть любой символ, который вы не разрешаете в качестве составного.) Такие меры увеличивают словарь фильтра, что делает его более избирательным. Например, в текущем фильтре «free» в строке Subject имеет вероятность спама 98%, тогда как тот же токен в теле письма имеет вероятность спама лишь 65%.
Вот некоторые из текущих вероятностей [6]:
Subject*FREE 0.9999 free!! 0.9999 To*free 0.9998 Subject*free 0.9782 free! 0.9199 Free 0.9198 Url*free 0.9091 FREE 0.8747 From*free 0.7636 free 0.6546 В фильтре из «Плана по борьбе со спамом» все эти токены имели бы одну и ту же вероятность — 0,7602. Тот фильтр распознавал около 23 000 токенов. Текущий распознает около 187 000.
Недостаток большего пространства токенов заключается в том, что возрастает вероятность промахов. Распределение вашего корпуса по большему числу токенов дает тот же эффект, что и его уменьшение. Если вы считаете восклицательные знаки составными символами, например, у вас может не оказаться вероятности спама для слова free с семью восклицательными знаками, хотя вам известно, что для free всего с двумя восклицательными знаками вероятность составляет 99,99%.
Одним из решений этой проблемы является то, что я называю дегенерацией (упрощением). Если вы не можете найти точное совпадение для токена, рассматривайте его так, как если бы он был менее специфичной версией. Я считаю, что замыкающие восклицательные знаки, заглавные буквы и появление в одном из пяти отмеченных контекстов делают токен более специфичным. Например, если я не нахожу вероятность для «Subject*free!», я ищу вероятности для «Subject*free», «free!» и «free» и беру ту, которая дальше всего от 0,5.
Вот альтернативы [7], которые рассматриваются, если фильтр видит «FREE!!!» в строке Subject и не имеет для него готовой вероятности.
Subject*Free!!! Subject*free!!! Subject*FREE! Subject*Free! Subject*free! Subject*FREE Subject*Free Subject*free FREE!!! Free!!! free!!! FREE! Free! free! FREE Free free Если вы делаете это, обязательно учитывайте варианты как с первой заглавной буквой, так и полностью прописными или строчными. В спаме чаще встречаются предложения в повелительном наклонении, а в них первое слово — глагол. Поэтому глаголы с первой заглавной буквы имеют более высокую вероятность оказаться спамом, чем они же в нижнем регистре. В моем фильтре вероятность спама для «Act» составляет 98%, а для «act» — всего 62%.
Если вы увеличиваете словарь фильтра, может получиться так, что вы будете учитывать одно и то же слово несколько раз — согласно вашему старому определению «того же самого». Логически это уже не один и тот же токен. Но если вас это все еще беспокоит, добавлю по опыту: слова, которые вы вроде как считаете несколько раз, обычно оказываются именно теми, которые вам и хотелось бы так посчитать.
Еще одно следствие расширения словаря заключается в том, что при анализе входящего письма вы находите больше интересных токенов, то есть таких, чья вероятность далека от 0,5. Я использую 15 наиболее интересных, чтобы решить, является ли письмо спамом. Но при использовании фиксированного числа можно столкнуться с проблемой. Если вы найдете много максимально интересных токенов, результат в итоге может определиться тем случайным фактором, который задает порядок сортировки одинаково интересных токенов. Один из способов справиться с этим — считать некоторые из них более интересными, чем другие.
Например, токен «dalco» встречается 3 раза в моем спам-корпусе и ни разу — в легитимном. Токен «Url*optmails» (то есть «optmails» внутри URL) встречается 1223 раза. И все же, по моей прежней схеме расчета вероятностей для токенов, оба имели бы одинаковую вероятность спама — пороговые 0,99.
Это кажется неправильным. Существуют теоретические аргументы в пользу того, чтобы присваивать этим двум токенам существенно разные вероятности (Пантель и Лин так и делают), но я этого еще не пробовал. Однако представляется, что если мы находим более 15 токенов, которые встречаются только в одном корпусе или только в другом, нам следует отдавать приоритет тем, которые встречаются часто. Поэтому теперь есть два пороговых значения. Для токенов, встречающихся только в спам-корпусе, вероятность равна 0,9999, если они встречаются более 10 раз, и 0,9998 в противном случае. То же самое на другом конце шкалы для токенов, найденных только в легитимном корпусе.
Позже я, возможно, введу более существенное масштабирование вероятностей токенов, но даже эта крошечная градация по крайней мере гарантирует, что токены сортируются в правильном порядке.
Другой возможностью было бы учитывать не просто 15 токенов, а все токены, превышающие определенный порог интересности. Стивен Хаузер делает это в своем статистическом спам-фильтре [8]. Если вы используете порог, сделайте его очень высоким, иначе спамеры смогут обмануть вас, наполняя сообщения большим количеством невинных слов.
Наконец, что делать с HTML? Я перепробовал весь спектр вариантов: от полного игнорирования до разбора от корки до корки. Игнорировать HTML — плохая идея, потому что он полон полезных признаков спама. Но если разбирать его целиком, ваш фильтр может деградировать в простой распознаватель HTML. Наиболее эффективным подходом представляется золотая середина: обращать внимание на одни токены и игнорировать другие. Я смотрю на теги a, img и font, а остальные игнорирую. На ссылки и изображения смотреть определенно стоит, поскольку они содержат URL.
Вероятно, я мог бы обращаться с HTML умнее, но я не думаю, что на это стоит тратить много времени. Спам, напичканный HTML, фильтровать легко. Более умные спамеры уже избегают его. Так что эффективность в будущем не должна сильно зависеть от того, как вы работаете с HTML.
Эффективность
С 10 декабря 2002 по 10 января 2003 года я получил около 1750 спам-писем. Из них просочились 4. Это дает уровень фильтрации около 99,75%.
Два из четырех пропущенных спам-писем прорвались потому, что в них случайно оказались слова, часто встречающиеся в моей обычной переписке.
Третье было из тех, что эксплуатируют уязвимый cgi-скрипт для отправки писем третьим лицам. Их трудно отфильтровать только по содержимому, потому что заголовки не вызывают подозрений, а слова подобраны аккуратно. Тем не менее мне обычно удается их поймать. Это конкретное письмо проскочило с вероятностью 0,88, чуть ниже порога в 0,9.
Конечно, рассмотрение последовательностей из нескольких токенов легко бы его поймало. Фраза «Below is the result of your feedback form» выдает его мгновенно.
Четвертый спам представлял собой то, что я называю спамом будущего, потому что я ожидаю, что именно в это спам и эволюционирует: абсолютно нейтральный текст, за которым следует URL. В данном случае это было письмо от кого-то, кто сообщил, что наконец-то доделал свою домашнюю страничку, и попросил заглянуть на нее. (Страница, разумеется, оказалась рекламой порносайта.)
Если спамеры аккуратны с заголовками и используют свежий URL, в спаме будущего фильтрам просто не за что зацепиться. Мы, конечно, можем ответить отправкой краулера для проверки страницы. Но это может и не понадобиться. Коэффициент отклика на спам будущего должен быть низким, иначе им занимались бы все. Если он достаточно низок, спамерам будет невыгодно его рассылать, и нам не придется слишком усердствовать с его фильтрацией.
А теперь действительно шокирующая новость: за тот же месячный период у меня было три ложных срабатывания.
В каком-то смысле получить несколько ложных срабатываний — это облегчение. Когда я писал «План по борьбе со спамом», у меня их не было вообще, и я не знал, какими они будут. Теперь, получив несколько, я с облегчением обнаружил, что они не так страшны, как я опасался. Ложные срабатывания статистических фильтров оказываются письмами, которые очень похожи на спам, и это, как правило, именно те письма, потерю которых вы переживете легче всего [9].
Два ложных срабатывания были новостными рассылками от компаний, у которых я что-то покупал. Я никогда не подписывался на них, так что формально это был спам, но я считаю их ложными срабатываниями, потому что раньше не удалял их как спам. Причина, по которой фильтры их перехватили, заключалась в том, что в январе обе компании перешли на коммерческие сервисы рассылок вместо отправки со своих собственных серверов, и как заголовки, так и текст стали намного более «спамовыми».
Третье ложное срабатывание, однако, было неприятным. Это было письмо от кого-то из Египта, написанное одними заглавными буквами. Это стало прямым следствием учета регистра токенов; фильтр из «Плана по борьбе со спамом» его бы не задержал.
Трудно сказать, каков общий уровень ложных срабатываний, потому что статистически мы находимся на уровне шума. Любой, кто работал над фильтрами (по крайней мере, эффективными), знает об этой проблеме. В отношении некоторых писем трудно сказать, спам это или нет, и именно с ними вы в итоге и сталкиваетесь, когда настраиваете фильтры по-настоящему жестко. Например, к настоящему моменту фильтр перехватил два письма, отправленных на мой адрес из-за опечатки, и одно, отправленное мне по ошибке в уверенности, что я — другой человек. Строго говоря, это ни мой спам, ни моя обычная почта.
Еще одно ложное срабатывание пришло от вице-президента компании Virtumundo. Я написал им, притворившись клиентом, и поскольку ответ пришел через почтовые серверы Virtumundo, он нес в себе самые уличающие заголовки, какие только можно вообразить. Пожалуй, это тоже не настоящее ложное срабатывание, а своего рода эффект неопределенности Гейзенберга: я получил его только потому, что писал о фильтрации спама.
Не считая этих случаев, у меня пока было всего пять ложных срабатываний примерно на 7740 нормальных писем — показатель 0,06%. Остальными двумя были уведомление о задержке заказанного товара и приглашение на вечеринку от Evite.
Я не думаю, что этой цифре можно доверять — отчасти потому, что выборка слишком мала, а отчасти потому, что, как мне кажется, я могу подправить фильтр, чтобы он не цеплял некоторые из них.
Ложные срабатывания кажутся мне ошибкой совершенно иного рода, чем ложные пропуски. Доля отсева спама — это показатель производительности. Ложные срабатывания я считаю скорее багами. Я подхожу к повышению доли отсева как к оптимизации, а к снижению ложных срабатываний — как к отладке.
Так что эти пять ложных срабатываний — мой список багов. Например, письмо из Египта попало под раздачу потому, что текст заглавными буквами сделал его похожим для фильтра на нигерийский спам. Это действительно своего рода баг. Как и в случае с HTML, письмо, целиком написанное заглавными буквами, концептуально представляет собой один признак, а не отдельный признак для каждого слова. Мне нужно обрабатывать регистр более тонко.
Итак, что же делать с этими 0,06%? Думаю, не делать далекоидущих выводов. Вы можете рассматривать это как верхнюю границу, учитывая малый размер выборки. Но на данном этапе это скорее показатель багов в моей реализации, чем некой неустранимой доли ложных срабатываний байесовской фильтрации как таковой.
Будущее
Что дальше? Фильтрация — это задача оптимизации, а ключ к оптимизации — профилирование. Не пытайтесь угадать, где ваш код работает медленно, потому что вы угадаете неправильно. Посмотрите, где он тормозит, и исправьте это. В фильтрации это переводится так: посмотрите на спам, который вы пропустили, и выясните, что можно было сделать, чтобы его поймать.
Например, спамеры сейчас активно работают над тем, чтобы обойти фильтры, и одно из их действий — разбиение и намеренное искажение написания слов, чтобы фильтры их не узнали. Но работа над этим не является моим главным приоритетом, поскольку я все еще без проблем отлавливаю такой спам [10].
Есть два типа спама, с которыми у меня сейчас действительно возникают трудности. Первый тип притворяется письмом от женщины, приглашающей поболтать с ней в чате или посмотреть ее анкету на сайте знакомств. Они проскальзывают потому, что это единственный вид торгового предложения, которое можно сделать без использования рекламного жаргона. В них используется тот же словарный запас, что и в обычной переписке.
Другой вид спама, который мне трудно фильтровать, исходит от компаний, например, из Болгарии, предлагающих услуги заказной разработки ПО. Они просачиваются потому, что я и сам программист, и их спам полон тех же слов, что и мои настоящие письма.
Вероятно, сначала я сосредоточусь на сообщениях типа личных объявлений. Думаю, если присмотреться повнимательнее, я смогу найти статистические различия между ними и моей реальной почтой. Стиль изложения там определенно другой, хотя для его выявления может потребоваться фильтрация по последовательностям слов. Кроме того, я заметил, что они склонны повторять URL, чего человек в обычном письме делать бы не стал [11].
Аутсорсинговый спам поймать будет сложно. Даже если отправить краулер на их сайт, там не найдется явных статистических улик. Возможно, единственный выход — централизованный список доменов, рекламируемых в спаме [12]. Но таких писем не может быть слишком много. Если бы единственным оставшимся спамом были незапрошенные предложения услуг заказной разработки из Болгарии, мы все, вероятно, могли бы спокойно заняться чем-нибудь другим.
Приведет ли нас статистическая фильтрация к этой точке на самом деле? Я не знаю. Прямо сейчас лично для меня спам не является проблемой. Но спамеры пока не предпринимали серьезных попыток обмануть статистические фильтры. Что произойдет, когда они начнут?
Я не испытываю оптимизма по поводу фильтров, работающих на сетевом уровне [13]. Когда возникает статическое препятствие, которое стоит обойти, спамеры довольно эффективно справляются с этой задачей. Уже существует компания под названием Assurance Systems, которая прогонит ваше письмо через Spamassassin и скажет, будет ли оно отфильтровано.
Фильтры сетевого уровня не будут абсолютно бесполезными. Их может быть достаточно, чтобы убить весь так называемый «opt-in» спам — то есть письма от таких компаний, как Virtumundo и Equalamail, заявляющих, будто они честно работают по спискам подписчиков. Их можно фильтровать по одним только заголовкам, независимо от содержимого тела письма. Но любой, кто готов подделывать заголовки или использовать открытые релеи — включая, вероятно, большинство порноспамеров, — сможет при желании протащить сообщение через сетевые фильтры. (Хотя отнюдь не то сообщение, которое им хотелось бы отправить, и это уже плюс.)
Фильтры, внушающие мне оптимизм, — это те, которые рассчитывают вероятности на основе почты каждого конкретного пользователя. Они могут быть намного эффективнее не только в предотвращении ложных срабатываний, но и в самой фильтрации: например, обнаружение адреса получателя, закодированного в base-64 в любом месте сообщения, является очень сильным признаком спама.
Но главное преимущество индивидуальных фильтров в том, что все они будут разными. Если у каждого пользователя в фильтрах будут разные вероятности, это сделает цикл оптимизации спамеров — то, что программисты назвали бы циклом «правка — компиляция — тестирование», — мучительно медленным. Вместо того чтобы просто подгонять спам, пока он не пройдет через копию фильтра на их собственном компьютере, им придется делать тестовую рассылку для каждой правки. Это было бы похоже на программирование на языке без интерактивной командной строки (REPL), а такого я бы никому не пожелал.
Примечания
[1] Paul Graham. ``A Plan for Spam.'' August 2002. http://paulgraham.com/spam.html.
Вероятности в этом алгоритме вычисляются с использованием вырожденного случая теоремы Байеса. Делаются два упрощающих предположения: что вероятности признаков (то есть слов) независимы, и что нам ничего не известно об априорной вероятности того, что письмо является спамом.
Первое предположение широко распространено в классификации текстов. Алгоритмы, использующие его, называют «наивными байесовскими».
Второе предположение я сделал потому, что доля спама в моей входящей почте колебалась от дня ко дню (и даже от часа к часу) настолько сильно, что общее априорное соотношение казалось бесполезным для прогнозирования. Если предположить, что P(spam) и P(nonspam) равны 0,5, они сокращаются, и их можно исключить из формулы.
Если бы вы занимались байесовской фильтрацией в ситуации, когда соотношение спама и нормальной почты стабильно очень велико или (особенно) очень мало, вы, вероятно, могли бы повысить эффективность фильтра за счет учета априорных вероятностей. Чтобы сделать это правильно, вам пришлось бы отслеживать соотношения по времени суток, поскольку объемы спама и легитимной почты имеют отчетливые суточные циклы.
[2] Patrick Pantel and Dekang Lin. ``SpamCop-- A Spam Classification & Organization Program.'' Proceedings of AAAI-98 Workshop on Learning for Text Categorization.
[3] Mehran Sahami, Susan Dumais, David Heckerman and Eric Horvitz. ``A Bayesian Approach to Filtering Junk E-Mail.'' Proceedings of AAAI-98 Workshop on Learning for Text Categorization.
[4] На тот момент у меня было ноль ложных срабатываний примерно на 4000 нормальных писем. Если бы следующее обычное письмо оказалось ложным срабатыванием, мы получили бы 0,03%. Этим значениям доли ложных срабатываний нельзя доверять, как я объясняю ниже. Я привожу здесь эту цифру лишь для того, чтобы подчеркнуть: какова бы ни была реальная доля ложных срабатываний, она меньше 1,16%.
[5] Bill Yerazunis. ``Sparse Binary Polynomial Hash Message Filtering and The CRM114 Discriminator.'' Proceedings of 2003 Spam Conference.
[6] В «Плане по борьбе со спамом» я использовал пороги 0,99 и 0,01. Кажется оправданным использовать пороги, пропорциональные размеру корпусов. Поскольку сейчас у меня порядка 10 000 писем каждого типа, я использую 0,9999 и 0,0001.
[7] Здесь есть недостаток, который мне, вероятно, стоит устранить. В настоящее время, когда «Subject*foo» дегенерирует до просто «foo», это означает получение статистики вхождений «foo» в теле письма или в строках заголовка, кроме тех, что я помечаю. На самом деле мне следовало бы отслеживать статистику для «foo» в целом, наряду с конкретными версиями, и дегенерировать «Subject*foo» не до «foo», а до «Anywhere*foo». То же самое с регистром: мне следовало бы дегенерировать от заглавных букв к любому регистру, а не к нижнему.
Вероятно, имело бы смысл проделать то же самое и с ценами, например, дегенерировать от «$129.99» к «$--9.99», «$--.99» и «$--».
Можно было бы также переходить от слов к их основам (стеммам), но это, вероятно, улучшило бы качество фильтрации только на раннем этапе при малых размерах корпусов.
[8] Steven Hauser. ``Statistical Spam Filter Works for Me.'' http://www.sofbot.com.
[9] Ложные срабатывания бывают разными, и нам следует помнить об этом при сравнении методов борьбы со спамом. В то время как многие ложные срабатывания фильтров вызваны околоспамовыми письмами, потерю которых вы легко переживете, ложные срабатывания из-за черных списков, например, будут просто письмами от людей, выбравших не того провайдера. В обоих случаях перехватывается письмо, близкое к спаму, но для черных списков эта близость физическая, а для фильтров — текстовая.
[10] Если спамеры научатся скрывать токены настолько хорошо, что это станет проблемой, мы сможем ответить простым удалением пробелов, точек, запятых и т. д. и использовать словарь для извлечения слов из получившейся последовательности. И, разумеется, обнаружение таким способом слов, которых не было видно в исходном тексте, само по себе будет признаком спама.
Извлекать слова будет непросто. Потребуется нечто большее, чем просто восстановление границ слов; спамеры как добавляют (“xHot nPorn cSite”), так и пропускают (“P#rn”) буквы. Здесь могут пригодиться исследования в области компьютерного зрения, поскольку человеческое зрение — это предел, к которому будут стремиться подобные уловки.
[11] В целом спам более однообразен и склонен к повторам, чем обычная почта. Спамеры хотят вбить свое послание в голову. В настоящее время я не допускаю дубликатов в топ-15 токенов, потому что можно получить ложное срабатывание, если отправитель случайно употребит какое-то «плохое» слово несколько раз. (В моем текущем фильтре вероятность спама для слова “dick” составляет 0.9999, но это также и имя.) Кажется, нам все же следует хотя бы замечать повторы, поэтому я, возможно, попробую разрешить до двух одинаковых токенов, как делает Брайан Бертон в SpamProbe.
[12] Вот во что выродятся такие подходы, как у Brightmail, когда спамеров вынудят использовать методы в стиле Mad Libs для генерации всего остального содержимого письма.
[13] Иногда утверждают, что нам следует заниматься фильтрацией на сетевом уровне, поскольку это эффективнее. На самом деле под этим обычно имеют в виду следующее: сейчас мы фильтруем на сетевом уровне и не хотим начинать все с нуля. Но нельзя подгонять задачу под свое решение.
Исторически аргументы об ограниченности ресурсов оказывались на проигравшей стороне в спорах об архитектуре ПО. Люди обычно используют их лишь для оправдания решений (в особенности бездействия), принятых по другим причинам.
Спасибо Саре Харлин, Тревору Блэквеллу и Дэну Гиффину за прочтение черновиков этой статьи, и еще раз Дэну — за большую часть инфраструктуры, на которой работает этот фильтр.
Связанные статьи: