FForm Platform
enzh-CN

安全与部署

将 FormPlatform 作为具有受保护密钥、HTTPS 和运行防护的私有 .NET 10 服务部署。

安全配置与生产部署

生产环境的连接字符串、OAuth client secret、SMTP 密码、支付密钥、VAPID 私钥、DNN SSO 密钥和 S3 凭据都不得提交到 `appsettings.json`。本地开发用 `dotnet user-secrets`;Windows/IIS 使用受网站证书私钥保护的外部 secrets 文件;Linux/systemd 使用 credential 或仅运行帐号可读的秘密文件。

配置优先级

应用基础 JSON 只包含无敏感默认值。环境变量、User Secrets 和外部 secrets 文件覆盖基础 JSON。层级环境变量使用双下划线,例如:

ManagementDatabase__ConnectionString
Media__S3__AccessKey
Media__S3__SecretKey
RespondentExternalAuthentication__Google__ClientSecret

保护后的 Windows secrets 文件由安装程序或保护工具读取证书解密到内存;应用程序池身份需要读取证书私钥,但不应拥有整个部署目录或管理员帐户权限。

系统表单需要从数据库反向保存到 C# 时,请参阅系统表单反向同步到源码。该流程会沿用安全配置优先级读取连接,并明确区分源码快照与完整数据库备份。

反向代理

公开 HTTPS 由 IIS/Nginx 终止时,Kestrel 仅监听 loopback。代理必须转发 `Host` 和 `X-Forwarded-Proto`。否则应用会把公开 HTTPS 请求误认为 HTTP,影响登录 cookie、安全重定向、许可证 origin、OAuth callback、支付 webhook 和 sitemap URL。

IIS 应用程序池使用 **No Managed Code**,安装 .NET 10 Hosting Bundle,把 **Load User Profile** 设为 `True` 并保持 `setProfileEnvironment` 启用,使 current-user DPAPI 使用应用程序池身份的稳定 profile;同时写入 stdout 日志目录权限,并让池身份读取部署目录、运行时数据目录、必要的证书私钥和本地媒体目录。systemd 服务应使用专用低权限用户、固定 `WorkingDirectory`、显式 `ASPNETCORE_URLS` 和受控 credentials。

Data Protection 密钥环

系统用户、受访者、外部登录临时 Cookie 和远程认证状态共用 `App_Data/keys` 密钥环。Authentication Scheme 会形成不同的 Data Protection purpose,因此共用密钥环不会让不同类型的 Cookie 相互冒用。

Windows 上,Host 使用当前运行身份的 DPAPI 加密以后新写入的密钥。密钥必须由最终 Windows Service 或 IIS 应用程序池身份生成并使用;换机器或换 Windows 身份后无法解密。启用 DPAPI 不会重写已有明文 XML 密钥;如安全策略要求加密全部历史密钥,应规划主动轮换,并接受受保护数据和现有会话失效的影响。DPAPI 不能取代 `App_Data/keys` 的严格 ACL。

非 Windows 主机会跳过 DPAPI,必须依靠专用服务帐号和文件权限保护密钥环,或在使用共享存储前配置可移植的生产密钥加密器。Web Farm 可以采用节点本地密钥环配合 Client Affinity,但节点故障或关联丢失会要求重新登录;若要求无缝故障转移,应使用共享持久化密钥环,并以证书或等效的可移植加密器保护,不能使用只绑定单机身份的 current-user DPAPI。

发布与验证

使用 standalone 打包脚本生成生产包;不要从正在运行的 Debug 输出复制文件。安装或升级后验证 `/healthz`、管理数据库连接、迁移日志、许可证、FormPlatform 登录、匿名/受访者流程、静态资产、反向代理子路径(若使用)和备份恢复流程。

空库首次行政区划种子与 IIS 启动

空的 Management 数据库会触发可选的 158,355 行中英文行政区划种子。该任务在后台执行且不阻塞 Host 完成启动,因此不占用 IIS/ANCM 的 `startupTimeLimit`。所有记录仍放在单个事务中:并发查询不会看到不完整的层级;根据 Provider 和隔离级别,它会看到提交前的空状态,或等待最终提交。日志会记录开始、每 10,000 行进度、完成、取消或失败。数据库 Provider 级应用锁会串行化 Web Farm 各节点的种子任务;进程中止会回滚,下次启动因表仍为空而自动重试。

使用 `GeneralGeoLocationTree` 的部署应保持 `SeedData:GeoLocation:Enabled` 开启;隔离测试或明确由外部预置该表时可以关闭。应用可能早于首次种子完成而开始接收请求,因此依赖地理 Tree/AsyncSelect 的页面会暂时没有选项;生产放量前应以种子完成日志作为这项数据的就绪信号。

English edition: SECURE_CONFIGURATION_AND_DEPLOYMENT.md.