38

如何检测(使用正则表达式或启发式)文本字符串(如评论)中的网站链接?

目的是防止垃圾邮件。HTML 被剥离,所以我需要检测复制和粘贴的邀请。 垃圾邮件发送者发布链接应该不经济,因为大多数用户无法成功访问该页面。我想要关于最佳实践的建议、参考或讨论。

一些目标:

  • 像格式良好的 URL 一样容易实现的目标 ( http://some-fqdn/some/valid/path.ext)
  • URL 但没有http://前缀(即有效的 FQDN + 有效的 HTTP 路径)
  • 任何其他有趣的事情

当然,我正在阻止垃圾邮件,但是可以使用相同的过程来自动链接文本。

想法

这是我在想的一些事情。

  • 内容是母语散文,所以我可以在检测中触发快乐
  • 我应该先去掉所有空格来捕捉“ www .example.com”吗?普通用户会知道自己删除空间,还是让任何浏览器“按我的意思做”并为您剥离它?
  • 也许多次传球是一个更好的策略,扫描:
    • 格式正确的 URL
    • 所有非空格后跟“。” 后跟任何有效的 TLD
    • 还要别的吗?

相关问题

我已经阅读了这些内容,它们现在记录在此处,因此您可以根据需要在这些问题中引用正则表达式。

更新和总结

哇,我在这里列出了一些非常好的启发式方法!对我来说,最划算的是以下几点的综合:

  1. @Jon Bright 的 TLD 检测技术(一个很好的防御瓶颈)
  2. 对于那些可疑的字符串,按照@capar 将点替换为点状字符
  3. @Sharkey 的下标 · 是一个不错的点状字符。(即“ · ”)。· 也是一个单词边界,因此很难随意复制和粘贴。

这应该使垃圾邮件发送者的每千次展示费用足够低以满足我的需求;“标记为不适当”的用户反馈应该可以捕捉到其他任何东西。列出的其他解决方案也非常有用:

  • 去掉所有虚线四边形(@Sharkey 对他自己的回答的评论)
  • @Sporkmonger 对客户端 Javascript 的要求,它将所需的隐藏字段插入到表单中。
  • ping URL 服务器端以确定它是否是一个网站。(也许我可以通过 SpamAssassin 或其他贝叶斯过滤器按照@Nathan 运行 HTML ..)
  • 查看 Chrome 智能地址栏的来源,看看 Google 使用了哪些巧妙的技巧
  • 调用 OWASP AntiSAMY 或其他 Web 服务进行垃圾邮件/恶意软件检测。
4

13 回答 13

19

我将我的答案集中在试图避免垃圾邮件发送者上。这导致了两个子假设:因此,使用该系统的人将积极尝试违反您的检查,而您的目标只是检测 URL 的存在,而不是提取完整的 URL。如果你的目标是别的东西,这个解决方案看起来会有所不同。

我认为您最好的选择是使用 TLD。有两个字母的 ccTLD 和(当前)相对较小的其他列表。这些需要以点为前缀,并以斜杠或某些单词边界为后缀。正如其他人所指出的,这不会是完美的。如果不禁止合法的“我再试一次。它不起作用”或类似的话,就无法获得“buyfunkypharmaceuticals .it”。综上所述,这将是我的建议:

[^\b]\.([a-zA-Z]{2}|aero|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel)[\b/]

这将得到的东西:

  • 购买funkypharmaceutical s.it
  • 歌电子商务
  • http://stackoverflo **w.com/**questions/700163/

一旦人们开始混淆他们的 URL,它当然会中断,替换“。” 用“点”。但是,再次假设垃圾邮件发送者是您的目标,如果他们开始做这种事情,他们的点击率将再下降几个数量级,趋向于零。我认为,有足够信息可以对 URL 进行去混淆处理的一组人,以及一组不知道足以访问垃圾邮件站点的人,有一个微不足道的交集。此解决方案应让您检测到所有可复制粘贴到地址栏的 URL,同时将附带损害降至最低。

于 2009-04-15T12:15:07.390 回答
6

我不确定使用正则表达式检测 URL 是否是解决此问题的正确方法。通常你会错过一些不为人知的边缘情况,如果垃圾邮件发送者有足够的动机,他们就可以利用这些情况。

如果您的目标只是从评论中过滤垃圾邮件,那么您可能需要考虑贝叶斯过滤。事实证明,它在将电子邮件标记为垃圾邮件方面非常准确,它可能也能为您做同样的事情,具体取决于您需要过滤的文本量。

于 2009-04-14T03:10:11.140 回答
6

我知道这对自动链接文本没有帮助,但是如果您搜索并用看起来相同的字符替换所有句号,例如希伯来语点 hiriq (U+05B4) 的 unicode 字符,该怎么办?

以下段落是一个示例:

这可能会工作ִ句号看起来有点奇怪,但仍然可读ִ当然好处是任何人复制和粘贴 wwwִgoogleִcom 都不会太远ִ :)

