对于FreeSWITCH系统保护来说,VoIP安全是一个越来越重要的主题。保护策略包括主动防御和被动防御。FreeSWITCH中的主动防御技术包括各种类型的加密技术,它们用于SIP和RTP通信,以防止篡改或窃听电话。FreeSWITCH的被动防御技术,与其它开源工具结合,可以阻止未知来源的可疑或恶意传输,并阻止滥用或欺诈。在生产环境中运行时,将FreeSwitch功能与通常可用的开源VoIP工具相结合的重要性益发突显。
本章内容将分为以下四个小节:
网络级保护信令保护音频保护密码保护大多数恶意用户利用开放的网络端口入侵VoIP系统。从弱密码到已知软件的BUG,他们寻找一切可利用的东西,并试图利用这些来控制电话系统的配置和路由。他们一般的目的是进行盗打、窃听电话或窃取信息(如语音邮件)。
由于网络是系统的入口点,因此请务必密切关注网络的设置方式,并利用FreeSwitch中的某些功能进一步保护你的系统。
在开放的互联网上,SIP是一种经常被盗用的技术。在多数场景下,恶意黑客会尝试扫描某个范围的IP地址,向5060端口发送UDP数据包,嗅探服务端的反应。一旦他们找到有响应的服务器,他们就会尝试强行使用普通密码,或者干脆尝试拨号。在某些情况下,它们还会向服务器发送大量假注册或其他数据包,破坏系统正常运行的能力。
平均来说,一台SIP服务器接入互联网30分钟后,就会开始受到黑客和脚本的攻击。如果你跟踪SIP包,你将会看到很多REGISTER尝试或INVITE尝试,它们的user-agents是SIPvicious、friendly-scanner或SIPcli(还有那些更努力把自己伪装成“普通”话机的人)。是的,他们都是有目的的。
保护FreeSWITCH系统最基本的方法之一是分离SIP接口,并在每个接口上强制执行不同的防火墙或IPTables规则。
正如你在前端章节所学的那样,FreeSWITCH允许你设置不同的Sofia SIP接口,这样,你就可以在同一系统的不同IP地址:端口上接收与发送SIP消息。可能不太明显的是,这个设置对于提供额外的安全性和稳定性很有用。
就安全性而言,Sofia SIP profiles有默认的context用于控制来电路由。这些contex可以默认配置为严格受限的拨号方案context。如果你把受限的拨号方案context与SIP profile相关的配置结合,就不太可能有人通过你的系统发送欺骗性的SIP请求,即使你不小心造成了一个小的错误配置。
此外,每个Sofia SIP profile都可以配置自己独立的访问控制列表(ACL)。通过这种方式,可以对面向外部的SIP profile (IP地址)施加更严格的限制,对私有IP地址施加更宽松的限制。
在稳定性和性能方面,关于FreeSWITCH的设计,一个鲜为人知的事实是每个Sofia SIP接口都是一个单独的线程。这意味着,通过为每个端口和IP分配单独的线程,可以在一定程度上把人可能对系统造成的任何干扰降低到最小程度。虽然这绝不是保护系统的万无一失的方法,但是当受到恶意攻击时,任何额外的解决方案都是有帮助的。
在最简单的形式中,为你的运营商或网络电话提供商(ITSP)单独配置一个SIP profile,把它与内部话机所使用的SIP profile隔离开来,本质上是非常有益的。大多数恶意攻击始于5060端口的扫描,并发现其中的SIP交互。在这点之上,他们将尝试各种组合来突破我们的鉴权防线,或以其它方式滥用该端口。如果你限制这个IP的访问,并把端口改为一个随机的值 ,通过ACL控制你的运营商访问权限,那么即使你的用户名和密码泄漏了,你也能阻止他们访问系统。
下图展示了人们使用FreeSWITCH时常用的缺省组网设置:
另一种组网方式是:使用独特的,不同寻常的端口,让黑客难以找到它。进一步,你可以用防火墙限制运营商的访问端口,同时,为内部话机开放另一个端口。那么,组网结构将变成下图这样:
为了实现上图的示例,即运营商通过5678端口通信,而内部话机通过23000端口通信,你可以这样配置:
<profile name="incoming_from_pstn"> <settings> <param name="auth-calls" value="true"/> <param name="apply-inbound-acl" value="my_carriers"/> <param name="context" value="inbound_call"/> <param name="sip-port" value="5678"/> ... other settings here ... </settings> </profile>
上面这个是供运营商访问的Sofia profile,运营商必须把呼叫发到5678端口。当呼叫抵达这个端口时,将适用my_carriers 这个ACL列表,它确保只有来自运营商的呼叫才能通过。如果你在my_carriers ACL中犯了什么错误,这没什么大不了,它配置的context是inbound_call,这个context只允许入局呼叫,不允许出局。这是一套相当可靠的限制条件。
此外,由于你知道只有你的运营商会通过5678端口与你通信,那么你可以修改你的防火墙或IPTable,让这个端口只接受运营所属IP的数据。对于入局访问来说,这是一种简单有效的控制方式。
接下来,你需要为内部用户建立一个profile:
<profile name="customer_access"> <settings> <param name="auth-calls" value="true"/> <param name="apply-inbound-acl" value="default_deny_list"/> <param name="context" value="customer_call"/> <param name="sip-port" value="23000"/> ... other settings here ... </settings> </profile>
这个Sofia SIP profile供内部用户使用,你的客户所发起的呼叫必须发给23000这个SIP端口。这个端口的通信要求鉴权,并用有一个缺省的ACL列表叫default_deny_list,它缺省拒绝所有流量。这个机制要求强制鉴权,也就是说,必须提供合法的用户名,并且校验其密码。如果用户信息校验通过,呼叫将被转给customer_call context,在这里进一步处理。
这个示例复杂一些,展现另一种网络隔离的方式,假设你有网络路由设备,那么你可以对网络进行物理分割(独立网络电缆和路由器),或者建立子网或VLAN(参见下一章)。在更复杂的组网结构中,你还可以通过操作系统,为不同的网卡绑定不同的IP地址。除了把SIP端口映射到不同的网络接口之外,还可以把event socket和其它FreeSWITCH管理端口映射出来。
为了实现这个方案,你需要设置两个Sofia SIP profiles,就像这样:
<profile name="incoming_from_pstn"> <settings> <param name="auth-calls" value="true"/> <param name="apply-inbound-acl" value="my_carriers"/> <param name="context" value="inbound_call"/> <param name="sip-port" value="5678"/> <param name="sip-ip" value="2.3.4.5"/> ... other settings here ... </settings> </profile> <profile name="customer_access"> <settings> <param name="auth-calls" value="true"/> <param name="apply-inbound-acl" value="default_deny_list"/> <param name="context" value="customer_call"/> <param name="sip-port" value="23000"/> <param name="sip-ip" value="212.222.33.111"/> ... other settings here ... </settings> </profile>
请注意其中的SIP IP设置,不同的接口是不同的。一个是2.3.4.5,另一个是212.222.33.111。FreeSWITCH会根据Sofia SIP profile中配置的IP地址尝试连接不同的物理网口。这样,你可以为FreeSWITCH系统中的不同网口,配置不同的防火墙规则和网络连接。
在这个场景中,2.3.4.5中一个内部IP地址,它不能在公网中路由;而212.222.33.111则是一个公网IP地址,在公网中是可路由的。除非你有用户在外部网络中,否则212.222.33.111将只开放给对接的运营商。如果内部用户需要通过公网访问,可以通过VPN接入你的网络。这将是最安全的策略。
前面描述的场景,可以通过下图说明:
如上图所示,内部话机与FreeSWITCH上绑定IP地址为2.3.4.5的网卡通信,而运营商则与绑定为212.222.33.111的网卡通信。
VLAN是一种将电话与本地网络上的数据通信隔离开来的绝佳方法,如果操作正确,它们可以提高通话质量,同时防止恶意活动。
你不愿意看到本地局域网的数据流量(有人在拷贝电影或备份大文件)影响到电话通信的共享带宽,从而降低音/视频通话的质量。
VLAN经常被忽略,但事实上,把电话网络和计算机网络混合在一起往往会造成巨大的伤害。在同一网络中,识别一台设备的地址并登录是很简单的。从中可以很轻松地提取很多话机的SIP用户名和密码。比如,你登录一台老式的Polycom话机后,就可以导出包含电话凭据的配置,并以纯文本形式查看它们。如果话机位于网络中的一个私有网段,那么要达到相同目的就要面临更大的挑战。
除了直接操纵话机外,VLAN还阻止计算机上运行的工具向语音网络发送虚假信息。这包括一些简单的场景,如未经授权的软电话,劫持一个分机并发送虚假的BYE消息,从而把本应该继续通话的话务故意挂断。
值得注意的是:VLAN对大多数网络都是可用的,无论是基于端口标记的网络(在交换机上指定物理口分配VLAN),还是基于软件标记的网络都适用(通过网卡,或操作系统在IP报头中用特定的VLAN号标记每个数据包)。
VLAN的设置方法超出本书的讨论范围。然而,应该注意的是,几乎所有流行的台式话机和最新的网络设备都支持VLAN,包括基于软件和基于端口的VLAN标记。
检测试图访问系统的入侵者,或故意创建拒绝服务或类似类型的干扰的入侵者是一种挑战。虽然不寻常的流量有时候看起来很明显,但是在设置自动检测和阻止黑客尝试的规则时,必须考虑一些边缘情况。
有些工具通过发送大量的假的授权尝试消息,并忽略SIP中的授权质询,以此冲击VoIP系统。有一款很常见的攻击工具叫friendly scanner或SIPvicious。这类工具使系统忙于处理伪造的请求,从而让系统过载,处理真正的请求变得困难。另一种可疑行为是短时间内频繁拨打长途或国际长途电话。
在尝试使用系统中的凭据(识别与否)时,FreeSWITCH提供了记录告警信息的功能。然后可以用Fail2Ban之类的程序监视这一日志行的输出频率。如果频率达到我们设定的阈值,那么对应的IP地址可能会被堵塞一段时间(或永久)。如果在相对较短的时间内从同一IP地址进行大量授权尝试,通常认为这是可疑的。
为了确保FreeSWITCH收到无效身份验证尝试时生成警告,可以修改SIP profile并添加以下设置:
<param name="log-auth-failures" value="true"/>
收到授权尝试时,会生成一条日志信息,内容看起来是这样的:
[WARNING] SIP auth challenge (REGISTER) on sofia profile 'customer_access' for [user_rdkj7h@2600hz.com] from ip 184.106.157.100
Fail2Ban 会自动统计这些日志出现的频率,如果达到设定的阈值,那么系统将自动阻塞来自IP 184.106.157.100的通信数据。
Fail2Ban是一个第三方程序,它运行在后台监视日志。如果特定的日志行(比如我们前面提到的授权尝试)出现的频率达到某个值(指定时间周期内超过指定的次数),Fail2Ban会触发一个响应动作。可以向你发封电子邮件进行告警,或自动添加一条IPTables规则,阻断相应IP的通信。
本书不是Fail2Ban的完全指南。但是,在本章后续内容中,我们还是会给一些示例脚本。
配置Fail2Ban需要创建好几个文件,它们指示Fail2Ban需要关注什么样的日志,如果有匹配的日志应该做些什么。
Fail2Ban的默认配置中有一个用于存放filter的目录。这些filter包含用于匹配日志的字符串,相当于筛选器。如果你需要在日志中查找不同类型的可疑输出,可以设置任意多个filter。与FreeSWITCH非法登陆输出的错误日志相结合,立马实现一套有效的过滤机制。
另一个文件叫jail配置文件,它将filter应用于一套规则之中,比如说错误允许出现的频率,超过阈值时需要执行什么响应动作之类的。Jail配置文件有效地定义了filter匹配时的应对措施。
Filter配置文件让我们首先浏览一个filter配置文件。这类文件通常存放在/etc/Fail2Ban/filter.d/目录下,并根据你的筛选内容命名。这个文件包含一个filter定义,用于查找授权尝试失败的日志。它的格式是标准的正则表达式。在这个案例中,我们认为FreeSwitch在有人试图以无效凭据注册或进行呼叫时都会失败。
Fail2Ban社区的友好人士为FreeSWITCH用户维护了一个定制的配置。可以通过他们的git仓库获取最新的版本( https://github.com/fail2ban/fail2ban/blob/master/config/filter.d/freeswitch.conf),把它另存为/etc/Fail2Ban/filter.d/freeswitch.conf。本文撰写时,它的内容是:
# Enable "log-auth-failures" on each Sofia profile to monitor # <param name="log-auth-failures" value="true"/> # -- this requires a high enough loglevel on your logs to save these messages. # # In the fail2ban jail.local file for this filter set ignoreip to the internal # IP addresses on your LAN. # [Definition] failregex = ^\.\d+ \[WARNING\] sofia_reg\.c:\d+ SIP auth (failure|challenge) \((REGISTER|INVITE)\) on sofia profile \'[^']+\' for \[.*\] from ip <HOST>$ ^\.\d+ \[WARNING\] sofia_reg\.c:\d+ Can't find user \[\d+@\d+\.\d+\.\d+\.\d+\] from <HOST>$ ignoreregex = # Author: Rupa SChomaker, soapee01, Daniel Black # https://freeswitch.org/confluence/display/FREESWITCH/Fail2Ban # Thanks to Jim on mailing list of samples and guidance
它将关注FreeSWITCH 中注册(REGISTER)和呼叫(INVITE)失败的日志信息。
Jail 配置
现在,将这个filter与一个jail条目结合起来,如果在一段时间内收到太多失败的邀请或注册,那么这个条目会阻止一个IP地址。
升级Fail2Ban时可能会覆盖/etc/jail.conf文件。创建一个/etc/fail2ban/jail.local文件,并输入以下内容,注意把FreeSWITCH日志文件的路径修改为你环境中的路径(你的日志文件路径可能是/usr/local/freeswitch/log/freeswitch.log),并把sender字段中的Email地址修改为你自己的:
[freeswitch] enabled = true port = 5060,5061,5080,5081 filter = freeswitch logpath = /var/log/freeswitch/freeswitch.log action = iptables-allports[name=freeswitch, protocol=all] sendmail-whois[name=FreeSwitch, dest=root, sender=fail2ban@example.org] maxretry = 10 findtime = 60 bantime = 600 # "ignoreip" can be an IP address, a CIDR mask or a DNS host ignoreip = 127.0.0.1/8 192.168.2.0/24 192.168.1.0/24
上面设置中,使用名为freeswitch的filter,如果在指定周期60秒内(findtime),某个IP地址有10次(maxretry)的注册或呼叫授权失败,那么阻止入侵者的IP并发送一封告警邮件。如果在60秒内满足筛选器(意味着发生10次失败的邀请或注册授权尝试),则会在600秒(bantime)内完全禁止有问题的IP地址,并向配置的管理员地址发送警报邮件。
不要制造冤假错案Fail2Ban的配置必须调优,这样一个大型的站点才不会在恢复上线时被踢除下线,因为刚上线时,它所属的所有话机都会在同一瞬间内重新注册。举例说明:如果你有一个Fail2Ban的速率限制条目(关于“良好”流量数量的规则,而不是关于“失败尝试”数量的规则),如果该站点正好在5秒钟内向你发送了50个身份验证请求,你可能不希望Fail2Ban阻止它们。因为这个站点有50部话机,假设站点停电了,在供电恢复的瞬间,所有话机都会同时尝试重新注册,如果我们只管数量,瞬间流量过大将导致它们被阻止。这显然不是我们的意愿。通过流量判断“拒绝服务”(Denial of Service,DOS)攻击时千万要小心。
设置Fail2Ban时,要注意做好边缘测试,比如我们刚讨论过的停电的场景。
已经特别针对“经典”或“普通”SIP开发出针对性的加密技术(和基于WebRTC的SIP不同,这点后面会有介绍)。
SIP加密基于两个概念——加密信令和加密媒体(音频/视频)通信。与任何标准加密机制一样,SIP加密利用标准加密库,并涉及密钥交换和密码协商,保证安全地传输和接收信息。
SIP中使用的主要加密算法(稍后将详细介绍)与这些场景非常相似:Web上的SSL或ssh连接远程服务器时的密钥交换。在任何一种交换中,主要目标都是在双方之间建立一种算法和一个只有他们双方知道的共同秘密,并把它们用于对实际内容(比如说电话)的加密和解密。
在任何一种交换中,主要目标都是在双方之间建立一个加密算法和一个只有他们知道的共同加密秘密,这可以用来加密和解密实际内容——电话呼叫。
许多人大谈术语TLS、SSL和SRTP,却没有完全理解它们。为了充分保护通信,这里建议同时对信令和音频实施加密策略。
在接下来几节中,我们将挨个介绍各种加密策略的细节。
FreeSWITCH有一些可用的加密选项。你可以加密信令(SIP消息)、媒体(RTP携带的音频流),或者对两者都加密。
TLS (传输层安全)对基于TCP连接的所有内容加密,但它有个缺点,即TCP引入的抖动的时延。UDP通常是RTP的首选,使用TLSV1会带来一点额外的流量开销。
ZRTP的优点是它允许端到端(end-to-end)加密而不需要预先交换密钥或证书,但配置起来有些复杂,特别是对于某些客户端。ZRTP协议是由Phil Zimmermann参与共同设计的,他就是创建PGP加密的那个家伙。更多信息请访问http://zfone.com。
SSL (Secure Sockets Layer) v2/3; SSLv2已经被发现漏洞,自2011年以来已经被弃用,而SSLv3在2014年被破解,并在2015年被弃用(可以谷歌搜索POODLE攻击)。我们没有必要使用一种可破解的加密方式,因此,禁用SSL算法。
我们的默认配置已经纠正这个问题很长时间了,但保险起见,你还是检查一下自己的设置。希望你的tls-version参数配置中,不要出现sslv2或sslv3。
打开/usr/local/freeswitch/conf/vars.xml文件,(如果你是用安装包安装的,那么可能是/etc/freeswitch/vars.xml),找到这一行,确保它的内容是这样的:
<X-PRE-PROCESS cmd="set" data="sip_tls_version=tlsv1,tlsv1.1,tlsv1.2"/>
然后检查所有SIP profiles,看看它们是引用了这个变量还是有自定义的。一般都是继承全局变量设置的:
<param name="tls-version" value="$${sip_tls_version}"/>
对于任何类型的SIP加密,你都需要由认可的证书颁发机构颁发("签名")的安全证书,该证书负责证明你的身份。
你可以使用模拟证书颁发机构的软件(自己充当证书颁发机构)来制作“自签”证书作弊。千万不要这样,请阅读一下"WebRTC, SIP 和 Verto"那一章中的“证书”那一节。
证书与使用SSL作为加密方法无关,“SSL证书”只不过是调用安全证书的旧方法(因为当时使用的是SSL,但它也可以用于TLS,这完全没有任何问题,始终是同一个证书)。此外,如果你禁用SSL,你依然需要证书,因为TLS、DTLS和其它所有的加密算法都需要证书。
你需要使用真实的、实际的证书颁发机构颁发的证书(而不是“自签”证书)。这些“真实”的证书,可以被SIP客户端、WebRTC客户 端、浏览器和物联网自动接受。
从https://letsencrypt.org,你可以免费获取合法证书,你也可以探寻最适合自己需要的付费解决方案(比如说通配证书)。
关于证书获取安装的细节,请参考第5章“WebRTC,SIP与Verto”的“证书”一节
SIP信令中包含你的话机用于发起和接收呼叫的鉴权信息,还包含主叫与被叫电话号码、身份信息,默认情况下,都是以纯文本的形式描述的。这很容易嗅探和假造。加密可以增加它的难度。此外,如果你使用SRTP(安全RTP),那么SIP信令中还包含了保证音频安全用的加密密钥。如果有人以纯文本的方式获取这些密钥内容,那么他就很容易攻击你的加密媒体。
当你拿到证书之后,你需要告诉FreeSWITCH使用这些证书。为了达到这个目的,需要设置/usr/local/freeswitch/conf/vars.xml里的几个变量:
<X-PRE-PROCESS cmd="set" data="sip_tls_version=tlsv1,tlsv1.1,tlsv1.2"/> <X-PRE-PROCESS cmd="set" data="internal_tls_port=3361"/> <X-PRE-PROCESS cmd="set" data="internal_ssl_enable=true"/> <X-PRE-PROCESS cmd="set" data="external_tls_port=3381"/> <X-PRE-PROCESS cmd="set" data="external_ssl_enable=false"/> <X-PRE-PROCESS cmd="set" data="sip_tls_ciphers=ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"/>
注意:在vars.xml中,TLS(由于历史原因,以"ssl"命名)选项对内部和外部profile是分开设置的。
最后一行设置使用的密码算法。如果你需要抓包分析自己的SIP TLS 包(使用私钥),那么你只能使用非完全正向保密(PFS)算法。因此,使用AES256-SHA:
<X-PRE-PROCESS cmd="set" data="sip_tls_ciphers=AES256-SHA"/>
在vars.xml中设置好默认值后,检查你的SIP profile,确保其中的参数反映了你的意志(注意"<!--"与"-->"间的内容是被注释掉的):
<!-- TLS: disabled by default, set to "true" to enable --> <param name="tls" value="$${internal_ssl_enable}"/> <!-- Set to true to not bind on the normal sip-port but only on the TLS port --> <param name="tls-only" value="false"/> <!-- additional bind parameters for TLS --> <param name="tls-bind-params" value="transport=tls"/> <!-- Port to listen on for TLS requests. (5061 will be used if unspecified) --> <param name="tls-sip-port" value="$${internal_tls_port}"/> <!-- Location of the agent.pem and cafile.pem ssl certificates (needed for TLS server) --> <!--<param name="tls-cert-dir" value=""/>--> <!-- Optionally set the passphrase password used by openSSL to encrypt/decrypt TLS private key files --> <param name="tls-passphrase" value=""/> <!-- Verify the date on TLS certificates --> <param name="tls-verify-date" value="true"/> <!-- TLS verify policy, when registering/inviting gateways with other servers (outbound) or handling inbound registration/invite requests how should we verify their certificate --> <!-- set to 'in' to only verify incoming connections, 'out' to only verify outgoing connections, 'all' to verify all connections, also 'subjects_in', 'subjects_out' and 'subjects_all' for subject validation. Multiple policies can be split with a '|' pipe --> <param name="tls-verify-policy" value="none"/> <!-- Certificate max verify depth to use for validating peer TLS certificates when the verify policy is not none --> <param name="tls-verify-depth" value="2"/> <!-- If the tls-verify-policy is set to subjects_all or subjects_in this sets which subjects are allowed, multiple subjects can be split with a '|' pipe --> <param name="tls-verify-in-subjects" value=""/> <!-- TLS version default: tlsv1,tlsv1.1,tlsv1.2 --> <param name="tls-version" value="$${sip_tls_version}"/> <!-- TLS ciphers default: ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH --> <param name="tls-ciphers" value="$${sip_tls_ciphers}"/>
使用TLS可能会有一些陷阱和混乱。TLS是基于TCP的,而不是UDP。如果话机位于防火墙或NAT穿越机制之后,FreeSWITCH主动连接话机(比如向话机传递呼叫)可能会连接不上。你必须确保所有防火墙的配置支持TCP入局穿透。此外,还要保证你的话机上的时间配置正确,因为如果时间相差太多,你可能会收到神秘的证书错误消息,导致不能正常建立握手。
对RTP流(音频或视频)进行加密,可以保证SIP通话的实际内容不会被窃听、录音非法截取。有多种方法可以达成这个目标。
实现加密的核心在于:发送与接收双方就加密的方法和数据传输过程中加密与解密的算法达成一致。换句话说,如果不是两边都支持的加密方法,你就不能使用。此外,加密算法是基于密钥交换完成的,这通常在呼叫开始时进行。密钥交换有点类似于双方交换密码,但它是以电子方式进行的,而且通常是自动的。
加密音频和视频媒体流有两种流行方式:SRTP和ZRTP。
SRTP由来自思科和爱立信的协议与加密专家组成的一个小组在2004年开发。SRTP定义了一种传输和接收RTP的方法,它在消息中携带身份验证和完整性信息,还有RTP数据的回放保护信息。因为它比较老,而且由关键的IP电话硬件供应商开发的,所以影响广泛,大部分SIP设备都采用它。几乎市场上可以见到的所有设备都支持SRTP。
ZRTP是由Phil Zimmermann (PGP的创建者)在2006年开发的。它是一个较新进入者,使密钥协商自动化,大大简化了设置和操作,以确保RTP通话的安全和加密。它还具有不依赖于服务器端加密的额外优势。加密可以发生在不知道RTP流内容的服务器之间。然而,目前支持ZRTP的硬件数量有限,如果这个协议要完全成功,还需要多数硬件制造商实现。
FreeSWITCH既支持SRTP也支持ZRTP,不要着急,这一章会介绍怎么使用它们。
SRTP是一种加密机制,它在SIP呼叫建立过程中协商。SIP对方的双方必须都同意支持RTP加密,并在SIP信令包中交换密钥。SRTP所使用的密钥是在SIP协商过程中交换的。然后用这些信息对媒体流加密。
SRTP支持对RTP数据进行加密,对RTP UDP数据包加密的开销比较小。这样做的好处是:呼叫数据加密了,但仍然通过UDP通信,使网络时延最小化,而且可以和未加密流共享网络遍历机制。
一般来说,对于现有的安装,SRTP是最适合防火墙的策略,因为使用RTP时已经完成了网络上的实质传输工作。在FreeSWITCH中配置SRTP相当容易。
因为已经完成了使RTP在网络上正确传输的实际工作。SRTP在FreeSwitch中配置相当容易。
注意:除非你同时启用SIP的加密配置(前面讨论过的),否则SRTP的密钥将在网络中裸奔。为了在你的话机与FreeSWITCH之间实现完全的安全连接,你应该把SIP加密和SRTP加密结合起来使用。这可以防止任何窥探的中间人攻击。如果只启用SRTP,那么只有RTP包的有效载荷部分数据是受保护的。
启用SRTP
你可以在拨号方案中为每一路呼叫单独启用SRTP,需要时设置以下标记:
<action application="set" data="sip_secure_media=true"/>
这需要对出局和入局的两条leg上都执行,才能完全有效。当然,向你提供PSTN落地网关的ITSP供应商可能不支持SRTP,因此,你可以只在FreeSWITCH与终端间启用SRTP。
通过检查变量${sip_secure_media_confirmed}来确定媒体安全的情况。我们给个示例,如果SIP媒体受保护,下面代码块将播放一个bong提示音:
<extension name="is_secure"> <condition field="${sip_secure_media_confirmed}" expression="^true$"> <action application="sleep" data="1000"/> <action application="gentones" data="${bong-ring}"/> </condition> </extension>SRTP调试
在调试加密通话时,SIP数据包中有一个有用的提示,它说明电话是否正确地请求加密。如果你在SIP协商过程中提供RTP加密能力,你可以在SIP消息中看到一行a=crypto描述(你可以在FreeSWITCH 控制台上看到TLS加密的SIP消息文本,方法是执行"sofia global siptrace on"命令)。
ZRTP是一种基于SRTP的加密算法,与SRTP不同的是,它在媒体流中交换加密密钥,使加密过程更安全,而且对不支持协议的服务器是透明的。这使ZRTP比SRTP更灵活,并为终端提供完全控制,以处理所有层面的加密需求,还没有中间人攻击的风险。ZRTP也不需要在媒体建立之前交换密钥。密钥交换发生在RTP对话建立的初始期间。RTP协议在RFC6189中有充分的阐述。
ZRTP的一个主要优势是它可以通过代理工作。通常使用SRTP,通信路径中的每个点都需要知道加密协议,并且通过对媒体流加密和解密。这样的话,如果你有权限访问路径中间的节点,那就意味着你可以在中间监听。使用ZRTP时,正好相反,中间的服务器根本不了解其中的加密协议。它们只是认为自己在透传标准的RTP数据包。因为服务器需要关心RTP流里所包含的内容,所有只需要两边的终端支持ZRTP,这样对话的安全性保障才更彻底。代理不需要理解或传递加密信息。
ZRTP在FreeSWITCH中的另一个优势是它是默认启用的。ZRTP协议本身把协商包插入到RTP对话的初始包中,并等待应答。如果收到应答,那么在其它终端请求时,就能自动启用ZRTP加密。
因为zrtp是一种不那么流行的协议,所以除了支持ZRTP的电话和软电话客户端之外,还有ZRTP软件代理可以工作。这个代理允 许你简单地安装一款叫Zfone的插件,就能把天生不支持ZRTP的软件改造掉,让它自动完成RTP流量的加密。Zfone在后台默默地运行,发生密钥交换时,会弹出通知消息告诉你。此外,还有一款SDP可以帮助你开发支持ZRTP的软件和硬件。
启用 ZRTP
首先,编辑/usr/local/freeswitch/conf/autoload_config/switch.conf.xml,把rtp-enable-zrtp属性设置为"true":
<param name="rtp-enable-zrtp" value="true"/>
其次,你可以在拨号方案中启用或禁用ZRTP支持,命令如下:
<action application="set" data="zrtp_secure_media=[true|false]"/>
ZRTP协商时,你将会在FreeSWITCH的控制台上看到这样的输出说明正在提供ZRTP:
[DEBUG] switch_rtp.c:928 [ zrtp main]: START SESSION INITIALIZATION.
接下来,ZRTP协议将开始向RTP流中注入ZRTP协商包。如果ZRTP成功开启会话,你将看到一条确认消息,后面跟着一系列ZRTP日志消息,表明现在通道进入安全状态,例如:
[zrtp protoco]: Enter state SECURE (DH).
您还将看到所选共享机密缓存已自动存储,将在下次呼叫时用于比较:
[ zrtp cache] Storing ZRTP cache to </usr/local/freeswitch/db/zrtp.dat>...
在演示配置中,当你呼叫9664(或呼叫5000接入IVR,然后按3)时,会同时尝试SRTP和ZRTP。如果你从启用SRTP或ZRTP的软电话上呼叫(比如Linphone),你将在听到音乐之前听到"This call is secure"的提示音。
WebRTC默认是加密的,使用TLS进行wss信令加密,使用DTLS(基于UDP的TLS)进行RTTP加密。请参阅WebRTC那一章的加密无处不在那一节。
对媒体和数据流的加密是强制的。不对媒体流加密,你根本无法建立WebRTC通信。媒体流包括音频、视频,还可能有数据流。媒体流通过DTLS交换密钥,加密为SRTP。
会话协议的信令(SIP或VERTO)也是加密的。承载这类信令的传输层通常是安全的WebSocket。在定义WebRTC信令服务器和终端时,URI前缀WSS:// (WebSocket Secure)无处不在。WSS信令交换由TLS加密。
在FreeSWITCH系统中,很多时候都用到密码:话机注册、发起呼叫、FreeSWITCH向外部网关/ITSP注册、管理员通过Event Socket连接FreeSWITCH系统时的身份验证(比如说fs_cli)。这些场景经常使用弱的明文密码。
此外,许多用户将密码设置为简单、易于猜测的组合。更糟糕的是,有些人甚至从未更改或设置过语音信箱密码,保留了默认设置。
这些密码通常是有针对性的,一旦泄漏,就会被用于实施欺诈。
以下是一些可以缓解这些痛点的机制。
不要以明文形式在磁盘中保存注册凭据。在你的用户目录中定义SIP凭据时,把这样的格式:
<param name="password" value="samiam"/>
替换为a1-hash 预计算的密码,就如:
<param name="a1-hash" value="c6440e5de50b403206989679159de89a"/>
在linux平台上生成a1-hash,可以获取username:domain:password的值,并对它进行MD5运算,它用到你的用户名、域名和密码,通过冒号绑定在一起。例如:
echo -n "darren:2600hz.com:pass1234" | md5sum b62d1e3e27773ffd173c87e342a6aace
在用户目录条目中使用返回的散列值。这意味着您不必将实际的SIP注册凭据存储在磁盘上,这样,入侵你文件系统的黑客也将无看到你的实际密码。
下面是一个完整的示例:
<user id="darren"> <params> <param name="a1-hash" value="c6440e5de50b403206989679159de89a"/> </params> </user>语音信箱历史上曾遭到各种原因的攻击。除了简单监听别人的消息之外,语音信箱还经常被利用,因为它具有远程开启回拨或前转的功能。最常见的一种攻击策略是入侵语音信箱系统,并把个人呼叫转移到一个昂贵的国际长途目标上,适时间内盗用数千美金的话费。语音邮件密码黑客行为即使在今天也很流行。
防范弱的语音信箱密码相当简单。FreeSWITCH在数据库中以纯文本的形式存储语音信箱密码,允许你扫描弱诸如1111、1234之类的密码。你还可以扫描出哪些账号是直接把分机号设置为密码的,这是另一种常见的不安全策略。
要扫描弱密码,你需要写一个脚本来查找存储语音信箱配置的数据库。假设你使用的是FreeSWITCH的默认配置,那么语音邮箱数据库是一个SQLite文件,它位于你FreeSWITCH目录下的DB文件夹中。根据你的FreeSWITCH安装方式,这个目录的具体位置会有些许不同,最有可能的地方是/opt/freeswitch/db、/usr/local/freeswitch/db或/var/lib/freeswitch/db。
检查数据库的一个示例方法是使用以下简单的SQLite查询
sqlite3 db/voicemail_default.db "select * from voicemail_prefs where password=1234 or password=1111"
这条命令调用SQLite3在的linux客户端去查找voicemail_prefs这张表,检查所有密码设置为1111或1234的记录。它会在屏幕上打印出所有信箱相关的信息,包括用户名、域名。然后,你可以采取纠正措施,要么强制重置密码,要么与用户联系,建议他们更改密码。
只是简单介绍当今最常见的VoIP安全技术。此外还有很多资源,如www.hackingvoip.com网站、关于入侵VoIP和计算机安全的书籍。
采取本章中概述的基本步骤,将为你提供足够的安全防范当今最常见的黑客攻击、DoS攻击和盗用。这应该能够让大多数中小型PBX或承载VoIP的系统安全可靠地运行。
现在我们即将进入本书的最后一章。它告诉我们:当我们碰到出错问题时;我们无法实现某些东西时;我们碰到一个 FreeSWITCH的BUG时,需要怎么处理。我们将学习有关故障排除、寻求帮助和报告问题的基本知识。
