最近这段时间一直没有机会投稿,前段时间被拉去做产品的集中研发,还分饰部分产品经理的角色,后来因为疫情原因又耽误了,最近是做商务推广,搞得我一个技术人员都快变成了高级商务……闲话不多说,吐槽到此为止,前面好多期都是跟大家聊WAF,因为WAF基本等于了web安全的基础,WAF产品也是web安全中必不可少的一环。这一期想跟大家聊一聊攻防演练平台。

 

如果大家对我了解不多或者忘记了我工作的背景,可以回顾我之前的系列文章,简单总结一句话:一个人的信息安全部。

 

背景就是一个人的信息安全部,按照攻防演练的国际说法,不管红队还是蓝队,都是我一个人自娱自乐的项目,很多人说,攻防演练平台这种产品,只适用于大企业,安全体系成熟的企业,对于中小微企业来说,有一个安全人员就已经不错了,攻防演练根本就搞不起来,总不能自己跟自己打吧。

 

首先想跟大家分享一个概念,攻防演练的意义是什么。

 

一提到攻防演练,大家(不仅限于安全人员)的脑海中不由浮现出CTF、黑客、打擂、红客、高端、应急演练等等(以上是找公司的各个部门人员做的印象调研,包括开发、高层、市场、运维、产品等)。实际上攻防演练很简单,从字面意义上来说,就是一组人发起攻击,一组人进行防御。好像太直白了一些……不过事实如此。

 

在这里回应很多人的说法,一个人的安全部有必要做攻防演练吗?一人分饰两角真的有意义吗?

 

站在我的角度说,如果让我一人分饰两角,那真是没有什么意义,但是如果红蓝队的范围不仅仅限于安全呢?

 

在生产中其实会出现各种各样的事故,不单单是由安全问题引起的,比如服务器故障、代码紊乱、时间同步紊乱、数据库同步丢失、网络问题等等。而事实上,运维有事故应急演练,开发有紧急上线,安全有攻防演练,看似各司其职,但实际上却是谁也离不开谁。举个简单的例子,拿网络波动来说,如果不进行细致的分析,很难发现到底是因为运维的原因还是网络的原因,或者是安全的原因。以生产中的实例为依据,以下是事故现场还原,贴符的勿进以免破功~

 

一个风和日丽的下午,我正遨游在知识的海洋中,一个电话打破了平静的生活:

 

紧急情况,接到客诉说连接咱们的生产域名一直超时,赶紧组织人手排查事故原因,加紧恢复。此时收到某云通知,区域性网络瘫痪已恢复。之后开始查异常。

 

首先是网络:

我这没有异常,解析域名能解析到,telnet是通的

 

紧接着开发:

有业务日志,看日志也没问题

 

运维回应:

nginx日志也正常,CPU内存都正常,流量正常没有堆积

 

安全回应:

一切正常,没有异常请求

 

2分钟后恢复瘫痪状态……整个业务无法访问

 

那问题从哪来的呢?先是讨论网络,毕竟从现象上看更接近网络问题,然后讨论安全,大流量DDOS攻击导致网络瘫痪?域名劫持?查了半个小时,最后发现nginx的问题,虽然端口开着,但是假死了,业务过不去,这个神奇的现象来自于linux的文件系统,此bug是某云在经历了整个区域网络瘫痪后启用恢复导致的。属于云运维事件具体就不多说了。

 

在这里我说的是,一个事故的发生必须要经过各个方面的排查,有经验的应急人员能快速准确的排查出问题属于哪,但不意味着排查问题要单线程的工作(仅凭经验一个方向一个方向排查),应该是发散似的有重点排查,也有协助排查。同样攻防平台也是一样,要有重点,同样也要有协助。

 

我个人认为对于攻防平台来说,靶场选择、人员考核、技能学习是重点,靶场维护、观战是协助。

 

作为中小企业的靶场选择,尽量选择贴近自身业务环境的靶场是关键,这样不会花大量的时间去研究靶场环境,同时对于人员熟悉度来说也是相对比较高的,花费的时间成本不会太多,甚至业务测试环境都可以直接用来做靶场。这样就以为着平台的靶场接口要非常灵活,可以直接导入自定义镜像。

 

红蓝队的人员选用对于中小企业来说是比较头疼的,因为懂安全的是非常少的,基本只有1个专职安全人员,这时红队人员应该怎么选呢?可以集结一部分架构人员结合安全人员进行培训,中小企业的架构师偏重于研发,在研发项目初期的选型阶段,研发架构往往会选择稳重便捷开发的架构,会考虑响应时间,处理速率,处理逻辑等问题,但在安全方面的重视程度或者说了解程度普遍没有那么深入,结合攻防演练平台,可以和安全人员一同学习安全技能,了解黑客大体是怎么进行入侵的,对应在研发过程以及架构选型中就可以提前避免一些不必要的研发漏洞。运维人员可以集体参与进来,一旦事故发生,安全与运维结合处理事故是必不可少的,通过攻防演练平台,运维人员可以清楚的知道黑客入侵进服务器会做什么操作,让运维人员提前做好关键日志的备份,而不是全备,全备的好处是在信息量全面,但是极为消耗性能与存储空间,各有利弊。同时可以在整个排查阶段了解如何快速进行排查,以便在日后的生产环境中遇到简单的问题可以快速分析出是哪方面的事故。

 

在技能学习方面,知识的传达一定是高效的。中小企业怎么做到高效,我个人认为应该通过分析业务使用语言进行知识的传达。比如我们使用的是java,那么了解相关的java安全知识就相对重要,序列化与反序列化将作为重点。使用了Jenkins作为自动发布,那么

Jenkins所有使用中的组件漏洞应当被当作重点知识传达。攻防平台不仅是攻防的实践,更是知识储备的平台,时刻作为人才培养与储备的平台,感兴趣的核心研发人员都可以在此进行研发方面的学习认知,了解基础安全与组件安全,方便研发过程中的选型与基础安全问题排查。

 

攻防平台不仅仅是统计的一个分数,作为技能考核,更应该能回溯整个攻防过程,以便攻防人员进行交流讨论。

 

最后打个广告,四维创智的天幕攻防平台,有意的可以私信我,如果看上四维的任何产品都可以走代理价呦,正式开启作者生涯中的地摊阶段。

最近这段时间一直没有机会投稿,前段时间被拉去做产品的集中研发,还分饰部分产品经理的角色,后来因为疫情原因又耽误了,最近是做商务推广,搞得我一个技术人员都快变成了高级商务……闲话不多说,吐槽到此为止,前面好多期都是跟大家聊WAF,因为WAF基本等于了web安全的基础,WAF产品也是web安全中必不可少的一环。这一期想跟大家聊一聊攻防演练平台。

 

如果大家对我了解不多或者忘记了我工作的背景,可以回顾我之前的系列文章,简单总结一句话:一个人的信息安全部。

 

背景就是一个人的信息安全部,按照攻防演练的国际说法,不管红队还是蓝队,都是我一个人自娱自乐的项目,很多人说,攻防演练平台这种产品,只适用于大企业,安全体系成熟的企业,对于中小微企业来说,有一个安全人员就已经不错了,攻防演练根本就搞不起来,总不能自己跟自己打吧。

 

首先想跟大家分享一个概念,攻防演练的意义是什么。

 

