> For the complete documentation index, see [llms.txt](https://man.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://man.bsdcn.org/man7/sprog.7.md).

# sprog(7)

`sprog` — 安全编程实践

## 名称

`sprog`

## 描述

多年来，安全问题已悄然潜入许多系统。本文档是防止这些问题发生的编程实践指南。

### 概述

编写安全的应用程序需要非常审慎和悲观的态度。应用程序应遵循“`最小权限`”原则运行，使得任何进程都不应拥有超出完成其功能所需的最少访问权限。应尽可能重用已测试过的代码。通常，任何超出程序控制范围的东西都不应被信任。这包括所有形式的用户输入、系统资源、进程间通信以及事件的时序。

### 缓冲区溢出

缓冲区溢出是最常见的安全问题类型之一。简而言之，如果程序对所接收的数据不够小心，这些数据可能会被写入到内存中越界位置，覆盖函数调用的返回地址，程序将被强制运行执行恶意行为的代码。

标准 C 库中有许多函数在使用时难以甚至不可能防止缓冲区溢出。这些函数包括 fscanf(3)、gets(3)、getwd(3)、realpath(3)、scanf(3)、sprintf(3)、strcat(3)、strcpy(3)、vscanf(3) 和 vsprintf(3)。

许多其他处理字符串的函数如果使用不当，也可能引发潜在的缓冲区溢出。例如，strncat(3) 并不会主动提供 NUL 字符终止。当然，必须始终指定正确的长度。使用 strlcat(3) 和 strlcpy(3) 可确保字符串以 null 终止并且具有指定的长度。

接收字符串格式的函数也必须小心使用。字符串可能包含额外的格式说明符，这为缓冲区溢出打开了另一种可能性。切勿在不使用 `%s` 的情况下传递包含不可信数据的字符串。始终使用正确的安全惯用法：

```sh
function("%s", string);
```

在库和编译器层面存在一些为这些问题提供后盾的机制，但是，没有任何东西能够替代编写良好的代码。

### Set-user-ID 问题

在许多情况下，程序可能需要以提升的权限集合运行。原因包括绑定受保护套接字、读写某些文件和目录以及访问各种资源。使用 setuid 程序通常是解决方案。然而，程序尽快放弃这些权限非常重要。例如，如果程序正在绑定到受保护套接字，它应在完成绑定后立即放弃其权限。这通过 setuid(2) 系列系统调用完成。

### 受限环境

限制进程的传统方法是使用 chroot(2) 系统调用。此系统调用更改根目录，进程及其任何子进程的所有其他路径都从该根目录引用。当然，进程必须首先具有对此路径的访问权限。新环境在调用 chdir(2) 将进程放入新环境之前实际上不会生效。遗憾的是，如果获得了 root 访问权限，进程可以突破此环境。

通常，jail(2) 可用于创建比 chroot(2) 所能提供的更完整和封闭的环境。Jail 限制该环境内的所有进程，包括具有超级用户权限的进程。

POSIX.1e 扩展所描述的细粒度权限目前仍在开发中，是 TrustedBSD 项目的重点。更多信息可在 `http://www.TrustedBSD.org/` 找到。

### 信任

程序不应对其运行环境做出假设。这包括用户输入、信号、环境变量、系统资源、进程间通信和共享内存等超出程序控制范围的内容。它们也不应假设能够检测到所有形式的无效数据。相反，应使用正向过滤，仅允许已知安全的特定输入子集。这与管理员应应用于防火墙的逻辑相同，即默认拒绝并指定要接受的内容。

### 竞态条件

竞态条件是由事件的相对时序引起的异常行为。程序不应假设特定事件会在另一事件之前发生。竞态条件最常见的原因是信号、访问检查和文件读取。信号本质上是异步的，因此在处理它们时必须格外小心。尝试使用顺序非原子操作来检查访问权限是个非常糟糕的主意，因为文件可以在任何时候被移动和更改。不要使用 access(2) 和 open(2) 的序列，而应使用 seteuid(2) 然后直接调用 open(2)。事先正确设置 umask(2)。

## 参见

jail(2), setuid(2), strlcat(3), strlcpy(3)

## 作者

Eric Melville <eric@FreeBSD.org> 最初基于 Murray Stokely <murray@FreeBSD.org> 编写的 FreeBSD Developer's Handbook 的一章撰写了本文档。
