嵌入式应用安全最佳实践-OWASP

来源:公众号“汽车信息安全”
2021-04-27
2622
自行青骥信息安全原创技术系列专题
图片
   系统加固、禁用不安全的函数、堆栈防护等等诸如此类的防护手段我们听了一遍又一遍,但对于怎样操作却是一头雾水。基于此,青骥为大家梳理了OWASP的《Embedded Application Security Best Practices》,一篇由开发人员、工程师和业余爱好者共同编撰的防护指南,从堆栈保护、注入防护、固件升级和加密签名、敏感信息安全存储、身份管理、嵌入式框架和工具链强化、调试代码和调试接口使用、TLS安全、数据收集和存储的使用/隐私、第三方代码和组件、威胁建模等多个角度为我们揭开嵌入式应用安全实践的神秘面纱。
    为了给大家呈现核心内容而不被冗长的代码所困扰,以下内容在原文的基础上进行了删减,如有兴趣,可以自行查阅原文。









1.堆和栈溢出保护




防止使用已知的危险函数和API来防止固件中的内存损坏漏洞。(例如,使用不安全的C函数-strcatstrcpysprintfscanf。诸如缓冲区溢出之类的内存损坏漏洞可能包括堆栈溢出(堆栈溢出或堆溢出(堆溢出。为简单起见,本文档不区分这两种类型的漏洞。如果攻击者检测到缓冲区溢出并利用了缓冲区溢出,指令指针寄存器将被覆盖以执行攻击者提供的任意恶意代码。


在源代码中查找易受攻击的C函数。示例:在“ C”存储库中使用下面的“ find”命令在源代码中查找易受攻击的C函数,例如“ strncpy”和“ strlen”。

find . -type f -name '*.c' -print0|xargs -0 grep -e 'strncpy.*strlen'|wc –l

grep表达式可与以下表达式一起使用

$ grep -E '(strcpy|strcat|strncat|sprintf|strlen|memcpy|fopen|gets)' fuzzgoat.c


下面显示了针对C源代码运行的bugfinder的示例输出。

$ flawfinder fuzzgoat.c //一个静态扫描工具

 

FINAL RESULTS:

fuzzgoat.c:1049:  [4] (buffer) strcpy:

  Does not check for buffer overflows when copying to destination (CWE-120).

  Consider using strcpy_s, strncpy, or strlcpy (warning, strncpy is easily

  misused).

fuzzgoat.c:368:  [2] (buffer) memcpy:

  Does not check for buffer overflows when copying to destination (CWE-120).

  Make sure destination can always hold the source data.

不推荐使用的函数的用法,Noncompliant Code Example:此不兼容的代码示例假定get()stdin中读取的字符数不能超过BUFSIZ-1个字符。这是一个无效的假设,并且所产生的操作可能导致缓冲区溢出。还要注意,BUFSIZ是在stdio.h中定义的宏整数常量,表示setvbuf()的建议参数,而不是此类输入缓冲区的最大大小。


gets()函数从标准输入中读取字符到目标数组,直到遇到文件结尾或读取换行符为止。删除任何换行符,并且在最后一个字符读入数组后立即写入空字符。

图片


符合示例fgets()函数从流到数组中最多读取少于指定数量的字符。此解决方案兼容,因为从stdin复制到buf的字节数不能超过分配的内存:

图片

strncat()是原始strcat()库函数的变体。两者都用于将一个以NULL终止的C字符串追加到另一字符串。最初的strcat()的危险在于,调用者提供的数据可能超出了接收缓冲区的容量,从而使它超出了范围。最常见的结果是segmentation violation 更糟糕的结果是,内存中接收缓冲区后面的任何内容都被无声且未被检测到的损坏。

strncat()添加了一个附加参数,允许用户指定要复制的最大字节数。这不是要复制的数据量。它不是源数据的大小。这是对要复制的数据量的限制,通常设置为接收缓冲区的大小。

 strncat”的符合示例用法:

图片


 strncat”的不兼容示例用法:

图片

下面的屏幕截图演示了在使用buildroot构建固件映像时启用了堆栈保护支持。


编程时需要考虑的问题

  • 什么样的缓冲区及其驻留位置:物理,逻辑,虚拟内存?

  • 当释放缓冲区或将缓冲区留给LRU时,将保留哪些数据?

· 将采用什么策略来确保旧缓冲区不会泄漏数据(例如:使用后清除缓冲区)?

  • 将缓冲区初始化为分配时的已知值。

  • 考虑变量的存储位置:堆栈,静态或分配的结构。

  • 在不再需要缓冲区或临时文件时,请在运行时处置并安全擦除它们(例如,在释放缓冲区之前,从存储个人身份信息(PII)的位置擦除缓冲区)。

  • 显式初始化变量。

  • 确保在每次固件构建时都使用安全的编译器标志或开关。(例如,对于GCC-fPIE,-fstack-protector-all,-Wl,-z,noexecstack,-Wl,-z,noexecheap等。更多信息,请参见其他参考部分。)

  • 对已知的易受攻击函数使用安全的等效函数,例如(下面的非穷举列表):

· 建议使用C库安全的串函数,如gets()->fgets()strcpy()->strncpy()strcat()->strncat()sprintf()->snprintf()

· 使用自己封装的安全串函数;

· 使用其他的安全库函数,如intelsafestringlibhttps://github.com/intel/safestringlib里面提供了诸如memcmp_s()memcpy_s()memmove_s()memset_s()等函数;

  • SoC和MCU包含内存管理单元(MMU),使用MMU实现隔离线程和进程,以在内存漏洞被利用时减少攻击面;SoC和MCU包含内存保护单元(MPU),使用MPU实现强制内存和独立进程的访问规则,以及强制特权规则。如果没有可用的MMU或MPU,则使用已知位监视堆栈,通过确定堆栈中有多少不再包含已知位来监视堆栈的消耗量。

  • 如果使用FreeRTOS操作系统,请考虑在开发和测试阶段使用hook函数将“configCHECK_FOR_STACK_OVERFLOW”设置为“1”,但在生产阶段将其删除。



2. 注入防护


确保对所有不受信任的数据和用户输入进行了验证,清除和/或编码输出,以防止意外的系统执行。应用程序安全性内有各种注入攻击,例如操作系统(OS)命令注入,跨站点脚本(例如JavaScript注入),SQL注入以及其他攻击(例如XPath注入)。但是,嵌入式软件中最普遍的注入攻击与OS命令注入有关。

 

图片

    上面的代码在执行any_cmd‘happy';useradd'attacker’时实际执行的操作为

图片

    这是因为system使用的全shell翻译器,因此推荐使用execve()exec函数系列不使用完整的shell解释器,因此它不容易受到命令注入攻击的影响。

如果指定的文件名不包含(/),则execlp()execvp()和(非标准)execvP()函数会在搜索可执行文件时复制shell程序的动作。因此,仅当PATH环境变量设置为安全值时,才应使用不带(/)的字符。

execl()execle()execv()execve()函数不执行路径名替换。

此外,应采取预防措施以确保不受信任的用户无法修改外部可执行文件,例如,通过确保该可执行文件不可被用户写入。该兼容解决方案与前面的非兼容代码示例明显不同。首先,将输入合并到args数组中,并将其作为参数传递给execve(),从而消除了在形成命令字符串时对缓冲区溢出或字符串截断的担忧。其次,此兼容解决方案在子进程中执行/usr/bin/any_cmd之前,会派生一个新进程。尽管此方法比调用system()更复杂,但是增加的安全性值得付出额外的努力。

图片


编程时需要考虑的问题

  • 不要调用shell命令包装,例如但不限于:

·PHP:system()exec(),passthru(),shell_exec()

·C:system()popen(),exec(),execl(),execle(),execv(),execve()

·C++:ShellExecute()

·Lua:os.execute()

·Perl:system(),exec()

·Python:os.system()subprocess.call()

  • 如果可能,请避免将用户数据用于操作系统命令。如果需要,建立数字到命令字符串的查找映射,用于可能被传递给操作系统的用户驱动的字符串。

  • 通过查找映射,使用接受命令的白名单'以确保仅处理预期的参数值。

  • 确保根据上下文输出编码字符的用户数据(例如HTML,JavaScript,CSS等)

  • HTML实体编码,输出编码为:





3. 固件升级和加密签名


在下载时确保强大的更新机制以及适用时利用加密签名的固件映像来更新与第三方软件有关的功能。签名和验证过程使用公钥加密,如PGP签名。万一私钥被泄露,软件开发人员必须撤消被泄露的密钥,并且将需要使用新密钥重新签署所有先前的固件版本。

notePGPPrettyGoodPrivacy,是一种公钥加密算法,常被用来加密和签名通信数据。我们可以使用PGP来验证我们从网站上下载下来的软件没有被篡改。软件的作者会使用PGP软件对他们软件进行签名,这样你就可以在下载后验证软件的完整性。因为PGP是非对称加密,作者会用自己的私钥进行软件的签名,因此我们需要先获取到作者的公钥,一般网站会直接提供,然后我们需要检查该公钥的指纹以确保它是正确的公钥,然后将正确的公钥导入到PGPkeyring中,然后下载软件的签名文件,然后使用公钥验证软件的签名,如果签名正确,那么就说明软件没有被篡改。

下面以内核镜像签名为例:

1)下载镜像和镜像的签名文件

wget [https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.6.6.tar.xz] (https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.6.6.tar.xz)

 

wget [https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.6.6.tar.sign] (https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.6.6.tar.sign)

2)下载PGP公钥

# gpg2 --keyserver hkp://keys.gnupg.net --recv-keys 38DBBDC86092693E

gpg: /root/.gnupg/trustdb.gpg: trustdb created

gpg: key 38DBBDC86092693E: public key "Greg Kroah-Hartman (Linux kernel stable release signing key)

gpg: no ultimately trusted keys found

gpg: Total number processed: 1

gpg:               imported: 1

3)解压并核验镜像