一提到攻防演练,大家(不仅限于安全人员)的脑海中不由浮现出CTF、黑客、打擂、红客、高端、应急演练等等(以上是找公司的各个部门人员做的印象调研,包括开发、高层、市场、运维、产品等)。实际上攻防演练很简单,从字面意义上来说,就是一组人发起攻击,一组人进行防御。好像太直白了一些……不过事实如此。

 

在这里回应很多人的说法,一个人的安全部有必要做攻防演练吗?一人分饰两角真的有意义吗?

 

站在我的角度说,如果让我一人分饰两角,那真是没有什么意义,但是如果红蓝队的范围不仅仅限于安全呢?

 

在生产中其实会出现各种各样的事故,不单单是由安全问题引起的,比如服务器故障、代码紊乱、时间同步紊乱、数据库同步丢失、网络问题等等。而事实上,运维有事故应急演练,开发有紧急上线,安全有攻防演练,看似各司其职,但实际上却是谁也离不开谁。举个简单的例子,拿网络波动来说,如果不进行细致的分析,很难发现到底是因为运维的原因还是网络的原因,或者是安全的原因。以生产中的实例为依据,以下是事故现场还原,贴符的勿进以免破功~

 

一个风和日丽的下午,我正遨游在知识的海洋中,一个电话打破了平静的生活:

 

紧急情况,接到客诉说连接咱们的生产域名一直超时,赶紧组织人手排查事故原因,加紧恢复。此时收到某云通知,区域性网络瘫痪已恢复。之后开始查异常。

 

首先是网络:

我这没有异常,解析域名能解析到,telnet是通的

 

紧接着开发:

有业务日志,看日志也没问题

 

运维回应:

nginx日志也正常,CPU内存都正常,流量正常没有堆积

 

安全回应:

一切正常,没有异常请求

 

2分钟后恢复瘫痪状态……整个业务无法访问

 

那问题从哪来的呢?先是讨论网络,毕竟从现象上看更接近网络问题,然后讨论安全,大流量DDOS攻击导致网络瘫痪?域名劫持?查了半个小时,最后发现nginx的问题,虽然端口开着,但是假死了,业务过不去,这个神奇的现象来自于linux的文件系统,此bug是某云在经历了整个区域网络瘫痪后启用恢复导致的。属于云运维事件具体就不多说了。

 

在这里我说的是,一个事故的发生必须要经过各个方面的排查,有经验的应急人员能快速准确的排查出问题属于哪,但不意味着排查问题要单线程的工作(仅凭经验一个方向一个方向排查),应该是发散似的有重点排查,也有协助排查。同样攻防平台也是一样,要有重点,同样也要有协助。

 

我个人认为对于攻防平台来说,靶场选择、人员考核、技能学习是重点,靶场维护、观战是协助。

 

作为中小企业的靶场选择,尽量选择贴近自身业务环境的靶场是关键,这样不会花大量的时间去研究靶场环境,同时对于人员熟悉度来说也是相对比较高的,花费的时间成本不会太多,甚至业务测试环境都可以直接用来做靶场。这样就以为着平台的靶场接口要非常灵活,可以直接导入自定义镜像。

 

红蓝队的人员选用对于中小企业来说是比较头疼的,因为懂安全的是非常少的,基本只有1个专职安全人员,这时红队人员应该怎么选呢?可以集结一部分架构人员结合安全人员进行培训,中小企业的架构师偏重于研发,在研发项目初期的选型阶段,研发架构往往会选择稳重便捷开发的架构,会考虑响应时间,处理速率,处理逻辑等问题,但在安全方面的重视程度或者说了解程度普遍没有那么深入,结合攻防演练平台,可以和安全人员一同学习安全技能,了解黑客大体是怎么进行入侵的,对应在研发过程以及架构选型中就可以提前避免一些不必要的研发漏洞。运维人员可以集体参与进来,一旦事故发生,安全与运维结合处理事故是必不可少的,通过攻防演练平台,运维人员可以清楚的知道黑客入侵进服务器会做什么操作,让运维人员提前做好关键日志的备份,而不是全备,全备的好处是在信息量全面,但是极为消耗性能与存储空间,各有利弊。同时可以在整个排查阶段了解如何快速进行排查,以便在日后的生产环境中遇到简单的问题可以快速分析出是哪方面的事故。

 

在技能学习方面,知识的传达一定是高效的。中小企业怎么做到高效,我个人认为应该通过分析业务使用语言进行知识的传达。比如我们使用的是java,那么了解相关的java安全知识就相对重要,序列化与反序列化将作为重点。使用了Jenkins作为自动发布,那么

Jenkins所有使用中的组件漏洞应当被当作重点知识传达。攻防平台不仅是攻防的实践,更是知识储备的平台,时刻作为人才培养与储备的平台,感兴趣的核心研发人员都可以在此进行研发方面的学习认知,了解基础安全与组件安全,方便研发过程中的选型与基础安全问题排查。

 

攻防平台不仅仅是统计的一个分数,作为技能考核,更应该能回溯整个攻防过程,以便攻防人员进行交流讨论。

 

最后打个广告,四维创智的天幕攻防平台,有意的可以私信我,如果看上四维的任何产品都可以走代理价呦,正式开启作者生涯中的地摊阶段。

查看CVE推送每日更新,做成类似于新闻头条的推送是企业安全从业人员最应该掌控的能力。随着安全体系工作的开展,每位甲方安全从业者从开始的朋友圈接收漏洞信息,到各个平台接收漏洞信息,但无论是三方还是朋友圈,都不能百分之百贴合与及时的自己想要掌控的漏洞信息,也正是基于这点,我开始自己做CVE的推送工作。

首先要爬取CVE,有一个比较方便的网站,内里集成了每天发布或更新的CVE

URL:https://cassandra.cerias.purdue.edu/CVE_changes/today.html

每一个链接都会链接到CVE漏洞详情中

那我们使用python针对CVE进行信息的爬取

headers = {

    'User-Agent':'Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0',

    'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',

    'Accept-Language':'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',

    'Accept-Encoding':'gzip, deflate',

    'Upgrade-Insecure-Requests':'1',

}

url = "https://cassandra.cerias.purdue.edu/CVE_changes/today.html"

def get_cve_urls():

    '''获取最新的cve漏洞url地址'''

    start_content = 'New entries' # 起始字符串

    end_content = 'Graduations'

    response = requests.get(url, headers=headers, timeout=60)

    response = str(response.text)

    start_index = response.index(start_content)

    if start_index >= 0:

        start_index += len(start_content)

        end_index = response.index(end_content)

        cve_urls_content = response[start_index:end_index]  # 获取网页的指定范围

        soup = BeautifulSoup(cve_urls_content,'lxml')

        cve_url_lists = []     # 存放获取到的cve url

        for u in soup.find_all('a'):

            cve_url = u["href"]

            cve_url_lists.append(cve_url)

#     print(cve_url)

        return cve_url_lists

def get_cve_info():

    '''获取最新cve漏洞信息'''

    print '[*] 最新cve漏洞信息:\n'

    sleep(2)

    cve_urls = get_cve_urls()

    numid = 1

    for cve_url in cve_urls:

        response = requests.get(cve_url,headers=headers,timeout=60)

        response = response.text

        soup = BeautifulSoup(response,'lxml')

        table = soup.find("div",id="GeneratedTable").find("table")    # 获取table标签内容

        cve_id = table.find_all("tr")[1].find("td",nowrap="nowrap").find("h2").string   # cve id

        cve_description = table.find_all("tr")[3].find("td").string       # cve 介绍

