在Internet上部署sip服务器的同学都知道,各种scanner不停的探测,尝试各种呼叫规则,尝试各类国际呼叫,如果没有前置防火墙,会被烦死,笔者就亲见因sip用户密码设置太简单而被恶意盗打国际长途的案例,因国际长途费用巨大,还被报警处理。今天笔者就以FreeSWITCH+CentOS7.9+firewalld+fail2ban单机在internet部署为例,实战讲解sip安全加固。

本篇内容假定您已经安装并了解firewalld和fail2ban,否则您应该先回头了解一下这两位,不然其中的配置理解有困难。另外,操作系统加固和sip用户密码加固不在本篇文章讨论范围内。

本篇文章的精髓在于对firewalld的理解,其中用到的PREROUTING_direct链已经内置在firewalld中。对永久封禁,可以不使用PREROUTING_direct,只使用PUBLIC_direct,但对于临时检测到的sip攻击,想要有效的配合fail2ban进行封禁,最好使用PREROUTING_direct,不然您会发现临时封禁可能会失效,至于为什么会这样,有赖于您对firewalld和iptables的理解。

实战之前,先在firewalld上放行sip,注意,没有用sip service方法,主要是不想用 系统的nf_conntrack_sip。

#FreeSWITCH端口设置为5060
firewall-cmd --permanent --zone=public --add-port=5060/udp
#FreeSWITCH RTP端口范围设置为16000-32000
firewall-cmd --permanent --zone=public --add-port=16000-32000/udp

一、永久封禁已知的几种sip scanner,如下:

firewall-cmd --permanent --direct --add-rule ipv4 raw PREROUTING_direct 0 -p udp --dport 5060 -m string --string "VaxSIPUserAgent" --algo bm -j DROP
firewall-cmd --permanent --direct --add-rule ipv4 raw PREROUTING_direct 0 -p udp --dport 5060 -m string --string "friendly-scanner" --algo bm -j DROP
firewall-cmd --permanent --direct --add-rule ipv4 raw PREROUTING_direct 0 -p udp --dport 5060 -m string --string "sipcli" --algo bm -j DROP
firewall-cmd --permanent --direct --add-rule ipv4 raw PREROUTING_direct 0 -p udp --dport 5080 -m string --string "VaxSIPUserAgent" --algo bm -j DROP
firewall-cmd --permanent --direct --add-rule ipv4 raw PREROUTING_direct 0 -p udp --dport 5080 -m string --string "friendly-scanner" --algo bm -j DROP
firewall-cmd --permanent --direct --add-rule ipv4 raw PREROUTING_direct 0 -p udp --dport 5080 -m string --string "sipcli" --algo bm -j DROP

针对信令中的sip agent,直接封禁。按照这个模板,您也可以将您项目中遇到的其他sip scanner加入其中直接禁掉,请注意用到了firewalld内置的PREROUTING_direct链。

二、配置fail2ban对检测到的sip攻击ip进行临时封禁。

1、安装fail2ban后,在centos7.9+firewalld环境下,在/etc/fail2ban/jail.d/下增加freeswitch.conf,内容如下:

[freeswitch]
enabled = true
port     = 5060,5061
action_  = %(default/action_)s[name=%(__name__)s-tcp, protocol="tcp"]
           %(default/action_)s[name=%(__name__)s-udp, protocol="udp"]
logpath  = /opt/freeswitch/log/freeswitch.log
findtime = 5m
bantime = 240h
maxretry = 5

其中的logpath路径根据您自己的实际目录进行配置。

2、此时可以查看/etc/fail2ban/jail.d/00-firewalld.conf,fail2ban使用的默认ban/unban动作是firewall-rich-rules:

[DEFAULT]
banaction = firewallcmd-rich-rules[actiontype=<multiport>]
banaction_allports = firewallcmd-rich-rules[actiontype=<allports>]

启动fail2ban,用测试工具故意向FreeSWITCH发起恶意用户注册,虽然fail2ban检测到了此次scanner攻击,也针对scanner ip进行了ban操作,但实际上FreeSWITCH日志中仍显示有大量的scanner存在,意即scanner发的sip包仍到达了FreeSWITCH,封禁失败。

使用firewall-cmd查看active zone(public)的rich rules,能看到添加的rich-rules:

rich rules: 
        rule family="ipv4" source address="192.168.1.12" port port="5060" protocol="tcp" drop
        rule family="ipv4" source address="192.168.1.12" port port="5061" protocol="tcp" drop
        rule family="ipv4" source address="192.168.1.12" port port="5060" protocol="udp" drop
        rule family="ipv4" source address="192.168.1.12" port port="5061" protocol="udp" drop

使用iptables查看对应的规则如下:

Chain IN_public_deny (1 references)
target     prot opt source               destination         
DROP       tcp  --  192.168.1.12         0.0.0.0/0            tcp dpt:5060 ctstate NEW,UNTRACKED
DROP       tcp  --  192.168.1.12         0.0.0.0/0            tcp dpt:5061 ctstate NEW,UNTRACKED
DROP       udp  --  192.168.1.12         0.0.0.0/0            udp dpt:5060 ctstate NEW,UNTRACKED
DROP       udp  --  192.168.1.12         0.0.0.0/0            udp dpt:5061 ctstate NEW,UNTRACKED

