CentOS 下使用 GCC 的安全编译与系统加固要点
一 基础准备与编译器安装
- 更新系统并安装开发工具链:
- sudo yum update -y
- sudo yum groupinstall “Development Tools” -y
- 验证:gcc --version、g++ --version
- 如需较新版本 GCC 而不替换系统默认编译器,建议使用 SCL(Software Collections):
- sudo yum install centos-release-scl -y
- sudo yum install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils -y
- 启用:scl enable devtoolset-9 bash(或写入 ~/.bashrc 以持久化:source /opt/rh/devtoolset-9/enable)
- 验证:gcc --version
二 推荐的 GCC 安全编译选项
- 建议的“通用安全基线”组合(适用于大多数 C/C++ 程序):
- -O2 -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fPIE -pie -z relro -z now
- 选项与防护效果一览(按需启用/组合):
- NX(数据不可执行):-z noexecstack(默认多为开启;用 -z execstack 会禁用,务必避免)
- RELRO(GOT/重定位只读):-z relro/-z now(now 为完全 RELRO,启动即重定位并设为只读)
- PIE/ASLR(地址随机化):-fPIE -pie(生成位置无关可执行文件,配合系统 ASLR 提升难度)
- 栈保护(Canary):-fstack-protector-strong(或 -fstack-protector;-fno-stack-protector 为禁用)
- FORTIFY_SOURCE(常见函数加固):-D_FORTIFY_SOURCE=2(需配合优化级别如 -O2)
- 共享库位置无关:-fPIC(编译 .so 时使用)
- 快速示例(可执行程序):
- gcc -O2 -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fPIE -pie -z relro -z now -o app app.c
- 快速示例(共享库):
- gcc -O2 -fPIC -shared -o libapp.so app.c
- 说明:不同发行版/glibc 版本对默认保护有所差异,生产环境应以“显式指定”为准,避免依赖默认行为。
三 编译后验证与自检
- 使用 checksec.sh 检查二进制的安全特性:
- git clone https://github.com/slimm609/checksec.sh
- ./checksec.sh/checksec --file=./app
- 关注:RELRO、STACK CANARY、NX、PIE、FORTIFY 等字段是否为期望状态
- 手动核验要点:
- 检查堆栈是否不可执行:readelf -l app | grep GNU_STACK(应为 RWE 表示可执行;使用 -z noexecstack 后不应出现 E)
- 检查是否启用 PIE:readelf -h app | grep Type(应为 DYN 表示 PIE)
- 检查 RELRO:readelf -d app | grep BIND_NOW(存在表示启用立即绑定,即 Full RELRO 倾向);readelf -d app | grep RELRO(显示 Partial/Full)
四 系统层面的加固配合
- 启用并保障内核 ASLR 有效:
- 查看:cat /proc/sys/kernel/randomize_va_space(建议值为 2)
- 临时启用:echo 2 > /proc/sys/kernel/randomize_va_space
- 永久生效:在 /etc/sysctl.conf 中加入 kernel.randomize_va_space=2 并执行 sysctl -p
- 构建与运行环境建议:
- 禁止给生产二进制授予不必要的 setuid/setgid 权限
- 避免使用 RPATH/RUNPATH 指向不可信路径,优先使用系统库路径或标准搜索路径
- 持续集成中加入 checksec 自检,作为发布前的强制门禁
五 常见问题与排查
- 启用 Full RELRO(-z now)导致启动慢或依赖解析失败:
- 现象:程序启动阶段即完成重定位,依赖未满足会报错
- 处理:确保所有依赖在构建环境中可用,或阶段性采用 Partial RELRO(-z relro)过渡
- 需要调试符号时与优化/加固的权衡:
- 建议保留 -g 生成调试信息,同时维持加固选项;发布时可用 strip 去除符号表
- 第三方或老旧代码无法在 -fPIE/-pie 下链接:
- 排查是否所有目标文件与库均使用 -fPIE 编译;必要时优先为可执行文件开启 PIE,库保持 -fPIC
- 内网环境无法使用 SCL 安装新版 GCC:
- 可挂载 CentOS ISO 作为本地仓库,离线安装 “Development Tools” 或指定 RPM 包,再进行安全编译基线配置