持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第19天,点击查看活动详情
前言
在昨天的文章中,使用抓取的漏洞数据,我们将括公司【company】、产品【product】、版本【version】、影响版本【influence】、CVE编号【cve_number】、漏洞类型【type】等多个节点进行导入,并以公司为核心进行了简单的图谱创建,但是实际效果还有些差异,一个是并没有导入全量数据,此外还有漏洞类型节点冗余,因为对于每一个CVE编号有需要记录漏洞类型,因此会有大量重复数据。因此今天将要对数据结构进行优化,并插入更多的数据进行功能测试。
现存的问题
可见一个厂商包含多个产品,一个产品可能包含多个漏洞,并且漏洞编号关联版本信息感觉略有些混乱,并且漏洞类型节点不是很直观,一个CVE编号节点包含多个漏洞类型,如图中黄色节点部分,都为应用,或者一个应用一个系统,无法判断漏洞的具体信息,此外原始信息中还包含应对措施等信息,这种长文本信息在图结构中很难展示,因此对现有问题进行总结
- 漏洞类型、影响版本不够直观,如大量的未知等
- 漏洞的详细信息无法展示,如漏洞描述、漏洞应对措施等等
- 跳数太多,导致图片展示过为复杂
解决方案
- 针对以上问题,一个是漏洞类型以及影响版本不在图数据库中存在,而是采用ES或者Mysql或者Redis形式存储
- 漏洞的详细信息在未来前端设计中将采用右侧弹框等形式展示,图数据库中不再进行存储
- 图中只展示两跳,点击之后进入第三跳
代码修改
首先清空之前的图数据库:
match (n) detach delete n
修改之后的代码如下:
import codecs
from py2neo import NodeMatcher
from connectUtils import connect2Neo4J
def cleanData(tempList):
returnList = []
for item in tempList:
itemDict = {}
type = item[0]
company = item[1]
product = item[2]
version = item[3]
influence = ' '.join(item[4:]).replace("From"," ").replace("(including)"," ").replace("(excluding)"," ").replace("Up to"," ").replace("-"," ").split()
influence = '-'.join([item for item in influence if item != ""])
itemDict["type"] = type
itemDict["company"] = company
itemDict["product"] = product
itemDict["version"] = version
itemDict["influence"] = influence
returnList.append(itemDict)
return returnList
def loadData():
lines = codecs.open("aliyunSpider.txt",'r','utf-8').readlines()
node_matcher = NodeMatcher(connect.conn)
for line in lines:
try:
json_line = eval(line.strip())
print(json_line["solution"])
print(cleanData(json_line["data"]))
cve_number = (json_line["cve_number"])
print(json_line["href"])
for item in cleanData(json_line["data"]):
company = item["company"]
product = item["product"]
companyData = node_matcher.match("company").where(name=company)
print(list(companyData))
if (len(list(companyData)) != 0):
companyNode = companyData.first()
productData = node_matcher.match("product").where(name=product)
if (len(list(productData)) != 0):
productNode = productData.first()
connect.creatRelationship(companyNode, productNode, "拥有")
else:
productNode = connect.creatNode("product", product)
connect.creatRelationship(companyNode, productNode, "拥有")
cveData = node_matcher.match("cvenumberNode").where(name=cve_number)
if (len(list(cveData)) != 0):
cvenumberNode = cveData.first()
connect.creatRelationship(productNode,cvenumberNode,"暴露漏洞")
else:
cvenumberNode = connect.creatNode("cvenumberNode", cve_number)
connect.creatRelationship(productNode,cvenumberNode,"暴露漏洞")
else:
companyNode = connect.creatNode("company",company)
productNode = connect.creatNode("product", product)
cvenumberNode = connect.creatNode("cvenumberNode", cve_number)
connect.creatRelationship(companyNode,productNode,"拥有")
connect.creatRelationship(productNode,cvenumberNode,"暴露漏洞")
except Exception as e:
print(e)
if __name__ == '__main__':
connect = connect2Neo4J()
loadData()
其中数据库连接类的代码不变,逻辑依旧是读取数据,并通过eval将数据转为json形式,进而处理数据将influence进行数据清洗,清洗后的数据通过之前文章中的neo4j公共类进行数据插入操作,对于公司不存在的节点,创建公司节点、创建CVE编号节点、创建产品类型节点,而对于公司存在的情况下,则判断公司、产品、CVE编号节点是否存在,如果存在则先查询节点,之后建立关系。
大批量数据插入
漏洞数据共计10W+余条,因此对数据插入的操作比较缓慢,可以先预览一些截图。
其中红色节点代表公司,绿色节点代表产品,而棕色节点代表CVE编号,由图中可见,多个产品可能同时暴露出同一个漏洞,因此从图谱中看待漏洞数据可以从另一个维度看产品所产生的漏洞分布以及关联情况。这是文本或者结构化数据不能够直观展示的。
而从这张图可以看出,部分漏洞对于厂商的产品影响范围极广,涵盖了各种产品,因此漏洞的影响面也是比较大的。
今天的文章对数据进行了处理并做了数据的重写插入,明天将通过不同的查询语句查询结果,为之后的接口做准备,蟹蟹~