# xz -cd linux-4.6.6.tar.xz | gpg2 --verify linux-4.6.6.tar.sign -

gpg: Signature made Wed 10 Aug 2016 06:55:15 AM EDT

gpg:                using RSA key 38DBBDC86092693E

gpg: Good signature from "Greg Kroah-Hartman (Linux kernel stable release signing key)

gpg: WARNING: This key is not certified with a trusted signature!

gpg:          There is no indication that the signature belongs to the owner.

Primary key fingerprint: 647F 2865 4894 E3BD 4571  99BE 38DB BDC8 6092 693E

4)处理警告:我们需要确定该签名是属于该owner的,有下面的方法:

  • 使用Kernel.org信任网。这将需要您首先在您所在的区域中找到kernel.org的成员并对其密钥进行签名。缺少与实际中PGP密钥的实际所有者的会面,这是验证PGP密钥签名有效性的最佳选择。

  • 使用gpg --list-sigs查看开发人员密钥上的签名列表。向尽可能多的已签署密钥的人发送电子邮件,最好是在不同的组织(或至少在不同的域)。要求他们确认他们已经签署了相关密钥。您最多应该对以这种方式收到的回复(如果收到)给予边际信任。

  • 使用以下站点查看从LinusTorvalds的密钥到用于签名压缩包的密钥的信任路径:pgp.cs.uu.nl。将Linus的密钥输入“from”字段,并将您在上面的输出中获得的密钥输入“to”字段。通常,只有Linus或具有Linus直接签名的人才负责发布内核。

