惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
雷峰网
雷峰网
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Spread Privacy
Spread Privacy
H
Hacker News: Front Page
PCI Perspectives
PCI Perspectives
Webroot Blog
Webroot Blog
罗磊的独立博客
H
Heimdal Security Blog
TaoSecurity Blog
TaoSecurity Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
大猫的无限游戏
大猫的无限游戏
月光博客
月光博客
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Google Online Security Blog
Google Online Security Blog
Last Week in AI
Last Week in AI
美团技术团队
Help Net Security
Help Net Security
The Hacker News
The Hacker News
C
Cisco Blogs
T
The Blog of Author Tim Ferriss
J
Java Code Geeks
The Register - Security
The Register - Security
IT之家
IT之家
WordPress大学
WordPress大学
Jina AI
Jina AI
Recent Commits to openclaw:main
Recent Commits to openclaw:main
H
Help Net Security
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Threat Research - Cisco Blogs
P
Proofpoint News Feed
NISL@THU
NISL@THU
爱范儿
爱范儿
The GitHub Blog
The GitHub Blog
Scott Helme
Scott Helme
V
Vulnerabilities – Threatpost
B
Blog
T
Tenable Blog
博客园 - 三生石上(FineUI控件)
T
The Exploit Database - CXSecurity.com
S
Security Affairs
小众软件
小众软件
Hacker News: Ask HN
Hacker News: Ask HN
Security Latest
Security Latest
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
W
WeLiveSecurity
A
Arctic Wolf
L
LINUX DO - 热门话题
Google DeepMind News
Google DeepMind News
M
MIT News - Artificial intelligence

SumSec's Blog