于 2009-04-15T02:39:28.943 回答
4

嗯,很明显,低垂的果实是以 http:// 和 www 开头的东西。试图过滤掉诸如“www.g mail.com”之类的东西会导致关于你想走多远的有趣的哲学问题。你想采取下一步并过滤掉“www dot gee mail dot com”吗?URL 的抽象描述怎么样,例如“万维网的缩写,后跟一个点,后跟字母 g,后跟单词 mail,后跟一个点,以商业 TLD 缩写结尾”。

在继续尝试设计算法之前,划清您将要尝试过滤的类型的界限很重要。我认为应该在“gmail.com”被视为网址的级别划线,但“gmail.com”不是。否则,每次有人未能将句子中的第一个字母大写时,您都可能会得到误报。

于 2009-04-14T20:09:09.067 回答
3

由于您主要是在寻找复制并粘贴到浏览器地址栏中的邀请,因此可能值得查看开源浏览器(例如 Chrome 或 Mozilla)中使用的代码,以确定是否输入“地址栏”的文本等效”是搜索查询或 URL 导航尝试。

于 2009-04-15T12:55:59.273 回答
2

ping 可能的 URL

如果您不介意一点服务器端计算,那么像这样的东西呢?

urls = []
for possible_url in extracted_urls(comment):
    if pingable(possible_url):
       urls.append(url)  #you could do this as a list comprehension, but OP may not know python

这里:

  1. extract_urls 接受评论并使用保守的正则表达式提取可能的候选者

  2. pingable 实际上使用系统调用来确定主机名是否存在于网络上。你可以有一个简单的包装器来解析 ping 的输出。

    [ramanujan:~/base]$ping -c 1 www.google.com

    PING www.l.google.com (74.125.19.147):来自 74.125.19.147 的 56 个数据字节 64 个字节:icmp_seq=0 ttl=246 time=18.317 ms

    --- www.l.google.com ping 统计 --- 1 个数据包传输,1 个数据包接收,0% 数据包丢失往返 min/avg/max/stddev = 18.317/18.317/18.317/0.000 ms

    [ramanujan:~/base]$ping -c 1 fooalksdflajkd.com

    ping:无法解析 fooalksdflajkd.com:未知主机

不利的一面是,如果主机提供 404,您将无法检测到它,但这是一个相当不错的第一步——验证地址是否为网站的最终方法是尝试导航到该地址。您也可以尝试获取该 URL,但这是更重量级的。

于 2009-04-18T07:01:36.507 回答
1

在多次尝试编写这段代码之后,我可以明确地说,您将无法绝对可靠地执行此操作,并且您当然无法检测到 RFC 允许的所有 URI 形式。幸运的是,由于您感兴趣的 URL 集非常有限,您可以使用上述任何技术。

但是,我可以非常肯定地说的另一件事是,如果您真的想击败垃圾邮件发送者,那么最好的方法就是使用 JavaScript。发送一段 JavaScript 执行一些计算,然后在服务器端重复计算。JavaScript 应该将计算结果复制到隐藏字段,以便在提交评论时也提交计算结果。在服务器端验证计算是否正确。绕过此技术的唯一方法是让垃圾邮件发送者手动输入评论,或者让他们开始为您运行 JavaScript 引擎。我使用这种技术将我网站上的垃圾邮件从每天 100 多封减少到每年一到两封。现在我收到的唯一垃圾邮件是人工输入的。收到主题垃圾邮件很奇怪。

于 2009-04-15T12:41:25.737 回答
1

当然,您意识到如果垃圾邮件发送者决定使用 tinuyrl 或此类服务来缩短他们的 URL,您的问题只会变得更糟。在这种情况下,您可能需要编写一些代码来查找实际的 URL,使用像TinyURL解码器这样的服务

于 2009-04-15T12:42:04.127 回答
1