5)处理“bad signature”:确定核验的tar而不是tar.zx文件,确保下载文件是正确的且没有截断;有时候我们还会遇到公钥更新不及时的问题,因此我们可以更改配置文件~/.gnupg/gpg.conf,更改PGP服务器地址,然后再下载公钥。

Demonstrating #1 above, verifying a signature incorrectly Example:

# gpg --verify linux-4.6.6.tar.sign linux-4.6.6.tar.xz

gpg: Signature made Wed 10 Aug 2016 06:55:15 AM EDT

gpg:                using RSA key 38DBBDC86092693E

gpg: BAD signature from "Greg Kroah-Hartman (Linux kernel stable release signing key)

Verifying a signature correctly Example:

# gpg --verify linux-4.6.6.tar.sign linux-4.6.6.tar

gpg: Signature made Wed 10 Aug 2016 06:55:15 AM EDT

gpg:                using RSA key 38DBBDC86092693E

gpg: Good signature from "Greg Kroah-Hartman (Linux kernel stable release signing key)

gpg: WARNING: This key is not certified with a trusted signature!

gpg:          There is no indication that the signature belongs to the owner.

Primary key fingerprint: 647F 2865 4894 E3BD 4571  99BE 38DB BDC8 6092 693E

编程时需要考虑的问题

  • 确保强大的更新机制,利用加密签名的固件映像来更新功能。