AI Agent 工程的必然演进:CLI、Skills、Harne… 从安全角度谈Java反射机制--前章 · SUMSEC 从安全角度谈Java反射机制--终章 · SUMSEC 逆向学习fastjson反序列化始 · SUMSEC 2020年研究回顾总结 · SUMSEC Abstract syntax tree classes for … Analyzing data flow in Java · SUM… Annotations in Java · SUMSEC Basic query for Java code · SUMSEC BypassSuper使用介绍说明 · SUMSEC CodeQL Create OpenJdk/Jdk8 Databa… CodeQL library for Java · SUMSEC Navigating the call graph · SUMSEC Overflow-prone comparisons in Jav… Types in Java · SUMSEC Working with source locations · S… Aliases · SUMSEC Expression · SUMSEC Formulas · SUMSEC Javadoc · SUMSEC Modules · SUMSEC Predicates · SUMSEC Queries · SUMSEC Type · SUMSEC Variables · SUMSEC 一道shiro反序列化题目引发的思考 · SUMSEC 修改ysoserial使其支持任意代码执行 · SUMSEC 自定义 ClassLoader 隔离运行不同版本jar包的方式 ·… 2020网鼎杯---Java文件上传wp · SUMSEC CNVD-2020-10487(CVE-2020-1938)tom… JDSRC安全课笔记 · SUMSEC Java反序列化链回显解决方案 · SUMSEC Skipped breakpoint because it hap… Windows Terminal 配置文件 · SUMSEC bypass 学习笔记之绕安全狗bypass safedog · … 一次意外的代码审计----JfinalCMS审计 · SUMSEC 一篇文章读懂Java代码审计之XXE · SUMSEC 从安全角度谈Java反射机制--序章 · SUMSEC 小楼昨夜又春风,你知ysoserial-Gadget-URLDNS… 春眠不觉晓,RCE知多少? · SUMSEC 漫谈Commons-Collections反序列化 · SUMSEC 漫谈Java反序列化 · SUMSEC 白头搔更短,SSTI惹人心! · SUMSEC 记一次面试题 · SUMSEC About Me 关于我 · SUMSEC Apache Flink任意Jar包上传导致远程代码执行 · SU… CVE-2019-1388 UAC提权复现 · SUMSEC CVE-2019-16097 || Harbor任意管理员注册漏洞… Python加密shellcode免杀 · SUMSEC Telegram机器人作为渗透测试框架 · SUMSEC VM虚拟机无法安装vmtools解决|本程序需要您将此虚拟机上安装… 谁能想到,电视遥控器竟成了 Vibe Coding 神器 · SU… 从手改 Skill 到自动进化:评测结果和执行轨迹如何让 Agen… 模型人人都能用,什么才是你能带走的?我的答案是一个可进化的SKIL… 模型人人都能用,什么才是你能带走的?我的答案是一个可进化的Skil… AI 时代 ShiroAttack2 5.x:修改了什么 · SU… 在 AGI 降临前,先给 AI 开一条”脑内弹幕”通道 · SUM… 一篇博文,三种时间:网页幻灯与 Remotion 动效的交付逻辑 … 🔍 别让大模型”想太多”:SKILL开发中的语义陷阱与抗幻觉设计 … 2022 年年度总结 · SUMSEC Java Swing To RCE 漏洞分析 · SUMSEC SpringBoot GatewayEL表达式漏洞分析 · SUM… Sensitive keys in codebases · SUM… 论如何优雅注入 Java 内存马 · SUMSEC SUMSEC 知识点 · SUMSEC VMWare Workspace ONE Access Auth … Spring Framework RCE CVE-2022-229… CVE-2022-33891 Apache Spark shell… 正则匹配配置不当 · SUMSEC Spring Data MongoDB SpEL CVE-2022… CodeQl Usage Tricks · SUMSEC Spring Boot RCE到内存马探索 · SUMSEC Shiro后渗透拓展面 · SUMSEC shiro反序列化漏洞攻击拓展面–修改key · SUMSEC GitHub Java CodeQL CTF · SUMSEC Hack-Tools 转化成Web · SUMSEC CodeQL与Shiro550碰撞 · SUMSEC CodeQL初见Shiro550 · SUMSEC CodeQL与AST之间联系 · SUMSEC Java加载动态链接库 · SUMSEC Log4j2 漏洞分析 · SUMSEC Interprocedural-Analysis 过程间分析 · … Data Analysis Foundation 数据分析基础 ·… Data Flow Analysis · SUMSEC Intermediate Representation 中间代表(… PII泄露–用CodeQL识别日志中的PII数据 · SUMSEC CodeQL workshop for Java: Unsafe … 前言 · SUMSEC 漏洞环境的搭建 · SUMSEC Fastjson回显 · SUMSEC Tomcat通用回显学习笔记 · SUMSEC 从Java反序列化漏洞题看CodeQL数据流 · SUMSEC 概述 · SUMSEC 记一次Log4j失败的Gadget挖掘记录 · SUMSEC Ysoserial改造记录 · SUMSEC JNDI注入 · SUMSEC shiro JRMP gadget · SUMSEC Fastjson MySQL gadget复现 · SUMSEC 2021年度总结 · SUMSEC
相似度算法调研 · SUMSEC
2023-01-09 · via SumSec's Blog

相似度算法调研

前言

相似度算法故名思义,就是判断两个件事物是否是存在相似相似性,通常我们比较多是一些字符串、文本文件。相似度算法其实很多都使用过,很经典的案例毕业论文全网匹配相似度,也就是我们常说的查重。

对两个较短的字符串,我们在人工判断是否具有相似性的时候,通常很快就能做出判断。

For Example:

我是中国人,在中国生活!

我是美国人,在美国生活!

这两个句话,就只存在两个字的差异。大家可以试着想想如何判断这两句是否相似的?

  • 首先很容易想到的是统计字符不同个数的数量,在计算不同的字符串在整个字符串的占比,最终得到相似度。

但如果使用统计字符串的方式很容易就在一些特定的语意的情况下很容易产生较大的差异的,比例说:

在中国,每一个人爱着国家。

中秋节,每一个人爱吃月饼。

在这情况下使用统计字符串的方式就可能误报了太大了,但这种情况在本文中不考虑,这属于是自然语言处理的范围,这个领域在全球都是还是一个比较难的研究课题。


相似度算法介绍

莱文斯坦-编辑距离(Levenshtein)

编辑距离(Minimum Edit Distance,MED),由俄罗斯科学家 Vladimir Levenshtein 在1965年提出,也因此而得名 Levenshtein Distance。

编辑距离的本质思想就是将两个中的一个字符串转化成另一个字符串最少需要编辑单个字符的个数。譬如,”kitten” 和 “sitting” 这两个单词,由 “whoami” 转换为 “whoiam” 需要的最少单字符编辑操作有:

  1. whoami → whoimi (substitution of “a” for “i”)
  2. whoimi → whoiai (substitution of “m” for “a”)
  3. whoiai → whoiam (substitution of “i” for “m” at the end)

因此,”whoami”和”whoiam”的编辑距离为3。

表示为 ![lev_{a,b}( a , b )](https://math.jianshu.com/math?formula=lev_%7Ba%2Cb%7D(%7Ca%7C%2C%20%7Cb%7C))

实现算法:

我们将两个字符串a,b 的 Levenshtein Distance 表示为![lev_{a,b}( a , b )](https://math.jianshu.com/math?formula=lev_%7Ba%2Cb%7D(%7Ca%7C%2C%20%7Cb%7C)) ,其中![ a ](https://math.jianshu.com/math?formula= a ) 和 ![ b ](https://math.jianshu.com/math?formula=%7Cb%7C) 分别对应 a,b 的长度。那么,在这里两个字符串a,b 的 Levenshtein Distance,即![lev_{a,b}( a , b )](https://math.jianshu.com/math?formula=lev_%7Ba%2Cb%7D(%7Ca%7C%2C%20%7Cb%7C)) 可用如下的数学语言描述:

img

1. 定义 lev_{a,b}(i, j) 指的是 ai 个字符bj 个字符之间的距离。为了方便理解,这里的i,j可以看作是a,b的长度。这里的字符串的第一个字符 index 从 1 开始(实际因为在表上运算的时候字符串前需要补 0),因此最后的编辑距离便是 i = |a|, j = |b| 时的距离: lev_{a,b}(|a|, |b|)

2. 当 min(i, j) = 0 的时候,对应着字符串ai 个字符和 字符串bj 个字符,此时的 i,j 有一个值为 0 ,表示字符串 a 和 b 中有一个为空串,那么从 a 转换到 b 只需要进行max(i, j)次单字符编辑操作即可,所以它们之间的编辑距离为 max(i, j),即 i, j 中的最大者。

3. 当 min(i, j) \ne 0 的时候,lev_{a,b}(|a|, |b|) 为如下三种情况的最小值:
1.lev_{a,b}(i-1, j) + 1 表示 删除 a_i
2.lev_{a,b}(i, j-1) + 1 表示 插入 b_j
3.lev_{a,b}(i-1, j-1)+1_{(a_i \ne b_j)} 表示 替换 b_j

1_{(a_i \ne b_j)} 为一个指示函数,表示当 a_i = b_j 的时候取 0 ;当 a_i \ne b_j 的时候,其值为 1。


Hamming

两个等长字符串之间的汉明距离是两个字符串对应位置的不同字符的个数。换句话说,它就是将一个字符串变换成另外一个字符串所需要替换的字符个数。例如:

1011101 与 1001001 之间的汉明距离是 2。

2143896 与 2233796 之间的汉明距离是 3。

“toned” 与 “roses” 之间的汉明距离是 3。

最简单汉明算法实现

func (h *Hamming) CompareUtf8(utf8Str1, utf8Str2 string) float64 {
	count := 0

	l1 := utf8.RuneCountInString(utf8Str1)
	max := l1

	l2 := utf8.RuneCountInString(utf8Str2)
	if max < l2 {
		max = l2
	}

	for i, j := 0, 0; i < len(utf8Str1) && j < len(utf8Str2); {
		size := 0
		r1, size := utf8.DecodeRune(StringToBytes(utf8Str1[i:]))
		i += size

		r2, size := utf8.DecodeRune(StringToBytes(utf8Str2[j:]))
		j += size

		if r1 != r2 {
			count++
		}

	}

	return 1 - (float64(count)+math.Abs(float64(l1-l2)))/float64(max)
}

Dice’s coefficient


Jaro

1、Jaro distance/similarity 对于两个字符串s1和s2,它们的Jaro 相似度算法由下面公式给出:

img

其中: ①|s1|和|s2|表示字符串s1和s2的长度。 ②m表示两字符串的匹配字符数。 ③t表示换位数目transpositions的一半。

m的计算表达式为:

img


JaroWinkler

Jaro-Winkler similarity是在Jaro similarity的基础上,做的进一步修改,在该算法中,更加突出了前缀相同的重要性,即如果两个字符串在前几个字符都相同的情况下,它们会获得更高的相似性。该算法的公式如下:

img

其中: ①simj 就是刚才求得的Jaro similarity。 ②l表示两个字符串的共同前缀字符的个数,最大不超过4个,取值范围[0,4]。 ③p是缩放因子常量,它描述的是共同前缀对于相似度的贡献,p越大,表示共同前缀权重越大,最大不超过0.25。p默认取值是0.1


Cosine

余弦相似度,相关原理就是高中学过的空间向量定理,两个向量夹角的角度。但余弦相似度得计算词出现频率,如果用分词的效率不高,并且计算量,内存开销都会很大。于是我想到采用base64编码的方式,因为base64编码的字符串同一个字符是相同的,也等价的计算词语出现的频率。然后将base64标准字符串进行余弦计算。

img


SimHash

传统的Hash算法只负责将原始内容尽量均匀随机地映射为一个签名值,原理上仅相当于伪随机数产生算法。传统的hash算法产生的两个签名,如果原始内容在一定概率下是相等的;如果不相等,除了说明原始内容不相等外,不再提供任何信息,因为即使原始内容只相差一个字节,所产生的签名也很可能差别很大。所以传统的Hash是无法在签名的维度上来衡量原内容的相似度,而SimHash本身属于一种局部敏感哈希算法,它产生的hash签名在一定程度上可以表征原内容的相似度。

  我们主要解决的是文本相似度计算,要比较的是两个文章是否相识,当然我们降维生成了hash签名也是用于这个目的。看到这里估计大家就明白了,我们使用的simhash就算把文章中的字符串变成 01 串也还是可以用于计算相似度的,而传统的hash却不行。我们可以来做个测试,两个相差只有一个字符的文本串,“你妈妈喊你回家吃饭哦,回家罗回家罗” 和 “你妈妈叫你回家吃饭啦,回家罗回家罗”。

  通过simhash计算结果为:

  1000010010101101111111100000101011010001001111100001001011001011

  1000010010101101011111100000101011010001001111100001101010001011

  通过传统hash计算为:

  0001000001100110100111011011110

  1010010001111111110010110011101

  大家可以看得出来,相似的文本只有部分 01 串变化了,而普通的hash却不能做到,这个就是局部敏感哈希的魅力。

​ SimHash的难点感觉是在分词和加权,分词处理之后,加权操作目前没有很好的解决方法。分词的话,如果是中英文的都有的情况也很难处理,比例说网页的源代码。对于分词这部分,我目前简单将文本进行base64编码,然后将粗暴的以四个字符分为一组。对于加权这块,我是统计每组出现的概率进行加权。


总结

​ 本节主要是讨论一下相似度算法的实现算法,目前本来中所有的算法都均已开源到GitHub,仓库地址 https://github.com/antlabs/strsim 。这个仓库并不是我的,我只是一个贡献者,目前算法的实现还没有结果大量测试,欢迎大家讨论并提出改进算法想法💡。


参考

  • https://github.com/antlabs/strsim/issues/1
  • https://www.jianshu.com/p/a617d20162cf
  • https://www.jianshu.com/p/a4af202cb702
  • https://www.geeksforgeeks.org/jaro-and-jaro-winkler-similarity/?ref=lbp
  • https://www.cnblogs.com/sddai/p/10088007.html