2017年,阿里云启动MVP(Most Valuable Professional)项目。顾名思义,MVP正在寻找阿里云最有价值专家,那些能够,并且愿意帮助他人,充分了解和使用阿里云技术的意见领袖。
本文是阿里云MVP 傅奎的实践分享,今天和大家讲讲 “安全态势,交互发现 —— 基于阿里云轻松搭建安全大屏 ”
一句话概述
使用DataV大屏展现态势感知 DNS 会话日志,从而实现交互式安全威胁发现。
剧透一下最终效果,绝对值得试试:
所有 DNS 日志的节点(源地址、DNS服务器地址、要解析的域名)关系图。点选其中任一节点,关联点自动高亮,非关联节点则进入蒙版状态,要是有什么可疑的节点、关系、类目,一眼就看出来!
背景介绍
自打“态势感知”上线了新版的“日志”功能,团队成员就在摩拳擦掌寻思如何充分挖掘日志信息的价值,而不仅仅是用于故障诊断或事件调查。其中,通过图形化展现不同网络资源节点的相互关系,进而实现交互式安全威胁发现,是最为理想的实现方式。此前尝试过 Graphviz、yEd、NetworkX 等方式,后来都因配置复杂,使用繁琐等问题放弃。
直到MVP 技术群里李文毅向大家推荐了 DataV,我想:是时候“make it true ”了!
产品介绍
以下材料援引自官方介绍,描述不准与我无关:
“态势感知提供的是一项SAAS服务,即在大规模云计算环境中,对那些能够引发网络安全态势发生变化的要素进行全面、快速和准确地捕获和分析,并提供一个体系化的安全解决方案。”
“DataV旨让更多的人看到数据可视化的魅力,帮助非专业的工程师通过图形化的界面轻松搭建专业水准的可视化应用。DataV提供丰富的可视化模板,满足您会议展览、业务监控、风险预警、地理信息分析等多种业务的展示需求。”
需求分析
态势感知的日志功能非常强大,目前支持查询:所有入站的7层数据、出入站栈的4层会话以及DNS双向日志。其中 DNS 日志有助于安全团队分析服务器是否遭受入侵,被植入木马病毒,存在异常请求等问题。
我们最关心的是:哪台服务器,通过哪个 DNS Server,解析了哪个域名?
针对该需求,如果有可视化的节点关系图辅助分析,那么威胁识别的效率将大幅提升。在没有使用 DataV 之前,通常的办法是使用一些图表工具进行展现,而且少不了定制化开发的工作量。DataV 的出现,大大解放了数据分析人员的双手,从而可以用于拖动进度条。仅仅通过少量的鼠标点击和基本的 API 配置,就能瞬间让你的数据充满活力,开口说话。DataV 自带节点关系图,并内嵌原生ECharts ,完全可以满足此类需求。
实现方法
你一定很期待强劲的态势感知与性感的 DataV强强联合会是什么样子。期待不如行动,我们一起动手去实现吧。
导出态势感知 DNS 日志
登录阿里云控制台,进入安全(云盾)|态势感知
功能页,通过子菜单选择日志 new
项目。
设置DNS 日志查询条件,分别是:
- 日志源:DNS
- 字段:qtype
- 判断条件:包含(目前只能选包含)
- 关键字:A
再设置好查询时间,点击搜索
就可以啦。
系统很快就能返回查询结果,通过右上角导出结果
将当前页(没错,,是当前页,,一次100条-_-)日志导出到Excel 中。如果需要更多数据,得依次翻页导出-_-。当然也有程序化解决方案,请往后看。
定制返回 JSON 串的数据源API
对导出的 Excel 文件进行数据抽取,关键是:
- 源地址:src_ip
- DNS Server:dst_ip
- 尝试解析的域名:qname
将源地址、DNS 地址、域名三项都纳入节点范畴,同时将源地址->DNS 地址、DNS 地址->域名纳入关系范畴,通过 HTTP 将节点 nodes 和关系 links 输出为 JSON 就是一个可用的API数据输入源。
别着急,作为良心分享,怎么能少了技术细节呢?为了不影响阅读,我把数据格式化和 API 相关的具体内容放在后面环节。
定制 DataV 大屏,指定 API 数据源
通过阿里云控制台大数据(数加)|DataV数据可视化
进入定制界面,直接选择新建可视化
。
创建大屏模板,设置一个你喜欢的名字。
向大屏图层添加数据展示组件, 这里可以选择关系网络或原生的 Echarts 网络图。
点选图表组件,进入右侧数据
选项卡,修改默认的数据源类型静态数据
为 API
。
填写满足系统要求的 API,如:http://www.test.com/datav.json
,鼠标离开输入框,左侧设计区会即时展现效果。
发布监控大屏,看效果
数据调试和预览成功后,可通过右上角的发布
按钮,正式发布报表。DataV 考虑得很周到,为报表提供了密码和 Token 两种安全保护机制。
访问发布后的报表链接:http://datav.aliyun.com/share/ef9aa**********a3fd8(这是他们的秘密不可访问的哈)
交互式发现
好吧,放一些我在测试环境模拟出来的数据。下面是一段时间内,所有 DNS 日志的节点(源地址、DNS服务器地址、要解析的域名)关系图。
点选其中任一节点,关联点自动高亮,非关联节点则进入蒙版状态,相当炫酷啊!
来,再看另外一组测试数据。要是有什么可疑的节点、关系、类目,一眼就看出来!
小提示:万一发现了什么神奇的域名或 IP 地址,可以直接上微步威胁情报查询,例如:https://x.threatbook.cn/domain/google.com。是不是坏人立即遁形,这个库太全了……
补充说明
替你踩过的坑
- 如果不打算使用
服务器代理
方式调用API,那么一定要设置好 API 的 HTTP 头部跨域参数 - 如果使用了 HTTPS 访问DataV 监控大屏,那么 API 接口也必须是 HTTPS 形式
- API 接口返回的数据要和静态数据输入框中的格式完全一样——JSON 串
- 如果你遇到了一些神奇的 Bug,请把图层或组件删除后从头再来一遍(不要问我怎么知道的)
- DataV 自带的关系图和内嵌的原生 ECharts 在数据格式上有一定的区别,要看仔细
Show you the code
下面这段代码可以帮助使用者在登录态势感知后,自动获取 DNS 会话日志,并按照 DataV 关系图所适配的数据格式生成 JSON 串。非专业开发人员的临时代码,写得比较丑,别太当真。
#!/usr/bin/python
# -*- coding:utf8 -*-
import json
# pip install requests
import requests
# 成功登录态势感知后,通过 Chrome 复制当前会话的 Cookie。
cookie_str = 'aliyun_country=CN; aliyun_site=CN;'\
'UM_distinctid=***; JSESSIONID=***; '\
'consoleNavVersion=1.1.1; _yundun_session0=***; '\
'aliyun_choice=CN; isg=***E-'
nodes_client = [] # 客户端 IP
nodes_server = [] # DNS Server IP
nodes_domain = [] # 解析的域名
def get_yundun_DNS_log(http_session=None, page_num = 1):
"""
访问阿里云后台,请求 DNS 日志
:param http_session: requests.session()
:param page_num: page number
:return: HTTP Response
"""
global cookie_str
url = 'https://yundun.console.aliyun.com/sas/slssearch/'\
'getLogList.json?__preventCache=1500********2&_timeScope=1800000'\
'¤tPage=%d&endTime=2017-07-19+19:00:00'\
'&pageSize=100&query=dns@qtype:A&reverse=true'\
'&startTime=2017-07-19+12:30:00'
req = http_session.request('GET', url=(url % page_num),
headers={'cookie': cookie_str})
if req.status_code == 200:
return req.text
return {}
def get_group_name(node):
"""
根据不同的节点类型,返回不同的类目组。相同组的节点将使用相同的颜色显示。
:param node: node_name
:return: group_name
"""
global nodes_client, nodes_server, nodes_domain
if node in nodes_client:
return 'group1'
if node in nodes_domain:
if 'ali' in node:
return 'group2'
return 'group3'
if node in nodes_server:
if node in ('114.114.114.114'):
return 'group4'
if node.startswith('192'):
return 'group5'
return 'group6'
def get_DNS_log_json_list():
"""
返回所有 DNS 日志记录 JSON
:return:
"""
dns_log_json = []
sessionX = requests.session()
# 翻页10次
for i in range(10):
res = get_yundun_DNS_log(sessionX, i+1)
log_json = json.loads(res)
dns_log_json += log_json['data']['list']
return dns_log_json
def geenrate_nodes_and_links():
"""
生成所有节点和关系的List
:return: (nodes[], links[])
"""
global nodes_client, nodes_server, nodes_domain
nodes = [] # 所有节点
links = [] # 所有关系
for log in get_DNS_log_json_list():
(client, domain, server) = ('','','')
for mContent in log['mContents']:
if mContent['mKey'] == 'src_ip':
client = mContent['mValue']
if mContent['mKey'] == 'qname':
domain = mContent['mValue']
if mContent['mKey'] == 'dst_ip':
server = mContent['mValue']
if client == '' or domain == '' or server =='':
continue
#print (client, domain, server)
if domain == 'shcmsproxy.aliyun.com':
continue
if client not in nodes_client:
nodes_client.append(client)
if client not in nodes:
nodes.append(client)
if domain not in nodes_domain:
nodes_domain.append(domain)
if domain not in nodes:
nodes.append(domain)
if server not in nodes_server:
nodes_server.append(server)
if server not in nodes:
nodes.append(server)
if (client, server) not in links:
links.append((client, server))
if (server, domain) not in links:
links.append((server, domain))
return (nodes, links)
def get_datav_json():
(nodes, links) = geenrate_nodes_and_links()
graph = {'nodes':[], 'links':[]}
for node in nodes:
graph['nodes'].append({
"imgPath": "",
"name": node,
"type": get_group_name(node)
})
for link in links:
graph['links'].append({
"source": link[0],
"target": link[1],
"value": 10
})
return '[%s]' % json.dumps(graph)
if __name__ == '__main__':
print get_datav_json()
以下是API输出结果示例:
[
{
"nodes": [
{
"imgPath": "",
"name": "192.168.1.1",
"type": "group1"
},
{
"imgPath": "",
"name": "114.114.114.114",
"type": "group2"
},
{
"imgPath": "",
"name": "taobao.com",
"type": "group3"
}
],
"links": [
{
"source": "192.168.1.1",
"target": "114.114.114.114",
"value": 10
},
{
"source": "114.114.114.114",
"target": "taobao.com",
"value": 15
}
]
}
]
将上述内容作为企业自身 API 接口的输出,同时设置 HTTP HEAD 相关的参数,即可通过 DataV 大屏调用并展现啦!
self.set_header('Access-Control-Allow-Origin', '*.aliyun.com')
self.set_header('Content-Type', 'application/json;charset=UTF-8')
跨域相关的问题请参考:浏览器的同源策略和跨域问题详解
一些期待
关于“交互式”
这篇文章的标题中有两个字我很喜欢——“交互”。
除了视图上的交互,实际上使用者还花了很长的时间用在态势感知日志查询、 导出和格式化上。
这也算是一种“交互”,一种比较笨的交互。希望未来阿里云能在多个产品之间的数据引用、内部接口交互上再做些升级,让我们这样的使用者少发挥技能,直到我们彻底“自废武功”。
就这些,如果您有什么问题欢迎在这里留言与我交流。
想和我成为工作伙伴一起探索云平台上的安全技术实践,也一样欢迎哦~