其中会有一部分英文的CVE介绍会存在特殊字符,比如单引号,这时我们需要将单引号做处理后才能输出

    if str(cve_description).find('\'') != -1:

            cve_description = str(cve_description).replace('\'', '')

            print('替换特殊字符处理--\'')

            print(str(cve_description))

CVE介绍为英文,如果想翻译安装trans插件,详细请自行百度

由于每天新增的CVE过多,可以添加自己关注的组件漏洞,关注的漏洞才发送

由于CVE官方并没有漏洞等级的介绍,可以将此CVE放到NVD中获取漏洞风险等级

   base_url = 'https://nvd.nist.gov/vuln/detail/'+cve_id

            base_score = requests.get(base_url,headers=headers,timeout=60)

            response_score = base_score.text

            soup_score = BeautifulSoup(response_score,'lxml')

    soup_score_div = soup_score.find("div",id="p_lt_WebPartZone1_zoneCenter_pageplaceholder_p_lt_WebPartZone1_zoneCenter_VulnerabilityDetail_VulnFormView_Vuln3CvssPanel")

    soup_score_tag = soup_score_div.find_all(id=re.compile("p_lt_WebPartZone1_zoneCenter_pageplaceholder_p_lt_WebPartZone1_zoneCenter_VulnerabilityDetail_VulnFormView_Cvss3NistCalculatorAnchor*"))[0].string

    print(soup_score_tag)

            print("[+] cve漏洞等级:"+soup_score_tag)

如此基本集成了漏洞推送的各个组件

整体代码:

from time import sleep

import requests

from bs4 import BeautifulSoup

import re

import smtplib

from email.mime.text import MIMEText

from email.header import Header

import datetime

import os

import sys

cvelist=[]

cvelist.append('<H1><b>New vulnerability ')

if sys.getdefaultencoding() != 'utf-8':

    reload(sys)

    sys.setdefaultencoding('utf-8')

now_time = datetime.datetime.today().strftime('%Y,%m,%d')

yesterday_time = datetime.datetime.today()+datetime.timedelta(-1)

yesterday = yesterday_time.strftime('%Y.%m.%d')

now_year = yesterday_time.strftime('%Y')

print(yesterday)

cvelist.append(now_time)

cvelist.append('</b></H1><p></p><p></p><p></p>')

component_lists = ['tomcat','nginx','apache','kibana','elastic','logstash','jackson','fastjson','windows','win10','win7','linux','centos','ssh','kernel','jenkins','zabbix','grafana','kubernetes','docker']

headers = {

    'User-Agent':'Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0',

    'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',

    'Accept-Language':'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',

    'Accept-Encoding':'gzip, deflate',

    'Upgrade-Insecure-Requests':'1',

}

url = "https://cassandra.cerias.purdue.edu/CVE_changes/today.html"

def get_cve_urls():

    '''获取最新的cve漏洞url地址'''

    start_content = 'New entries' # 起始字符串

    end_content = 'Graduations'

    response = requests.get(url, headers=headers, timeout=60)

    response = str(response.text)

    start_index = response.index(start_content)

    if start_index >= 0:

        start_index += len(start_content)

        end_index = response.index(end_content)

        cve_urls_content = response[start_index:end_index]  # 获取网页的指定范围

        soup = BeautifulSoup(cve_urls_content,'lxml')

        cve_url_lists = []     # 存放获取到的cve url

        for u in soup.find_all('a'):

            cve_url = u["href"]

            cve_url_lists.append(cve_url)

#     print(cve_url)

        return cve_url_lists

def get_cve_info():

    '''获取最新cve漏洞信息'''

    print '[*] 最新cve漏洞信息:\n'

    sleep(2)

    cve_urls = get_cve_urls()

    numid = 1

    for cve_url in cve_urls:

        response = requests.get(cve_url,headers=headers,timeout=60)

        response = response.text

        soup = BeautifulSoup(response,'lxml')

        table = soup.find("div",id="GeneratedTable").find("table")    # 获取table标签内容

        cve_id = table.find_all("tr")[1].find("td",nowrap="nowrap").find("h2").string   # cve id

        cve_description = table.find_all("tr")[3].find("td").string       # cve 介绍

        print "[+] cve漏洞编号:",cve_id

        if str(cve_description).find('\'') != -1:

            cve_description = str(cve_description).replace('\'', '')

            print('替换特殊字符处理--\'')

            print(str(cve_description))

        if any(component in str(cve_description) for component in component_lists):

            oscve = "trans en:zh-CN '"+str(cve_description)+"'|awk 'NR==3 {print $0}'"

            oscve_zh = os.popen(oscve).read()

            cvetitle = '<H1><b><span style="background-color: rgb(255, 153, 0);">'+str(numid)+'.CVE</span></b></H1>'

            cvelist.append(cvetitle)

            numid=numid+1

            cvelist.append('</p><p>vulnerability URL:')

            cvelist.append(cve_url)

            cvelist.append('</p><p>cve id:')

            cvelist.append(cve_id)

            cvelist.append('</p><p>vulnerability introduction</p><p>')

            cvelist.append(str(cve_description))

            cvelist.append('</p><p>译文:')

            cvelist.append(oscve_zh)

            base_url = 'https://nvd.nist.gov/vuln/detail/'+cve_id

            base_score = requests.get(base_url,headers=headers,timeout=60)

            response_score = base_score.text

            soup_score = BeautifulSoup(response_score,'lxml')

    soup_score_div = soup_score.find("div",id="p_lt_WebPartZone1_zoneCenter_pageplaceholder_p_lt_WebPartZone1_zoneCenter_VulnerabilityDetail_VulnFormView_Vuln3CvssPanel")

    soup_score_tag = soup_score_div.find_all(id=re.compile("p_lt_WebPartZone1_zoneCenter_pageplaceholder_p_lt_WebPartZone1_zoneCenter_VulnerabilityDetail_VulnFormView_Cvss3NistCalculatorAnchor*"))[0].string

    print(soup_score_tag)

            print("[+] cve漏洞等级:"+soup_score_tag)

            cvelist.append('</p><p>cve漏洞等级:')

            cvelist.append(soup_score_tag)

            cvelist.append('</p><p></p>')

        else:

            print('No Date')

    mail_host=" "  #设置服务器

    mail_user=" "    #用户名

    mail_pass=" "   #口令

    sender = ' '  #发件人

    receivers = [' ']  #收件人

    mail_msg=''.join(cvelist)

    message = MIMEText(mail_msg, 'html', 'utf-8')

    message['From'] = "{}".format(sender)

    message['To'] = ",".join(receivers)

    subject = yesterday+'CVE收录新增漏洞'

    message['Subject'] = Header(subject, 'utf-8')

    try:

  smtpObj = smtplib.SMTP_SSL(mail_host, 465)

  smtpObj.login(mail_user, mail_pass)

  smtpObj.sendmail(sender, receivers, message.as_string())

  print "邮件发送成功"

    except smtplib.SMTPException:

  print "Error: 无法发送邮件"

def main():

    get_cve_info()

if __name__ == "__main__":

    main()

请根据自己的情况填写邮箱,由于爬取CVE的网站是每天17:02更新漏洞,所以每天早上获取漏洞的小伙伴记得要采用yesterday变量,每天晚上获取漏洞的小伙伴采用today即可。

效果如下:

