Ubuntu 上保障 Fortran 程序安全的实用方案
一 构建阶段加固
- 启用编译器与链接器安全选项:使用 gfortran 时,建议至少开启以下选项,分别应对栈溢出、格式化字符串、危险库函数、内存不可执行、地址空间随机化与只读重定位等风险。
- 栈金丝雀与强校验:-fstack-protector-strong
- 格式化字符串与缓冲区溢出检查:-D_FORTIFY_SOURCE=2
- 不可执行栈:-z noexecstack
- 完整 RELRO(重定位只读,阻止 GOT 覆写):-Wl,-z,relro,-z,now
- 位置无关可执行与 ASLR:-fPIE -pie
- 示例(按安全强度从高到低排列,可按需取舍):
- 高强度:gfortran -O2 -fstack-protector-strong -D_FORTIFY_SOURCE=2 -z noexecstack -fPIE -pie -Wl,-z,relro,-z,now foo.f90 -o foo
- 兼容性优先:gfortran -O2 -fstack-protector -D_FORTIFY_SOURCE=1 -z noexecstack foo.f90 -o foo
- 说明与要点:
- ASLR 提供地址随机化,配合 PIE 才能对可执行文件本体生效;RELRO 的 Full 模式会在启动期解析全部符号并把 GOT 设为只读,能有效缓解 GOT 覆盖类攻击;FORTIFY_SOURCE 在编译期/链接期替换或检查危险函数(如字符串/格式化函数)以降低溢出风险。
二 运行阶段隔离与最小权限
- 最小权限运行:避免使用 root 直接运行计算任务;为程序创建专用用户与工作组,按需授予文件与目录访问权限(读写输入/输出与必要的临时目录,禁止全局写)。
- 沙箱与环境隔离:
- 使用 systemd 服务单元设置 ProtectHome=yes、ProtectSystem=strict、PrivateTmp=yes、NoNewPrivileges=yes、CapabilityBoundingSet= 仅保留所需能力,限制网络访问(如 RestrictAddressFamilies=AF_UNIX)与挂载命名空间。
- 在受控环境中运行(如容器或虚拟机)以隔离依赖与数据,降低被攻破后的横向影响。
- 系统级加固(可选但推荐):启用 AppArmor 对可执行文件进行强制访问控制。做法示例:
- 安装工具:sudo apt-get install apparmor-utils
- 生成并完善配置:sudo aa-genprof /path/to/your_fortran_binary
- 按程序的正常功能设计测试流程,执行后回到终端按 S 扫描日志并逐项选择允许/拒绝/继承/无限制,最终生成可加载的 profile 并 enforce。
三 系统与网络防护
- 及时更新与补丁:保持 Ubuntu 系统与依赖库为最新,及时修复已知漏洞(安全更新)。
- 边界与本地防护:启用 UFW 防火墙,仅开放必要端口与协议;关闭不必要的服务与端口,减少攻击面。
- 内核与信息泄露缓解:
- 提升 ASLR 强度:echo 2 | sudo tee /proc/sys/kernel/randomize_va_space(需要时可写入 /etc/sysctl.d/ 持久化)
- 限制内核信息泄露:/proc/sys/kernel/dmesg_restrict=1、/proc/sys/kernel/kptr_restrict=1(按需设置)
- 最小暴露面:对外服务尽量置于内网或受控网段,通过网关/反向代理与认证网关接入。
四 Fortran 代码层面的安全要点
- 输入校验与边界检查:对来自文件、命令行或网络的数据进行长度、范围与格式校验,避免越界读写与格式化字符串漏洞(例如避免不受控的 READ(…, fmt=…) 与 WRITE(…, fmt=…))。
- 安全的文件与内存操作:
- 打开文件时检查 IOSTAT,在到达 EOF 后不要继续顺序读写;需要重读时使用 REWIND 或 BACKSPACE 合理移动文件指针。
- 动态内存(如 ALLOCATE/DEALLOCATE)配对使用,释放后及时置空指针,避免悬垂指针与二次释放。
- 第三方库与接口:调用外部库(含 C/Fortran 互操作)时验证输入与返回码,避免将未校验的数据传入系统调用或加密接口;加密与随机数请使用成熟库而非自行实现。