iptables列出的规则已经很能说明问题了,就这默认配置,是没法ban scanner ip的,因为默认没有untrack、正在scan,不满足ctstate条件。

3、既然rich-rule模式不行,按照百度搜索的结果,很多人建议用ipset模式。于是改用firewallcmd-ipset来进行ban/unban的动作,修改/etc/fail2ban/jail.d/00-firewalld.conf

[DEFAULT]
banaction = firewallcmd-ipset[actiontype=<multiport>]
banaction_allports = firewallcmd-ipset[actiontype=<allports>]

再次启动测试工具向FreeSWITCH发起恶意注册,同2)类似,fail2ban也检测到了此次scanner攻击,也针对scanner ip进行了ban操作,但仍旧封禁失败。

使用firewall-cmd查看direct规则:

ipv4 filter INPUT_direct 0 -p tcp -m multiport --dports 5060,5061 -m set --match-set f2b-freeswitch-tcp src -j REJECT --reject-with icmp-port-unreachable
ipv4 filter INPUT_direct 0 -p udp -m multiport --dports 5060,5061 -m set --match-set f2b-freeswitch-udp src -j REJECT --reject-with icmp-port-unreachable

使用iptables查看规则:

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0            udp dpt:53
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:53
ACCEPT     udp  --  0.0.0.0/0            0.0.0.0/0            udp dpt:67
ACCEPT     tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:67
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
ACCEPT     all  --  0.0.0.0/0            0.0.0.0/0           
INPUT_direct  all  --  0.0.0.0/0            0.0.0.0/0           
INPUT_ZONES  all  --  0.0.0.0/0            0.0.0.0/0           
DROP       all  --  0.0.0.0/0            0.0.0.0/0            ctstate INVALID
REJECT     all  --  0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited
Chain INPUT_direct (1 references)
target     prot opt source               destination         
REJECT     tcp  --  0.0.0.0/0            0.0.0.0/0            multiport dports 5060,5061 match-set f2b-freeswitch-tcp src reject-with icmp-port-unreachable
REJECT     udp  --  0.0.0.0/0            0.0.0.0/0            multiport dports 5060,5061 match-set f2b-freeswitch-udp src reject-with icmp-port-unreachable

此时的conntrack记录:

ipv4     2 udp      17 179 src=192.168.1.12 dst=192.168.1.69 sport=5080 dport=5060 src=192.168.1.69 dst=192.168.1.12 sport=5060 dport=5080 [ASSURED] mark=0 zone=0 use=2

看到firewalld、iptables规则以及conntrack记录,对iptables和firewalld比较了解的同学估计也理解了为啥不能ban。。。

4、看了方法2和3的配置以及背后firewalld和iptable的规则,估计同学们有N种思路能让ban正常起来,本篇内容提供两种简单的方法,能让系统正常加固,抵御sip攻击:

1)方法1,启用NOTRACK

firewall-cmd --direct --add-rule ipv4 raw PREROUTING_direct 0 -p udp --dport 5060 -j NOTRACK

2)方法2,配置fail2ban使用firewalld内置的PREROUTING _direct链

使用方法1虽然能对检测到的sip攻击进行封禁,但NOTRACK的方法毕竟对业务路由可能会有影响,这催生了方法2,仅修改fail2ban的默认配置,使用firewalld内置的PREROUTING_direct链就能很完美的实现检测并封禁的功能,如下:

第一步,/etc/fail2ban/jail.d/00-firewalld.conf中使用firewall-ipset

第二步,修改/etc/fail2ban/action.d/firewallcmd-ipset.conf

将actionstart和actionstop中的filter修改为raw,如下:

[Definition]

actionstart = ipset create <ipmset> hash:ip timeout <default-ipsettime> <familyopt>
              firewall-cmd --direct --add-rule <family> raw <chain> 0 <actiontype> -m set --match-set <ipmset> src -j <blocktype>

actionflush = ipset flush <ipmset>

actionstop = firewall-cmd --direct --remove-rule <family> raw <chain> 0 <actiontype> -m set --match-set <ipmset> src -j <blocktype>
             <actionflush>
             ipset destroy <ipmset>

将chain改为PREROUTING_direct,如下:

[Init]

# Option:  chain
# Notes    specifies the iptables chain to which the fail2ban rules should be
#          added
# Values:  [ STRING ]
#
chain = PREROUTING_direct

第三步,修改/etc/fail2ban/action.d/firewallcmd-common.conf

将blocktype改为DROP,如下:

# Option:  blocktype (ipv4/ipv6)
# Notes    See iptables/firewalld man pages for jump targets. Common values are REJECT,
#          REJECT --reject-with icmp-port-unreachable, DROP
# Values:  STRING
#blocktype = REJECT --reject-with <rejecttype>
blocktype = DROP

改完重启fail2ban测试,仅仅通过简单修改fail2ban配置,完美解决了检测sip攻击并封禁的问题。