*本文原创作者:煜阳yuyang,本文属于FreeBuf原创奖励计划,未经许可禁止转载

Apollo(阿波罗)是携程框架部门研发的开源配置管理中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性。本文意在测试apollo的高可用性与安全性。

一、测试目的

随着程序功能的日益复杂,程序的配置日益增多:各种功能的开关、参数的配置、服务器的地址……

对程序配置的期望值也越来越高:配置修改后实时生效,灰度发布,分环境、分集群管理配置,完善的权限、审核机制……

在这样的大环境下,传统的通过配置文件、数据库等方式已经越来越无法满足开发人员对配置管理的需求。

Apollo配置中心应运而生!

测试apollo的高可用性与安全性。

二、测试范围

本次测试包括以下几个方面:

针对配置文件的修改是否生效

模拟灾难发生(宕机或网络波动等)看是否切换备用Apollo正常工作

模拟大应用发布并发看是否Apollo能抗压正常工作

三、测试环境

3.1 逻辑拓扑

3.2 网络拓扑

3.3 软/硬件环境

环境 角色 IP地址 指向
Portal MySQLApolloEureka 192.168.103.111  Apollo-portalApollo-configApollo-adminMySQLportalDB->111MySQLconfigDB->111Eureka->111,112 
DEV 192.168.103.111192.168.103.112  Apollo-configApollo-adminMySQLportalDB->111MySQLconfigDB->111Eureka->111,112 
PRO 192.168.103.113192.168.103.114 Apollo-configApollo-adminMySQLportalDB->111MySQLconfigDB->113Eureka->113,114

四、Apollo测试项对比

针对配置文件的修改是否生效

经测试生效

通过

模拟灾难发生(宕机或网络波动等)看是否切换备用Apollo正常工作

将其中一台服务器down机后,依然可发布

通过

模拟大应用发布并发看是否Apollo能抗压正常工作

经过测试,测试apollo得到如下压测数据

同时由于整体采用apollo框架,对整体项目的压测即对apollo整体框架的压测,给出的压测结论为:

系统经过一系列业务接口的压力测试,在响应与并发量上表现优秀,期间系统稳定可靠,服务器资源波动正常,全部业务场景千万次交互错误率为0%。

业务混合模式在长达8小时(1:2:1.5充值:查询:交易)的测试场景中,压测聚合报告数据表现优秀,720万次业务交互错误率为0%,95%连接响应时间均低于1000毫秒,TPS稳定在250/sec。

通过

五、应急措施

一旦框架出现问题,可能出现的情况:

1. 客户端无法接收到配置情况

2. 服务端无法更新配置发布

针对以上两点,需要仔细分析框架为何会出现此问题从而解决。再次之前应急方案为手动修改配置发布。(注:无论出现何种现象只影响自动化)

六、测试结论

经过Apollo性能测试,发现此框架稳定,能够承载大量信息处理,同时与spring集成最大程度兼容和方便了研发同学的使用与对接,实现了发布自动化,并且符合运维的分布式部署与集群理念,既为当一台服务器发生故障,不影响应用使用。再权限管控方面优异,实现了角色划分,方便管控。

以下为整体可用性分析:

场景 影响 降级 原因
某台Config Service下线 无影响 Config Service无状态,客户端重连其它Config Service
所有Config Service下线 客户端无法读取最新配置,Portal无影响 客户端重启时,可以读取本地缓存配置文件。如果是新扩容的机器,可以从其它机器上获取已缓存的配置文件
某台Admin Service下线 无影响 Admin Service无状态,Portal重连其它Admin Service
所有Admin Service下线 客户端无影响,Portal无法更新配置
某台Portal下线 无影响 Portal域名通过SLB绑定多台服务器,重试后指向可用的服务器
全部Portal下线 客户端无影响,Portal无法更新配置
某个数据中心下线 无影响 多数据中心部署,数据完全同步,Meta Server/Portal域名通过SLB自动切换到其它存活的数据中心
数据库宕机 客户端无影响,Portal无法更新配置 Config Service开启配置缓存后,对配置的读取不受数据库宕机影响

以上结论总结:此框架适合大型研发团体,随着团队发展壮大,使用成熟框架是势在必行,此框架符合公司需求,各个测试均通过,可以使用。

*本文原创作者:煜阳yuyang,本文属于FreeBuf原创奖励计划,未经许可禁止转载

在业务安全中,不仅仅要考虑业务是否有被攻击的可能,同时也要考虑整个业务的稳定性,如果大家认为这是运维要考虑的事情安全不需要考虑就有些片面了,在整体架构中,安全协同运维做好架构方面的设计是十分必要的,人无完人,只有方方面面都考虑到才能保证业务的安全。

在我们的架构中核心是zookeeper,在我前期的文章中也有关于我们业务架构的描述,不熟悉的朋友可以翻一翻,今天想讲的是zookeeper的平滑故障迁移,这实际上应该是故障应急演练,当然认为这是运维工作的可以跳过。

什么是zookeeper:

ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。

ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。

zookeeper的原理:

ZooKeeper是以Fast Paxos算法为基础的,Paxos 算法存在活锁的问题,即当有多个proposer交错提交时,有可能互相排斥导致没有一个proposer能提交成功,而Fast Paxos作了一些优化,通过选举产生一个leader (领导者),只有leader才能提交proposer,具体算法可见Fast Paxos。因此,要想弄懂ZooKeeper首先得对Fast Paxos有所了解。

zookeeper的基本运行流程:

1、选举Leader。

2、同步数据。

3、选举Leader过程中算法有很多,但要达到的选举标准是一致的。

4、Leader要具有最高的执行ID,类似root权限。

5、集群中大多数的机器得到响应并接受选出的Leader。

实验理论

3台zookeeper形成稳定的集群,当其中一台发生故障时,另外两台接替故障的一台继续工作,当follower出现问题时,leader不会发生变化,此时将迁移的对象接入,由于持续工作的两台配置文件没有变更,所以迁移的对象无法接入,处于notrunning状态,改变配置重启follower节点,停止被迁移的zookeeper将迁移对象接入,此时应是被迁移对象与leader形成一个集群正常工作,改变第三个节点的配置文件形成迁移后的3节点集群

实验环境

4台zookeeper

IP:

172.31.253.111

172.31.253.112

172.31.253.113

172.31.253.115

实验步骤

1.配置zookeeper(112,113,115为一个集群,目前集群为原始集群,即为无故障集群,集群上放test作为数据标识)

112配置文件:zoo.cfg

Myid:1

113配置文件:zoo.cfg

Myid:2

115配置文件:zoo.cfg

Myid:3

启动集群,查看集群状态

112follower:

113follower:

115leader:

115是leader,保留115,从follower开始模拟112发生故障,替换112->111

4.替换

111配置文件:

Myid:1

启动111并查看状态

此时的集群状态:

111:not running(对状态有质疑的请往上翻看实验理论)

112:follower

113:follower

115:leader

查看数据:

存在测试数据test(标识数据)

将113的配置文件变更

停掉112重启并查看状态

此时集群状态:

111:follower

113:follower

115:leader

查看数据:

将115配置文件变更后重启

数据依旧存在并且完成zookeeper的故障机替换

注:在启动113时如果没有停掉112,会导致115,112为一个集群,111,113为一个集群,出现两个leader,数据在两个集群中同时存在,数据虽然不受影响,但集群会有瞬时的中断,在此过程中会造成数据丢失的风险,所以一定注意要将替换下的zookeeper停掉!

