对车联网安全感兴趣,但却没有实车拿来练手,是一件很可惜的事情。为了解决这个问题,笔者结合自己的车联网安全实践经验,为大家搭建一个高度接近真实车辆的实验环境。这个环境使用了目前流行的多域架构,实现了包括VLAN、防火墙等真实的安全功能,供大家学习和参考。
域架构
对域架构的解释:
1)本实验环境实现了两个经典的通信域VCU和HU,VCU可以理解为整车控制域,而HU则是信息娱乐域,两个域通过以太网进行通信;
2)VCU域实现了车身CAN(BDCAN)和自动驾驶CAN(ASCAN),这两路CAN通过网关相连,用来模拟车身CAN报文发送至自动驾驶模块;
3)HU域实现了仪表CAN(ICCAN)与摄像头CAN(CAMCAN),它们分别与BDCAN、ASCAN通过以太网相连,第一路连接(BDCAN -> ICCAN)模拟车身数据在仪表盘上显示,第二路连接(CAMCAN -> ASCAN)模拟摄像头采集的数据传送给自动驾驶模块;
4)第一路连接与第二路连接通过VLAN进行隔离。
车辆功能
通过ICSim[1]模拟车辆功能,ICSim是一个开源的车辆仪表模拟器,该模拟器包含controls和ICSim两个模块,其中controls负责生成模拟的车辆数据,以CAN报文的方式发送给虚拟的CAN接口,ICSim从虚拟CAN接口读取CAN报文,并在仪表上更新对应零件的状态,如车速、车门状态等等。
(ICSim仪表和操作界面)
在我们这个架构中,ICSim和controls分别连接到两路不同的CAN上,其中ICSim连接到HU域的ICCAN,代表真实的仪表盘;controls连接到VCU域的BDCAN,代表真实的车身部件。VCU域与HU域通过以太网进行连接,controls产生的CAN报文通过以太网传送给ICSim。这种实现与真实的整车域架构及其接近,因为有些车型的仪表确实被划分到了HU域,以太网作为VCU与HU的通信协议也是当下比较流行的域架构。
通过如下方式创建vcanic和vcanbd:
sudo ip link add name vcanic type vcan
sudo ip link set dev vcanic up
sudo ip link add name vcanbd type vcan
sudo ip link set dev vcanbd up
接下来将ICSim与HU域的vcanic绑定,controls与VCU域的vcanbd绑定:
./icsim vcanic
./controls vcanbd
此时,代表车身零部件的controls产生的报文还不能顺利达到ICSim,因为vcanic与vcanbd两路CAN总线目前还未联通,我们将通过以太网的方式将这两路CAN连接起来,同时也将意味着VCU与HU的联通。
CAN-ETH通信
以太网的实现使用开源项目cannelloni[2],cannelloni的核心原理是通过UDP协议传送CAN报文,如下图所示:
(图片来自论文《Mapping CAN-to-ethernet communication channels within virtualized embedded environments》)
因为我们这个实验是在一台机器上进行的,所以我们将通过不同的端口区分VCU和HU这两个独立的通信域,结合划分广播域的需求,我们将通过vconfig创建带有vlan id的虚拟网卡。
VLAN划分广播域
考虑到通过以太网传输的报文类型包含了安全性要求比较高的ADAS(自动驾驶)报文,我们的想法是根据报文的不同安全等级来划分广播域,将普通控制报文和自动驾驶报文通过VLAN划分到不同的网络,相互之间不能访问。
首先需要在真实的网卡上创建带有vlan id的虚拟网卡:
$ sudo vconfig add enp0s31f6 20
$ sudo vconfig add enp0s31f6 30
创建结果如下:
$ ip link
(此处省略不相关网卡)
5: enp0s31f6.20@enp0s31f6: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 70:85:c2:7f:31:ef brd ff:ff:ff:ff:ff:ff
6: enp0s31f6.30@enp0s31f6: mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 70:85:c2:7f:31:ef brd ff:ff:ff:ff:ff:ff
给网卡添加ip地址并启动网卡:
$ sudo ifconfig enp0s31f6.20 192.168.20.100 netmask 255.255.255.0 broadcast 192.168.20.255 up
$ sudo ifconfig enp0s31f6.30 192.168.30.100 netmask 255.255.255.0 broadcast 192.168.30.255 up
启动成功之后的效果如下:
$ ifconfig
(此处省略无关网卡)
enp0s31f6.20: flags=4163 mtu 1500
inet 192.168.20.100 netmask 255.255.255.0 broadcast 192.168.20.255
inet6 fe80::7285:c2ff:fe7f:31ef prefixlen 64 scopeid 0x20
ether 70:85:c2:7f:31:ef txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 81 bytes 12838 (12.8 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
enp0s31f6.30: flags=4163 mtu 1500
inet 192.168.30.100 netmask 255.255.255.0 broadcast 192.168.30.255
inet6 fe80::7285:c2ff:fe7f:31ef prefixlen 64 scopeid 0x20
ether 70:85:c2:7f:31:ef txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 81 bytes 12838 (12.8 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
测试以下两个VLAN的连通性:
$ ping 192.168.20.100 -I enp0s31f6.30
PING 192.168.20.100 (192.168.20.100) from 192.168.30.100 enp0s31f6.30: 56(84) bytes of data.
^C
--- 192.168.20.100 ping statistics ---
70 packets transmitted, 0 received, 100% packet loss, time 70637ms
pipe 4
$ ping 192.168.30.100 -I enp0s31f6.20
PING 192.168.30.100 (192.168.30.100) from 192.168.20.100 enp0s31f6.20: 56(84) bytes of data.
^C
--- 192.168.30.100 ping statistics ---
5 packets transmitted, 0 received, 100% packet loss, time 4100ms
pipe 4
VLAN划分成功,接着我们使用cannelloni将BDCAN(vcanbd)和ICCAN(vcanic)连接起来:
$ cannelloni -I vcanbd -R 192.168.20.100 -r 20001 -l 20000
INFO:udpthread.cpp[INFO:146]:run:UDPThread up and running
canthread.cpp[108]:run:CANThread up and running
$ cannelloni -I vcanic -R 192.168.20.100 -r 20000 -l 20001 -p
INFO:udpthread.cpp[146]:run:UDPThread up and running
INFO:canthread.cpp[108]:run:CANThread up and running
连通之后通过controls的操作,便可将CAN报文发送给ICSim,仪表盘也可以显示状态了。通过同样的方式将ASCAN和CAMCAN连接起来,VCU域与HU域的通信就完全打通了。在实际的通信场景下,我们可能会依据类似最小权限原则来配置业务能力,比如在VCU与HU的通信场景中,我们可能会认为HU域只需要从VCU接收车身CAN报文的能力,而不需要发送车身CAN报文的能力;相反,HU域产生的摄像头数据,需要经以太网传送给VCU的ADAS模块,此时HU域可能需要的是发送摄像头报文的能力,而不需要接收能力。为了满足这种需求,我们在实验中增加了网络防火墙。
防火墙
通过iptables规则分别在VCU域和HU域建立防火墙,过滤存在风险的以太网报文,以达到如下两个目的:
以HU为例,通过如下规则对报文的流向进行控制:
$ sudo iptables -A INPUT -d 192.168.20.100 -j LOG --log-prefix='[hu-normal-in]' --log-ip-options
$ sudo iptables -A INPUT -p udp -d 192.168.20.100 -s 192.168.20.100 --dport 20001 --sport 20000 -j ACCEPT
$ sudo iptables -A INPUT -d 192.168.20.100 -j DROP
到目前为止,VCU与HU的通信已经完全打通,并且我们加上了防火墙规则,但VCU内部的通信却还没有解决,因为ADAS模块可能也需要车身零部件的数据来做自动驾驶决策,所以我们需要通过网关将BDCAN与ASCAN连接起来。
CAN网关功能
使用cangw可以实现简单的CAN网关功能,连接车身CAN(BDCAN)和ADAS CAN(ADASCAN),车身产生的CAN报文通过网关路由至ADAS模块。(其实cangw和cannelloni的功能结合起来已经很接近真实的CAN网关,真实的CAN网关还支持LIN、Flexray等)
网关的配置方式如下:
$ sudo cangw -A -s vcanbd -d vcanas -e
$ sudo cangw -A -s vcanas -d vcanbd -e
cangw还支持配置报文过滤规则以及完整性校验,读者可以继续探索,摄像头模块与ADAS模块的功能也可继续完善。
参考
[1].GitHub - zombieCraig/ICSim: Instrument Cluster Simulator
[2].GitHub - mguentner/cannelloni: a SocketCAN over Ethernet tunnel
转载请申明出处!