GPG(https://github.com/romanz/trezor-agent/blob/master/README-GPG.md)

  • 确保下载链路的安全,使用TLS1.2、TLS1.3或专用的VPN链路;

  • 包括一项功能,可以按照预定义的时间表利用自动固件更新。

· 在高度脆弱的用例中强制更新。

· 对于某些设备(例如医疗设备),应考虑计划的推送更新,以防止强制更新造成可能的问题。

  • 确保清楚显示固件版本。

  • 确保固件更新包括带有安全相关漏洞的变更日志。

  • 确保使用了防降级保护(防回滚)机制,以使设备无法还原为易受攻击的版本。

  • 考虑实IntegrityMeasurementArchitecture(IMA),这样,内核就可以通过扩展存储模块(EVM)来检查文件属性(包括扩展属性),并根据存储/计算的哈希值(称为标签)来验证文件是否未被更改。

· 标签有两种类型:

immutable and signed

Simple

  • 确保只有合适的应用可以对文件系统进行读写;

· 对可以将数据写入持久性存储位置的已批准流程应用适当的控件和监视。

  • 确保与服务器之间有可信赖的时钟源。




4. 敏感信息安全存储



请勿将密码,用户名,令牌,私钥或类似变体之类的机密硬编码到固件发行映像中。这也包括存储写入磁盘的敏感数据。如果有硬件安全元素(SE)或受信任的执行环境(TEE),则建议利用此类功能来存储敏感数据。否则,应评估使用强密码术以保护数据。如果可能的话,所有明文形式的敏感数据本质上应该都是短暂的,并且仅驻留在易失性存储器中。

下面的例子中,secret存储在malloc分配的缓冲区中但根据CPU的处理机制该缓冲区很有可能被swap到磁盘如果在调用memset_s前程序崩溃敏感信息肯恩存储在coredump

图片

    为了阻止信息被写入coredump该程序生成的coredump应该使用setlimit设为0

图片


    另外,可以使用mlock()通过将内存锁定在适当的位置来防止分页。这种兼容的解决方案不仅禁用了coredump的创建,而且还确保了缓冲区不会交换到硬盘上:

图片


编程时需要考虑的问题

  • 不要跨产品系列对证书进行硬编码。

  • 不要跨产品线对密码进行硬编码

  • 请勿将机密存储在不受保护的存储位置或外部存储中,包括EEPROM或闪存中。

(1) 从内核的角度考虑,敏感信息分配到缓冲区中,CPU为了性能考虑,会将其swap到磁盘中;因此对于敏感数据我们需要禁止swap换出;

(2) free分配的空间,内核不会立刻清除该内容,而是等到需要清除的空间达到一定程度或一定的时间后才会清除;因此对于敏感内容,我们需要强制内核立刻执行释放操作;

(3) 清除操作只是将该地址空间重新分配给其他程序,一般不会清除该地址的内容,因此我们必须在free手动调用memset_s清除该地址段的内容。




5. 身份管理



嵌入式设备中的用户帐户本质上不应是静态的。应该提供允许将用户帐户分开进行内部Web管理,内部控制台访问以及远程Web管理和远程控制台访问的功能,以防止自动进行恶意攻击。

编程时需要考虑的问题

通过设置/etc/login.defs的字段

图片

  • 用于Web管理和跨产品系列的终端访问的静态密码不应使用或在发布过程中删除。

· 如在此期间需要使用静态默认密码,确保在安装和激活设备后强制用户更改密码。

· 确保用户可以选择更改所有密码/密码/口令等到所有内置帐户

  • Pre-production账户验证脚本应该调整,与验证WIFI和WPS密码(如果适用)的方式类似。

  • 为用户实现远程登录和本地登录帐户功能。

  • SSH登录和管理员登录的用户分离。

  • 远程登录应实现临时帐户锁定阈值,以防止自动暴力攻击。

  • 对于Web管理界面:

· 确保会话ID是在请求正文中发送的,而不是在URL中发送的。

· 确保在用户注销时禁用会话ID

· 更改密码时,请确保禁用活动的会话ID

· 如果会话ID存储在cookie中,请确保cookie设置了HttpOnly标志。

· 确保会话ID是随机的,并且在会话之间变化。

  • 确保包含会话ID的用户名,密码和cookie不会通过不安全的协议(例如HTTP,FTP和Telnet)发送。

  • 应该实施密码复杂性策略,以阻止容易猜到的密码,例如“Password1”。复杂密码应具有以下属性:

· 长度至少10个字符或更多

· 至少有一个大写字母

· 至少一个数字字符

· 至少一个小写字母

· 至少一个特殊字符

  • 确保EEPROM受密码保护,以增强复杂性要求。

  • 采用密钥和证书轮换策略。




6. 嵌入式框架和C-Based工具链强化



BusyBox,嵌入式框架和工具链限制为仅在配置固件版本时使用的那些库和功能。嵌入式Linux构建系统(例如BuildrootYocto等)通常执行此任务。删除已知的不安全库和协议(例如Telnet)不仅可以最大程度地减少固件构建中的攻击入口点,而且还可以提供一种按设计安全的方法来构建软件,以阻止潜在的安全威胁。


library强化举例众所周知,压缩是不安全的(以及其他),SSLv2是不安全的,SSLv3是不安全的,以及TLS的早期版本。另外,假设您不使用硬件和引擎,而仅允许静态链接。有了相关知识和规范,您将可以如下配置OpenSSL库:

$ Configure darwin64-x86_64-cc -no-hw -no-engine -no-comp -no-shared -no-dso -no-ssl2 -no-ssl3 --openssldir=


选择一个shell举例:下面的屏幕快照利用buildroot演示了仅启用了一个Shellbash。(注意:Buildroot示例如下所示,但是还有其他方法可以与其他嵌入式Linux构建系统完成相同的配置。)

图片


服务强化举例:下面的屏幕截图显示了启用了openssh的文件,但不启用FTP守护进程proftpdpure-ftpd。仅当使用TLS才启用FTP。例如,proftpdpureftpd需要自定义编译,以将TLSmod_tls一起用于proftpd,并为pureftpd传递./configure--with-tls

图片

 

DasU-boot强化示例:通常,对嵌入式设备的物理访问使攻击路径可以修改Bootloader配置。下面提供了uboot_config的最佳实践示例。注意:通常会根据构建环境和特定的板卡自动生成uboot_config文件。为U-Boot2013.07及更高版本配置“验证启动”(安全启动)。默认情况下,“验证启动”未启用,并且至少需要以下配置要求主板支持。

CONFIG_ENABLE_VBOOT=y#启用验证启动

CONFIG_FIT_SIGNATURE=y#启用FIT镜像的签名验证。

CONFIG_RSA=y#启用用于FIT镜像验证的RSA算法

CONFIG_OF_SEPARATE=y#启用u-Boot与设备树的独立构建。

CONFIG_FIT=y#启用对Image格式的FlatImageTree(FIT)的支持。

CONFIG_OF_CONTROL=y#启用展平设备树(FDT)配置。

CONFIG_OF_LIBFDT=y

CONFIG_DEFAULT_DEVICE_TREE=y#指定用于U-Boot运行时配置的默认设备树。

之后,需要执行一系列步骤来配置“验证启动”。为Beagleboneblackboard构建验证启动的示例概述为:

(1) board构建U-Boot,并启用已验证的启动选项。

(2) 获取合适的Linux内核(最好是最新的)

(3) 创建一个ImageTreeSourceITS)文件,该文件描述您希望内核如何被打包,压缩和签名。