*本文原创作者:煜阳yuyang ,本文属于FreeBuf原创奖励计划,未经许可禁止转载

关于架构的理解有很多人会有误区,认为架构是一个很大的整体框架,像安全架构就是综合所有安全设备的一个框架,其实并不是这样,架构是为了设计系统的元件如何划分、元件之间如何发生相互作用,以及系统中逻辑的、物理的、系统的重要决定抉择,负责不同层次上的逻辑架构、物理架构、系统架构的设计、配置、维护等工作。

今天就让我偷懒一次吧,实在不想插图了,希望大家能看得进去。

架构思维要从多方面考虑整体架构的设计,接下来的架构思维会涉及业务,各位看官需要自行对接业务来分析看待架构思维。

首先给出一个场景

一:业务语言确定为java

二:采用分布式业务集群

三:业务需要大量调度与查数据库

四:业务量适中

这几点是我企业中遇到的一个场景,同样也是大多数中小企业的现实场景。

一、为什么使用Java语言

java作为中大型企业的开发语言,他的安全性与规范性不言而喻,通过java语言实现的B/S架构的设计是大多开发者的选择,同样作为稳定选择,java与php之间的较量一直没有停过。

分层思想是是设计计算机系统过程中非常重要的思想。比如操作系统常见的硬件层、驱动层、应用层之间的关系。分层可以更好地实现高内聚、低耦合的效果。我们都知道,Java语言有着完备的MVC框架,包括视图层、业务控制层和持久层,在Spring框架中,我们可以通过IOC和AOP降低编码过程中的高耦合,也就是说Java中的这些框架可以让开发者有更广阔的空间去设计科学合理的架构,也体现着Java多层架构的特点。相比Java而言,PHP留给开发者的空间并不多,但PHP近些年也在改进,迎合电子商务的需要,引入MVC设计模式,但成熟性和稳定性上与Java还是有着不小的差距。不得不提的是PHP可兼容MySQL开发,这使得在考虑成本因素的前提下,PHP变得小而精,收到了一些中小型网站的青睐。但是按照成熟度来讲,PHP还是远远比不上java。

二、为什么采用分布式业务集群部署

分布式业务集群最大的好处就是提供了灰度发布的可能性,提高了整体业务系统的可用性与可恢复性,一旦出现问题能在短时间内回滚到稳定版本。同时分布式业务集群部署还可以分担整体业务带来的压力,包括网络上的压力,服务器性能上的压力等等。

整体的业务前情提要就是这样,那么从业务角度考虑怎么设计业务架构?

业务架构的设计思维要围绕着高可用性来考虑问题。既然是分布式业务集群,那么其中的服务器调度是免不了的,而且核心就应该放在调度上。在这里使用dubbo+zookeeper的架构设计(相对稳定,因为是个存在比较久的技术)。

什么是dubbo+zookeeper?

如果大家有兴趣可以详细学习学习,这里给出详细介绍链接

简单介绍一下,业务集群注册到注册中心,调用者通过注册中心订阅业务集群的变换,当需要调度时通过注册中心确定哪台服务器的状态是最佳的,将调度任务下发到那台服务器中,完成整个业务任务。

由于zookeeper的架构设计时有同步,3台zookeeper做成的集群可以实时同步数据,意味着如果有一台宕机,业务正常工作不说,宕机的那台不管因为什么原因导致zookeeper崩溃,哪怕卸载重装也不怕数据的丢失,充分保护了数据的可用性。

同时由于业务需要大量调度与查数据库,为避免大量查询语句影响数据库性能,引入redis进行数据缓存来减轻数据库的压力。

这是整体业务的架构思维,那么下面重点来讲一下围绕业务架构思维展开的安全架构思维。

首先明确一点,安全是离不开业务的,任何安全点的设计都应该充分考虑业务。

由于业务都是使用代码实现的,代码审计是必须的安全点,那么在安全架构设计思维初期,首先就要考虑代码审计。相关代码审计工具如果有经费建议使用厂商的,如果预算不充足给大家推荐cobra,具体使用详见

整体考虑代码量与审计服务器性能,建议采用集群方式进行代码审计。

同时业务的http特性还需要我们构建WAF,同样的如果有经费建议使用厂商的,如果预算不足我的其他文章中有写到很多关于自建WAF的文章,欢迎翻阅。

考虑到了服务器集群的统一管理,推荐使用堡垒机作为统一管理入口,同样的如果有经费建议使用厂商的,这里推荐齐治,如果预算不足建议使用开源堡垒机jumpserver。

使用详见:http://www.jumpserver.org

同样还有基线与漏洞扫描的设计,这块在后期我会详细讲解如何使用开源代码搭建自己的checkserver.

在保证了外部的相对安全后,要考虑内部的相对安全,加密传输无疑是比较大众和方便的一种手段。同样内部安全永远离不开运维监控的支持,只用做好协同,才能保证相对稳定与安全的服务器环境,而安全、稳定、高效、灵活,才是业务架构的根本所在。

*本文原创作者:煜阳yuyang,本文属于FreeBuf原创奖励计划,未经许可禁止转载

在这里讲一下开源WAF的测试评估方法,以成品文档为例。

一. 测试目的

当WEB应用越来越为丰富的同时,WEB 服务器以其强大的计算能力、处理性能及蕴含的较高价值逐渐成为主要攻击目标。SQL注入、网页篡改、网页挂马等安全事件,频繁发生。2007年,国家计算机网络应急技术处理协调中心(简称CNCERT/CC)监测到中国大陆被篡改网站总数累积达61228个,比2006年增加了1.5倍。其中,中国大陆政府网站被篡改各月累计达4234个。

企业等用户一般采用防火墙作为安全保障体系的第一道防线。但是,在现实中,他们存在这样那样的问题,由此产生了WAF(Web应用防护系统)。Web应用防护系统(Web Application Firewall, 简称:WAF)代表了一类新兴的信息安全技术,用以解决诸如防火墙一类传统设备束手无策的Web应用安全问题。与传统防火墙不同,WAF工作在应用层,因此对Web应用防护具有先天的技术优势。基于对Web应用业务和逻辑的深刻理解,WAF对来自Web应用程序客户端的各类请求进行内容检测和验证,确保其安全性与合法性,对非法的请求予以实时阻断,从而对各类网站站点进行有效防护。

由于公司曾接连发生入侵事件,搭建WAF阻挡黑客脚步势在必行。

二. 测试范围

本次测试包括以下几个方面:

模拟黑客攻击看是否阻断生效

模拟灾难发生(宕机或网络波动等)看是否切换备用WAF正常工作

模拟大流量并发看是否WAF能抗压正常工作

模拟误报信息看WAF是否支持调整策略

模拟紧急情况WAF是否能切换工作模式

三. 测试环境

3.1网络拓扑

3.2软/硬件环境

角色 设备 IP地址 安装模块
WAF Linux Centos 7 192.168.99.17 Nginx1.15.5
ModsecurityV3
Java1.8.0
Geoip
Elasticsearch
Logstash
Filebeat
Keepalive
Python2.7
192.168.99.18 Nginx1.15.5
ModsecurityV3
Java1.8.0
Geoip
Elasticsearch
Logstash
Filebeat
Keepalive
Python2.7
192.168.105.18 Elasticsearch
Logstash
Kibana
Java1.8.0
Geoip