考虑合并 OWASP AntiSAMY API...

于 2009-04-18T12:07:10.157 回答
1

到目前为止,我最喜欢capar的答案,但是处理 unicode 字体可能有点麻烦,旧版浏览器通常会显示一个有趣的东西或一个小框……而且 U+05B4 的位置有点奇怪。 .. 对我来说,它出现在管道之外 |ִ| 即使在他们之间。

有一个方便的· (·) 但是,它以相同的方式中断剪切和粘贴。它的垂直对齐可以通过 <sub>ing 来纠正,例如:

堆栈溢出· com

反常,但无论如何在FF3中有效,它不能被剪切和粘贴为URL。<sub> 实际上非常好,因为它使 URL 无法粘贴的原因在视觉上很明显。

不在可疑 URL 中的点可以单独放置,例如,您可以这样做

s/\b\.\b/<sub>&middot;<\/sub>/g

另一种选择是在可疑点旁边插入某种零宽度实体,但像 ‍ 这样的东西 ‌ 和 &zwsp; 似乎在FF3中不起作用。

于 2009-04-19T05:00:54.497 回答
1

这里已经有一些很好的答案,所以我不会再发布更多。不过,我会给出几个问题。首先,确保测试已知的协议,其他任何东西都可能是淘气的。作为一个爱好 telnet 链接的人,您可能希望在搜索中包含更多的 http(s),但可能希望阻止说 aim: 或其他一些 url。其次,很多人会用尖括号 (gt/lt) 来界定他们的链接,比如 < http://theroughnecks.net > 或括号“(url)”,没有什么比点击链接更糟糕的了> 或 ) 与 URL 的其余部分一起使用。

PS对自参考插头感到抱歉;)

于 2009-04-19T05:38:45.060 回答
0

假设给定协议或“www”前缀,我只需要检测带有/out 协议的简单 http url。我发现上面提到的链接很有帮助,但最后我得出了这个:

http(s?)://(\S+\.)+\S+|www\d?\.(\S+\.)+\S+

显然,这并不能测试是否符合 dns 标准。

于 2018-04-24T12:48:26.020 回答
0

鉴于我在 Disqus 评论垃圾邮件中看到的类似字符形式的“其他有趣的业务”的混乱,你要做的第一件事就是处理它。

幸运的是,Unicode 人员为您提供了帮助。在您选择的编程语言中挖掘用于 Unicode 易混淆的 TR39 骨架算法的实现,并将其与一些 Unicode 规范化和 Unicode 感知的大写/小写匹配。

骨架算法使用由 Unicode 人员维护的查找表来做一些概念上类似于大小写折叠的事情。

(输出可能没有使用合理的字符,但是,如果你将它应用到比较的两边,如果字符在视觉上足够相似,足以让人类理解意图,你就会得到匹配。)

下面是这个 Java 实现的一个例子:

// Skeleton representations of unicode strings containing 
// confusable characters are equal 
skeleton("paypal").equals(skeleton("paypal")); // true
skeleton("paypal").equals(skeleton("ỿℓ")); // true
skeleton("paypal").equals(skeleton("ρ⍺уן")); // true
skeleton("ρ⍺уן").equals(skeleton("ỿℓ")); // true
skeleton("ρ⍺уן").equals(skeleton("ỿℓ")); // true

// The skeleton representation does not transform case
skeleton("payPal").equals(skeleton("paypal")); // false

// The skeleton representation does not remove diacritics
skeleton("paypal").equals(skeleton("pàỳpąl")); // false

(如您所见,您需要先进行一些其他规范化。)

鉴于您正在执行 URL 检测以判断某些内容是否为垃圾邮件,这可能是一种不常见的情况,可以安全地开始将 Unicode 规范化为 NFKD,然后剥离声明为组合字符的代码点。

(然后,您需要在将案例提供给骨架算法之前对其进行规范化。)

我建议您执行以下操作之一:

  1. 编写代码以在字符分解之前和之后运行混淆检查,以防在分解之前而不是之后被认为是可混淆的,并检查大写和小写的字符串,以防混淆表在大写和小写形式。
  2. 通过编写一个小脚本来检查 Unicode 表并确定分解或小写/大写一对字符是否会改变的任何代码点,从而调查 #1 是否真的是一个问题(如果不是,则无需浪费 CPU 时间)认为相互混淆。
于 2019-07-12T12:58:08.507 回答