(4) 使用RSA2048创建RSA密钥对,并使用SHA256哈希算法进行身份验证(将私钥存储在安全的地方,并且未硬编码到固件中)

(5) 签名内核

(6) 将公钥放入U-Boot的图像中

(7) U-Boot和内核放入开发板

(8) 测试映像和启动配置

除上述内容外,使适用的配置对嵌入式设备的上下文有效。以下是可以进行的显式配置。

CONFIG_BOOTDELAY-2。#禁止使用自动启动时访问u-boot的控制台

CONFIG_CMD_USB=n#禁用基本的USB支持和usb命令

CONFIG_USB_UHCI:定义低级部分。

CONFIG_USB_KEYBOARD:启用USB键盘

CONFIG_USB_STORAGE:启用USB存储设备

CONFIG_USB_HOST_ETHER:启用USB以太网适配器支持

通过以下配置宏在U-Boot中禁用串行控制台输出:

CONFIG_SILENT_CONSOLE

CONFIG_SYS_DEVICE_NULLDEV

CONFIG_SILENT_CONSOLE_UPDATE_ON_RELOC

要启用不可变的U-boot环境变量以防止未经授权的更改(例如修改bootargs,更新已验证的引导公钥等)或固件的side-loading,请删除非易失性内存设置,例如以下内容:

#define CONFIG_ENV_IS_IN_MMC

#define CONFIG_ENV_IS_IN_NAND

#define CONFIG_ENV_IS_IN_NVRAM

#define CONFIG_ENV_IS_IN_SPI_FLASH

#define CONFIG_ENV_IS_IN_REMOTE

#define CONFIG_ENV_IS_IN_EEPROM

#define CONFIG_ENV_IS_IN_FLASH

#define CONFIG_ENV_IS_IN_DATAFLASH

#define CONFIG_ENV_IS_IN_MMC

#define CONFIG_ENV_IS_IN_FAT

#define CONFIG_ENV_IS_IN_ONENAND

#define CONFIG_ENV_IS_IN_UBI

 

编程时需要考虑的问题

  • 确保诸如SSH之类的服务已创建安全密码。

  • 删除未使用的语言解释器,例如:perl,python,lua。

  • 从未使用的库函数中删除无效代码。

  • 删除未使用的外壳解释器,例如:ash,dash,zsh。查看/etc/shell

  • 删除旧的不安全守护程序,包括但不限于:telnetd、ftpd、ftpget、ftpput、tftp、rlogind、rshd、rexd、rcmd、rhosts、rexecd、rwalld、rbootd、rusersd、rquotad、rstatd、nfs、nis;

  • 删除未使用/不必要的实用程序或设置使用的权限,例如:sed,wget,curl,awk,cut,df,dmesg,echo,fdisk,grep,mkdir,mount(vfat),printf,tail,tee,test(directory),test(file),head,cat,at,cron;

  • 对特定的服务进行强化,如ftp,一般对于个人pc,编辑/etc/vsftpd/vsftpd.conf,设置

 

汽车级LinuxAGL)开发了一个示例表,列出了常见实用程序及其在调试或生产环境(内部版本)中的用法。

图片

  • 利用Lynis等工具加强审核和建议

wget --no-check-certificate https://github.com/CISOfy/lynis/archive/master.zip && unzip master.zip && cd lynis-master/ && bash lynis audit system

    审查的报告存放在/var/log/lynis.log

  • 与开发人员以及相关利益相关者就嵌入式设备上运行的软件执行迭代威胁模型练习。




7. 调试代码和调试接口使用


在将固件发布之前,确保已删除所有不必要的生产前构建代码以及无效和未使用的代码。这包括但不限于原始设计制造商(ODM)和第三方承包商等当事方可能留下的潜在后门代码和root特权帐户。通常,这属于OEM通过合同或二进制文件的逆向工程执行的范围。这也应要求ODM签署主服务协议(MSA),以确保不包括后门代码,并且已对所有代码进行了软件安全漏洞审查,以使所有第三方开发人员应对大规模投放市场的设备负责。