四. WAF测试项对比

模拟黑客攻击看是否阻断生效

将WAF模式调整为阻断模式,模拟SQL注入,及时阻断,返回码403

测试通过

模拟灾难发生(宕机或网络波动等)看是否切换备用WAF正常工作

将主WAFnginx关闭,访问域名依然正常,备用WAF上有访问日志

测试通过

模拟大流量并发看是否WAF能抗压正常工作

测试组发送压力包,WAF工作正常,监控CPU不超过10%

测试通过

模拟误报信息看WAF是否支持调整策略

发送模拟包触发WAF规则,通过ELK观察包显示的触发规则文件修正规则,修正后重启nginx,修正生效,放行模拟包

测试通过

模拟紧急情况WAF是否能切换工作模式

将modsecurity模块关闭,访问域名依然正常,nginx有访问日志,modsecurity没有访问日志

测试通过

五. 应急措施

应急等级分为高中低三个等级

低级:

一般为测试数据阻断,返回码为403,手动分析数据包中传递参数是否合理,若合理则寻找对应规则文件进行正则匹配修改或整体规则注释;若不合理则沟通研发进行报文调整

中级:

一般为大量长期数据阻断,返回码为403,先手工切换WAF工作模式为仅检测(modsecurity.conf->SecRuleEngine DetectionOnly),观察数据包是否恢复正常,若恢复正常,后续按照低级应急方案处理,若依旧不正常,则按照高级应急方案处理

高级:

一般为中级应急方案无效,则手动切换nginx安全模块为关闭状态(nginx.conf->modsecurity off),保证数据正常的情况下再进一步排查问题

六. 测试结论

WAF部署简单方便,使用ELK分析WAF日志对于专业人员来说十分轻松,与此同时能防御多种多样的攻击,防御列表如下:

SQL注入(SQLi) PHP代码注入
跨站点脚本(XSS) HTTPoxy
本地文件包含(LFI) Shellshock
远程文件包含(RFI) 会话固定
远程执行代码(RCE) 扫描程序检测
Xml代码注入(XXE) 命令注入
拒绝服务攻击(DoS) java反序列化

使用此WAF的优点:

免费,节省开支

可控,可随时增加修改自定义策略

灵活,通过日志灵活判断是否为攻击

安全,可阻断大部分的攻击

范围,只要部署网络任意位置用nginx转发即可使用

高效,过滤恶意流量增强了后端nginx处理效率

性能,不占用过多性能完全依赖nginx处理数据

使用此WAF的缺点:

误报,存在一定几率误报需实时监控调整

经过测试分析,WAF可有效阻断大部分黑客攻击,对于0day有着一定的防御作用。由于部署模式为双机热备,极大程度保证了WAF的运行安全以及业务的稳定。并经过流量测试证明了WAF的稳定性。同时撰写了应急方案,一旦产生误报有及时的应急措施帮助业务恢复稳定。必要时可关闭防御保证业务的可持续性。

在安全防护体系中,waf作为安全前线的第一道防护,起到了缓解的作用,在实际场景中,可以阻断公司前段时间发生的安全问题像XXE攻击等,同时有助于公司通过安全等级保护,极大程度保护交易数据不被篡改,同时保护服务器免遭黑客干扰,所以部署WAF势在必行。

*本文原创作者:煜阳yuyang,本文属于FreeBuf原创奖励计划,未经许可禁止转载

之前有在体系建设中写到开源WAF的利用,本次就继续这个话题给出使用手册+应急预案来做生产级开源WAF的支撑。

一.ModSecurity——WAF简介

ModSecurity是一个入侵探测与阻止的引擎,它主要是用于Web应用程序所以也可以叫做Web应用程序防火墙。

ModSecurity是实时web应用程序工具包监控、日志记录和访问控制。

防御内容:(OWASP TOP 10漏洞可防御)

SQL注入(SQLi)

跨站点脚本(XSS)

本地文件包含(LFI)

远程文件包含(RFI)

远程执行代码(RCE)

PHP代码注入

HTTPoxy

Shellshock

会话固定

扫描程序检测

元数据/错误泄漏

GeoIP国家/ 地区阻止

经测试同时可防御XXE、命令注入、反序列化等多种主动攻击

同时被动攻击亦可防御(DDoS、CC攻击等)

二.配置环境

1.服务器位置

真实IP:

IDC:

192.168.99.17(主)、192.168.99.18(备)、192.168.105.18(ELK)

阿里云:

172.19.135.151(主)、172.19.135.152(备)、172.19.135.153(ELK)

灾备措施:

IDC:

双机热备(keepalive VIP: 192.168.99.240)

阿里云:

SLB

映射IP:公网IP(脱敏)

对应映射关系: 192.168.99.240:443<=>公网IP(脱敏):443

2.主体搭建配合

Nginx+Mod_Security+elasticsearch+logstash+kibana+java1.8+elasticsearch-head

Nginx

版本:1.15.5

位置:/usr/local/nginx/*

目前占用端口:80 443

Mod_Security

版本:V3(目前为3.0.2)

配置位置:/usr/local/nginx/conf/modsecurity.conf

规则位置:/usr/local/nginx/conf/owasp-modsecurity-crs/rules/*.conf

日志位置:/opt/modsecurity/data/*/*/*

Elasticsearch

版本:5

位置: /usr/local/elasticsearch*/*

/opt/elasticsearch*/*

目前占用端口:9200

Logstash

版本:5

位置: /usr/local/logstash*/*

/opt/logstash*/*

规则位置: /usr/local/logstash*/waf/*.conf

/opt/logstash*/waf/*.conf

Kibana

版本:5

位置:/usr/share/kibana/*

配置位置:/etc/kibana/*

目前占用端口:5601

Filebeat

版本:5

位置:/opt/filebeat*/

目前占用端口:5044

elasticsearch-head