需要考虑的问题

  • 删除用于调试,部署验证和/或客户支持目的的后门帐户。

  • 确保开发,诊断或调试功能未包含在发行版本中。

  • 执行代码清理会话,以确保在存储库中删除无效或未使用的代码。

  • 在部署市场之前,请确保工作人员对第三方库和二进制映像进行了后门检查。

  • 应当使用诸如Binwalk,Firmadyne,IDApro,radare2,FirmwareModToolkit(FMK), FirmwareAnalysisComparisonToolkit(FACT)之类的工具以及各种其他工具进行固件分析。




8. 传输层安全TLS



确保所有通信方法都使用针对TLS的行业标准加密配置。TLS的使用可确保所有数据在传输过程中保持机密且不受篡改。如果嵌入式设备使用域名,请使用免费的证书颁发机构服务,例如“加密”。


  • 对新产品使用最新版本的TLS(撰写本文时,这是TLS1.2)

  • 考虑为固件实施TLS双向身份验证,该固件接受来自一组有限的允许客户端的TLS连接。

  • 如果可能,请考虑使用双向身份验证对两个端点进行身份验证。

  • 验证证书的公钥,主机名和链。

  • 确保证书及其链使用SHA256进行签名。

  • 禁用不推荐使用的SSL和早期TLS版本。

  • 禁用不推荐使用的NULL和弱密码套件。

  • 确保私钥和证书安全存储-例如安全环境或受信任的执行环境,或使用强大的加密技术进行保护。

  • 使用最新的安全配置来更新证书。

  • 确保有效的证书更新功能在到期时可用。

  • 使用—script ssl-enum-ciphers.nse,TestSSLServer.jar,sslscan和sslyze等服务使用ssllabs.com,nmap等服务验证TLS配置。

 

除了使用openssl实现TLS外,还可使用:

    FormerlyPolarSSL,使用mbedTLS

    ·https://tls.mbed.org/kb/generic/projects-using-mbedtls

    ·https://tls.mbed.org/

    https://tls.mbed.org/kb/how-to/mbedtls-tutorial

    之前的CyaSSLwolfSSL,使用wolfSSL的一系列项目:

    ·https://www.wolfssl.com/wolfSSL/wolfssl-embedded-ssl-case-studies.html

    ·https://www.wolfssl.com/wolfSSL/Home.html

     · https://github.com/wolfSSL/wolfssl-examples




9. 数据收集和存储的使用-隐私



限制个人识别信息(PII)和敏感个人信息(SPI)的收集,存储和共享。诸如社会安全号码之类的泄漏信息可能导致客户受到损害,这可能会对制造商造成法律影响。如果必须收集这种性质的信息,则必须遵循“Privacy-by-Design”的概念。

需要考虑的问题

  • 确定哪个PII/SPI对设备操作至关重要,以及是否存储业务和/或操作目的所需的信息。

  • 将存储时间的持续时间限制为设备操作所需的最短时间。

  • 确保信息安全存储-即在安全环境中,或使用强密码保护。

  • 为客户提供有关通过隐私策略收集,存储和分发哪些信息的详细信息;

  • 提供一种机制,使设备所有者可以恢复出厂设置,以删除其个人数据,然后再转移给其他用户或销毁。

  • 考虑在欧盟存储数据的设备的GDPR。




10. 第三方代码和组件


在设置工具链之后,重要的是要确保内核,软件包和第三方库都进行了更新,以防止公开的漏洞。应该对照漏洞数据库及其ChangeLog来检查Rompager之类的软件或Buildroot之类的嵌入式构建工具,以确定何时以及是否需要更新。重要的是要注意,此过程应在发行版本之前由开发人员和/QA团队进行测试,因为嵌入式系统的更新可能会导致这些系统的操作出现问题。

嵌入式项目应维护第三方的“材料清单”,并在其固件映像中包含开源软件。应检查此物料清单,以确认所包含的第三方软件均不具有任何未修补的漏洞。可以通过国家漏洞数据库或开放中心找到最新的漏洞信息。

存在用于对第三方软件进行分类和审核的几种解决方案。您的构建环境中内置了许多解决方案,例如:

·C/C++

· Makefile

·Go

· Usetheofficialdeptool

·Node

· npmlist

·Python