位置:/opt/elasticsearch-head/*

目前占用端口:9100

3.启用方法

启用顺序:

Nginx+Mod_Security=>elasticsearch+kibana=>elasticsearch-head=>logstash=>filebeat

Nginx

配置了service

Mod_Security

在nginx.conf中确定参数ModSecurityEnabled为on

在nginx.conf中确定参数ModSecurityConfig为modsecurity.conf

随nginx启动而启动

Elasticsearch

使用els用户运行elasticsearch

/usr/local/elasticsearch/bin/elasticsearch

Kibana

配置了service

Elasticsearch-head

/opt/elasticsearch-head/node_modules/grunt/bin/grunt server

Logstash

/usr/local/logstash/bin/logstash -f /usr/local/logstash/waf/

全部启动后访问5601端口

可在右上角调整时间区域显示

在最左侧有两个模块将重点讲解:visualize、dashboard

Visualize:创建模板

可根据数据创建以下图形界面

Dashboard:展示模板

将数据通过创建的图形展示出来

4.使用方法

可根据日期进行筛选数据内容,具体会得到如下图展示

详细解释参数:

1)time:事件传输时间

2)client_ip:源地址(攻击者IP)

3)geoip.city:攻击地点

4)geoip.region_name:攻击城市

5)geoip.country_name:攻击国家

6)requestHeaders.Host:攻击者访问的域名

7)requestedUri:攻击者访问的URL

8)responseStatus:服务器状态吗

9)httpMethod:服务器请求方法

10)transaction.messages:匹配正则匹配到的攻击规则(如为空则认定为非攻击性请求,如判断具有攻击性,自行添加策略)

11)requestHeaders.Referer:此条URL源

12)requestBody:请求方法为POST时的数据内容

筛选只能根据时间与攻击类型筛选(模板前两块)

筛选有阻断判断的日志记录

transaction.messages:*

5.调试方法

此说明仅针对Mod_Security策略调试

在msg字段中查看查看所属策略的策略文件,定位line查看正则匹配,更改正则至想要结果

6.性能说明

a.测试正常打包压测没有问题,WAF本身能抗住研发部测试组的压力测试包,ELK经过优化同样可以抗住压力测试包,经过个人DDoS测试能抗住1000线程的测试包1min,累计数据包达到10W多个(测试工具崩溃,WAF无碍,CPU在10%以下)。

b.日志大约达到100W条(约5G左右)并且存在大量长数据未分割(多为图片)日志筛选会异常慢,以至于出现timeout的情况。在日志量达到瓶颈之前应清除过早前的elasticsearch的索引以保证日志查询正常,命令如下:

或限制上传包大小。

右侧返回true为删除成功,如日志量过大,反应会相对慢,切勿重复点击执行,否则会导致删除失效(注:删除为高危命令,执行前需仔细核对)。

c.如出现空日志情况,核对哪个进程挂了,重新挂载,如果还没有数据,查看各个日志,如果filebeat显示一直等待进程,则删除registry文件(yum安装路径为/var/lib/filebeat/registry),重新启动filebeat会将全部日志导入(注:如日志量过大,需将日志进行清理或导出,过后再导入,否则全部日志导入将使搜索崩溃)。

d.待补充

7.应急方案

应急等级分为高中低三个等级

低级:

一般为测试数据阻断,返回码为403,手动分析数据包中传递参数是否合理,若合理则寻找对应规则文件进行正则匹配修改或整体规则注释;若不合理则沟通研发进行报文调整

中级:

一般为大量长期数据阻断,返回码为403,先手工切换WAF工作模式为仅检测(modsecurity.conf->SecRuleEngine DetectionOnly),观察数据包是否恢复正常,若恢复正常,后续按照低级应急方案处理,若依旧不正常,则按照高级应急方案处理

高级:

一般为中级应急方案无效,则手动切换nginx安全模块为关闭状态(nginx.conf->modsecurity off),保证数据正常的情况下再进一步排查问题

总结

在出使用手册+应急预案时应当注意多考虑架构的设计问题以及可能发生的链路问题。想的全面一些,才能遇事不慌。生产级开源WAF需要经常调试,做好调试记录会让工作事倍功半

*本文原创作者:煜阳yuyang,本文属于FreeBuf原创奖励计划,未经许可禁止转载

这一期主题是体系评估,那么这里其实评估的不仅仅的是安全体系的评估,还有业务的评估、风险的评估、设备的评估、人员的评估等等。而且主要是涉及中层的工作。

评估的意义是什么?

评估是综合分析体系现状,考虑体系发展方向的体现。

评估什么?

我们要对业务进行评估,包括大概产生的利润,需要的成本,后期的运营难度,发展空间,能否打出圈内知名度,影响力等等。

我们要对风险进行评估,包括可能发生的意外,意外的损失,运营的时效性等等。

我们要对选用的设备进行评估,包括使用成本,老化率,使用寿命,国产化,安全等等。

我们要对人员进行评估,包括人力成本,人员知识储备量,带来的价值等等。

由谁来评估?

业务方面应该由业务所有者(项目合作者)来进行评估,也就是由高层进行,评估后如果业务可以实施,交由中层进行业务设计,此时要对风险、选用设备进行评估,同时还要对人员进行评估。

业务评估:

(1)成本/利润把控

一个业务的产生首先最直接的目的就是为了让企业盈利,那么整个业务体系的建设成本把控就现得尤其重要。这里回应第一篇文章中评论所说,WAF都用开源的公司到底有多差?我不知道该怎么说这个问题,但是如果中层一句话,采用项目制,每个参与项目的人进行成本控制,谁控制的越好,谁到最后拿的越多。我想使用开源WAF其实就是每一个人评估后的必然结果,一个长期业务大概10年,10年的商业WAF投入需要多少?至少需要花费10万吧,一年1万算良心价格了,这还只是WAF,堡垒机呢?数据库审计呢?流量清洗呢?日志审计呢?漏扫呢?……很多人说安全是个无底洞,一个业务1000万的投入,就算把1000万都用在安全设备,也不见得能用全,要看这1000万怎么花,比如业务接口,如果是私密对接,走VPN走白名单,其实安全设备投入这块就不需要那么多,如果走公网放开接口,那么安全设备投入就要高得多。

(2)运营难度

业务在搭建好之后其实最重要的就是运营,确实不管是高层还是中层都会关心业务在运行期间不要出现问题,这与成本把控同样有所联系,为了不出问题,需不需要投入成本?如果需要投入成本,这个成本最大预算又该是多少?需不需要在运营期间拿下XXX标准(例如PCI、等保等等)这些都要在评估阶段想清楚。

(3)发展空间

业务的发展空间如果很大,即使前期投入超过预算,甚至还有倒贴的可能,但是运营阶段不需要什么投入,业务能力是一个持续增长的趋势,那么这个业务一样会被执行下去,评估业务发展空间也是高层需要做的。

(4)影响力

评估业务的影响力也是必要的,如果可以通过一个业务来提升知名度,那么成本把控也许会显得不那么重要

整个业务评估阶段的影响因素重视程度是相关联的,并没有统一的标准,没有什么阀值,基于市场变化是评估最大的难度。

风险评估:

(1)意外评估

这里所说的风险评估与等保以及体系管理的风险评估还不是一个概念,风险包括人为风险和物理风险,人为风险可能包括人员的内部数据泄露、人为破坏、黑客入侵等等。物理风险可能包括自然灾害、停电等等。等保与体系管理的风险评估大多是评估这些,而我说的风险评估是业务本身的风险,包括业务被中断、投入变化等等,当然两个风险评估是都要做的。

(2)时效性评估

时效性评估主要评估整个业务体系的持续时间与设备投入时间比较,防止因设备老化产生的问题。

这里整体的风险评估也是与投入资金相关联的,之前我在成本把控中说到要体现如何进行成本控制,其中提到的一点是使用开源安全产品进行成本把控,其实是因为开源安全产品不会比厂商设备差到哪里去,性能的差别无非是硬件的差别,就用WAF举例,开源WAF是一段代码,放到服务器中配合nginx做规则匹配判断,与厂商WAF除了硬件性能上的区别,本质是没有什么区别的,都是匹配,从策略层面上说,厂商WAF的策略也许更加贴合市场,误报率会低一些,开源WAF适配时间会长一些,使用中投入的人力成本会大一些,误报率会高一些,我认为本质没有什么区别,都需要业务的适配调整。那么能控制出来的成本可以用在更需要的地方。比如我把用了10多年的交换机更新一批防止老化、把可用性的投入再增加一些。

一个业务的风险如果用一个量化的视图来体现的话,我认为最可能的视图应该是这样的

要搞清风险的来源,根据风险占比制定有针对性的安全措施比全面的投入要经济有效的多。

设备评估:

这里要分软设备与硬设备,举个例子,负载均衡,用keepalived做虚拟IP,与直接使用F5设备的评估,前者虽然免费,但是其性能却无法与F5相提并论,传统F5设备无法上云,且需要考虑老化率与维护的相关事宜,云上的SLB(阿里云)和ELB(华为云)则在原理上与实现架构上均有自己的适配,这个适配在实际使用时应当评估其最大负载量,与负载时出现的轮询BUG。

人员评估:

这其实是人事在筛选时应当做的事情,不过多涉及,那么我们作为面试过程中的面试官或同事角色,应当如何做好对人员的筛选?

其实我认为重点不是在于面试题目,而应该在于人员的接受度,在面临一个岗位时,是否能完成岗位所需的诸多事宜,是否能高效的优化在岗期间每个事务的工作流程,是否能改进现有的架构去推动升级等等。当然能完成以上的任务必然会涉及到专业知识,要有专业知识,要有实战经验,这不仅仅体现在安全从业者,应当是每位从业者都面临的问题。

最后总结一下评估工作,很多人说评估是没有必要的浪费时间,在行动派眼中评估是空想,但我更想说的是,其实任何行动之前都是要评估的,如果评估结果告诉你这件事情可以不做,总要好过做一半发现他没有意义要更节省时间。每个人的时间都是宝贵的,希望所有人在自己的时间内,掌控时间,做自己时间的主人。

*本文原创作者:煜阳yuyang,本文属于FreeBuf原创奖励计划,未经许可禁止转载

近日看到一些关于工具的文章,很多人对于写工具类文章都是蜻蜓点水,写搭建,写基础使用,但是基础的开源工具在生产环境上的使用其实是比较困难的,有很多需要二次开发做到与生产环境适配,今天写这篇文章的目的就在于开启开源工具二次开发的思路,其中一个模块的二次开发很简单,大家基本都能看懂,就以这篇简单易懂的代码改动举例。本次开源工具二次开发以cobra代码审计为例。

适用范围:代码初学者、有一定python基础与协议基础

需求明确

首先要先明确自己的需求,我们的需求是在上线前做关联性代码审计,我采用的是cobra,至于为什么要使用cobra就不多说了,这是评估期间做的事情,文章主要写二次开发。

显示情况

我们的生产环境使用gitlab作为代码库,仅允许ssh方式下拉代码,而不允许http公开拉代码,这么做是为了安全,但是同样的也对cobra的使用造成了一定的麻烦。因为基础的cobra是没有ssh下拉功能的,需要我们自己做二次开发

代码改动

首先在原基础的cobra上我们做一个拉代码的测试

好像很叼的样子,没有漏洞,但是有层script提示没有选择目标

后台定位问题发现如下错误

一般出现这个问题不是分支错误就是路径错误,反正是找不到文件的,那直接用git clone试试原路径是否存在吧

500,询问了gitlab负责人才知道是根本没有开放http下拉代码的功能,统一使用ssh进行下拉。

那原基础的cobra能直接用ssh拉代码吗?试试看好了

提示请输入URL,也就是输入格式不对,那我们换一种方式输入

还是一样的提示,那看看后端是什么情况吧

一切正常。

首先对问题进行定位

命令为find ./ -name “*.py”|xargs grep “Please input a valid URL”

命令意思为在本级目录级下级目录搜索内容为Please input a valid URL的py脚本

找到了api.py,让我们进去看看这是什么

果然只限定了http与https,那根据咱们的需求加上ssh吧

原代码:

  if re.match(r'http://|https://', t):

                    arg = (t, formatter, output, rule, a_sid, is_del)

                    producer(task=arg)

                else:

                    return {"code": 1004, "msg": "Please input a valid URL"}

            result = {

                'msg': 'Add scan job successfully.',

                'sid': a_sid,

                'total_target_num': len(target),

            }

        else:

            if re.match(r'http://|https://', target):

                arg = (target, formatter, output, rule, a_sid, is_del)

                producer(task=arg)

            else:

                return {"code": 1004, "msg": "Please input a valid URL"}

改动后代码:

    if re.match(r'http://|https://|ssh://', t):

                    arg = (t, formatter, output, rule, a_sid, is_del)

                    producer(task=arg)

                else:

                    return {"code": 1004, "msg": "Please input a valid URL"}

            result = {

                'msg': 'Add scan job successfully.',

                'sid': a_sid,

                'total_target_num': len(target),

            }

        else:

            if re.match(r'http://|https://|ssh://', target):

                arg = (target, formatter, output, rule, a_sid, is_del)

                producer(task=arg)

            else:

                return {"code": 1004, "msg": "Please input a valid URL"}

重新试一下吧

后台提示需要输入root密码

我的环境是做了[email protected]的免密推送,root用户密码我不知道啊,就算有权限难道把密码写在配置文件里又安全吗?明文密码泄露的事情可是发生不少,于是继续看代码找问题

find ./ -name "*.py" |xargs grep "git clone"

看他的推送方式是什么

配置文件为./cobra/pickup.py

如果配置文件中没有输入用户名或密码,便是公开链接,直接clone,如果有用户名密码,则分割填入用户名和密码进行加密clone,如果这放在http协议中这个逻辑完全没有问题,但是放在ssh下拉代码里,就会存在很大的逻辑问题了

逻辑问题在于ssh的免密钥登录不需要密码,如果单纯以用户名密码作为判断依据那免密钥的作用就为零了,为了适配免密钥,实际上在代码中指定免密钥的用户即可,同时为保证其他基础功能不遭受破坏,增加的功能应使用判断前缀的方式进行代码改写,具体如下:

原代码:

         if self.repo_username is None or self.repo_password is None:

            # public repo

            clone_address = self.repo_address

        else:

            # private repo

            clone_address = self.repo_address.split('://')[0] + '://' + quote(self.repo_username) + ':' + \

                            quote(self.repo_password) + '@' + self.repo_address.split('://')[1]

        # clone repo with username and password

        

        # "http[s]://username:[email protected]/username/reponame"

        # !!! if add password in the url, .git/config will log your url with password

        cmd = 'git clone ' + clone_address + ' "' + self.repo_directory + '" -b ' + self.repo_branch

改后代码:

     if self.repo_username is None or self.repo_password is None:

            # public repo

            if (self.repo_address.split('://')[0] == 'ssh'):

                clone_address = 'ssh://' + '[email protected]' + \

                self.repo_address.split('://')[1]

            else:

            clone_address = self.repo_address

        else:

            # private repo

            if (self.repo_address.split('://')[0] == 'ssh'):

                clone_address = 'ssh://' + '[email protected]' + \

                self.repo_address.split('://')[1]

            else:

            clone_address = self.repo_address.split('://')[0] + '://' + quote(self.repo_username) + ':' + \

                            quote(self.repo_password) + '@' + self.repo_address.split('://')[1]

        # clone repo with username and password

        # "http[s]://username:[email protected]/username/reponame"

        # !!! if add password in the url, .git/config will log your url with password

        cmd = 'git clone ' + clone_address + ' "' + self.repo_directory + '" -b ' + self.repo_branch

增加前缀判断,如果前缀为ssh,则统一使用通用用户git进行ssh登录代码拉取

进行测试

如此完成了一次很简单的模块二次开发。

二次开发重要是需求与实现,将自己的需求完整的实现出来即可,不一定是框架意义上的开发才算二次开发,一定要明白自己需要的是什么,代码逻辑是什么,掌握好代码逻辑,二次开发也不算是很难的事情。

*本文原创作者:煜阳yuyang,本文属于FreeBuf原创奖励计划,未经许可禁止转载