· pipfreeze

·Ruby

· gemdependency

·Lua

· Seetherockspecfile

·Java

· mvndependency:tree

· gradleapp:dependencies

·Yocto

· buildhistory

·Buildroot(free)

· makelegal-info

·Package Managers(free)

· ·

dpkg--list

· rpm-qa

· yumlist

· aptlist--installed

·RetireJSf orJavascriptprojects(free)


需要考虑的问题

  • 使用retire.js对JavaScriptLibraries扫描

  • 对NodeJS包使用npm audit

  • 使OWASP DependencyCheck用于检测应用程序中公开披露的漏洞iondependenciesandfiletypes.

  • 使用safety check用于扫描与python相关的软件包的已知漏洞

  • 使用OWASP ZAP用于Web应用程序测试

  • 使用工具如Lynis用于基本内核强化审核和建议。


· wget--no-check-certificatehttps://github.com/CISOfy/lynis/archive/master.zip&&unzipmaster.zip&&cdlynis-master/&&bashlynisauditsystem
       •在以下位置查看报告:/var/log/lynis.log
     •注意:如果未使用Linux内核,Lynis将绕过内核检查。日志中将出现以下错误消息:“跳过测试KRNL-5695(确定Linux内核版本和发行版号)跳过的原因:不正确的客户机OS(仅Linux)”
       •如果存储空间有限(即,删除不必要的插件,例如php等),则应相应地修改Lynis
利用免费的库扫描程序,例如LibScanner,它可以搜索项目的依赖项,并将其与NVD交叉引用,以寻找用于yocto构建环境的已知CVE。该工具输出XML,使团队能够利用这些功能进行连续集成测试。


  • 利用软件包管理器(opkg,ipkg等)或工具链中杂类库的自定义更新机制。

  • 查看工具链,软件包和库的变更日志,以更好地确定是否需要更新。

  • 确保嵌入式系统的实现如Yocto和Buildroot,允许更新所有包含软件包。




11. 威胁建模


威胁建模是一种有助于量化威胁的练习,以了解攻击者(威胁行为者)如何能够危害系统,然后采取适当的缓解措施来阻止潜在的风险。 通常,威胁建模是作为设计阶段的一部分在部署到生产系统之前进行的一种练习,但也可以用于任何安全测试的开始阶段。 威胁建模通常将包括以下活动:

  • 识别系统中的所有资产,创建架构概述

  • 分解系统(或设备)

  • 识别威胁

  • 记录所有威胁及其各自的情况

  • 使用评级系统通过可能性和影响对每个威胁进行评级

 

威胁模型应回答以下四个问题:

  • 我们在建什么?

使用数据流程图(DFD)协助建模组件以及它们如何在本地以及与外部服务交互

DFD应显示连接资产的每个流程,用户,实体,数据存储和协议

利用诸如Microsoft Threat Modeling Tool 2016OWASP Threat Dragon之类的工具,或诸如https://draw.io/https://www.lucidchart.com之类的在线图表软件。

  • 会有什么问题吗?

利用STRIDE帮助识别和枚举威胁

  • 对于可能出错的问题,我们该怎么办?

DREAD有助于进行风险评分和优先级排序。风险越高,应对或缓解威胁的优先级越高。

  • 我们的分析效果如何?

进行回顾性活动,以检查整体质量,进度和未来计划。

威胁建模应尽早且尽可能频繁地进行。威胁模型的所有者最好掌握在软件团队的手中,应将其视为一份实时文档,该文档会在计划新功能时进行更新。一本很棒的书,也是一本权威的参考书,"Threat Modeling: Designing for Security".





12. 总结


    《Embedded Application Security Best Practices》从技术的角度很细致地为我们介绍了如何对嵌入式系统进行防护,在实际应用中我们可以结合汽车具体的使用场景进行优化,如对于不安全的函数,我们可以参考Cert CMisra C进行完善。

    总的来说,作为汽车网络安全的从业者,无论是在我们的TARA分析中,还是后期的测试验证中,OWASP均是一个很不错的可参考的免费资料来源,青骥在后面也会为大家呈现更多的内容。



收藏
点赞
2000