From d076291a6295e74e41595e8ab299854f4d0d9cee Mon Sep 17 00:00:00 2001 From: maxf Date: Mon, 28 Sep 2026 10:15:35 +0800 Subject: [PATCH] =?UTF-8?q?go=E7=89=88=E6=9C=AC=E5=A2=9E=E5=8A=A0=E8=BD=AF?= =?UTF-8?q?=E4=BB=B6=E7=AD=BE=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go/.gitignore | 6 +- go/SIGNING.md | 224 ++++++++++++++++++++++++++++++++++++++++++++++++++ go/build.bat | 115 ++++++++++++++------------ go/sign.bat | 56 +++++++++++++ 4 files changed, 349 insertions(+), 52 deletions(-) create mode 100644 go/SIGNING.md create mode 100644 go/sign.bat diff --git a/go/.gitignore b/go/.gitignore index 977ac82..504a50e 100644 --- a/go/.gitignore +++ b/go/.gitignore @@ -10,4 +10,8 @@ /frontend/node_modules/ # 测试二进制 -*.test \ No newline at end of file +*.test + +# 代码签名证书与工具(私钥材料,绝不入库) +/certs/ +/tools/ \ No newline at end of file diff --git a/go/SIGNING.md b/go/SIGNING.md new file mode 100644 index 0000000..62ddf27 --- /dev/null +++ b/go/SIGNING.md @@ -0,0 +1,224 @@ +# Excel 关键字搜索工具 —— 代码签名说明 + +Windows 发布版可执行文件(`.exe`)的 **Authenticode 代码签名** 与 **时间戳** 全流程说明。 +用于解决打包产物被 Symantec 等杀软误报(如 `Heur.AdvML.B`)的问题,也是正式对外分发的标准动作。 + +> 适用对象:`cmd/desktop`、`cmd/webui`、`cmd/searcher` 三个入口编译出的全部 exe。 + +--- + +## 一、为什么需要签名 + +| 现象 | 原因 | 签名的作用 | +|---|---|---| +| 杀软误报 `Heur.AdvML.B` | 无签名 + 符号剥离(`-s -w`)的结构特征,被启发式 ML 视为可疑 | 带 Authenticode 签名的 exe 结构显著不同,评分大幅下降 | +| 无签名 exe 被拦截/隔离 | 系统信任模型默认不信任"未知来源"程序 | 签名建立发布者身份,提高系统信任度 | + +**自签名证书的现实效果**:自签名证书**不链到公共信任根**,Symantec/Windows 不会"信任"该签名;但签名块本身已让 exe 脱离"无签名"形态,绝大多数启发式 ML 误报可消除。若要彻底消除全部杀软误报并显示绿色签名,需购买公共 OV/EV 证书(见「七、升级到公共证书」)。 + +--- + +## 二、相关文件与目录结构 + +``` +go/ +├── sign.bat # 一键签名脚本(纳入版本控制) +├── certs/ # 签名证书(已 gitignore,私钥材料,绝不入库/分发) +│ ├── codesign.crt # 自签名证书(公开部分) +│ ├── codesign.key # 私钥(⚠️ 最高机密) +│ └── codesign.pfx # 证书+私钥打包(签名工具实际使用) +└── tools/ # 签名工具(已 gitignore,可重新下载) + └── osslsigncode/ # osslsigncode 便携版(含依赖 DLL) + └── osslsigncode.exe +``` + +> `certs/` 与 `tools/` 已在 `go/.gitignore` 中排除,**不会**被提交到版本库,也不会进入发布包。 + +### 工具获取(首次安装 / tools/ 被清理后重装) + +`tools/osslsigncode/` 是便携版,不随版本库分发。在 Git Bash 中执行: + +```bash +cd go +mkdir -p tools && cd tools + +curl -sL -o osslsigncode.zip \ + https://github.com/mtrojnar/osslsigncode/releases/download/2.14/osslsigncode-2.14-windows-x64-mingw.zip + +unzip -o osslsigncode.zip + +# zip 解压后 exe 在 bin/ 子目录,移动到 sign.bat 引用的布局 +mkdir -p osslsigncode +mv -f bin/* osslsigncode/ +rm -rf bin share osslsigncode.zip + +# 验证 +./osslsigncode/osslsigncode.exe --help | head -3 +``` + +> ⚠️ zip 内含 `bin/osslsigncode.exe` + 依赖 DLL(`libcrypto-3-x64.dll`、`libssl-3-x64.dll`、`zlib1.dll`),必须与 exe 同目录,缺 DLL 会运行失败。 + +--- + +## 三、签发自签名代码签名证书(首次一次) + +> 前置:Git Bash(自带 OpenSSL ≥ 3.1)。以下命令在 Git Bash 中执行。 +> ⚠️ **MSYS 路径转换坑**:`-subj` 的 `/C=CN/...` 会被 Git Bash 误判为 POSIX 路径, +> 必须加 `MSYS_NO_PATHCONV=1` 前缀,否则报 `subject name is expected to be in the format...`。 + +```bash +cd go +mkdir -p certs + +MSYS_NO_PATHCONV=1 openssl req -x509 -newkey rsa:2048 -sha256 -nodes \ + -keyout certs/codesign.key \ + -out certs/codesign.crt \ + -days 3650 \ + -subj "/C=CN/ST=Sichuan/L=Chengdu/O=Excel Keyword Search Tool/OU=Release/CN=Excel Keyword Search Tool" \ + -addext "keyUsage=digitalSignature, nonRepudiation" \ + -addext "extendedKeyUsage=codeSigning" \ + -addext "basicConstraints=critical,CA:FALSE" +``` + +参数说明: +- `-x509`:直接自签(不经过 CA),`-nodes`:私钥不加密(本地文件使用,配合 `-pass` 保护 pfx) +- `-addext extendedKeyUsage=codeSigning`:声明**代码签名**用途(必填,杀软/系统校验此项) +- `-basicConstraints=CA:FALSE`:明确非 CA,防被滥用 +- `-days 3650`:10 年有效期(正式发布建议 ≥ 1 年) + +### 导出 PFX(签名工具实际使用) + +```bash +openssl pkcs12 -export \ + -out certs/codesign.pfx \ + -inkey certs/codesign.key \ + -in certs/codesign.crt \ + -passout pass:ExcelSearch2026 \ + -name "ExcelKeywordSearchRelease" +``` + +> `pass:ExcelSearch2026` 是**默认密码**(脚本内置)。正式环境请更换,并通过 `SIGN_PASSWORD` 环境变量注入(见下)。 + +### 验证证书 + +```bash +openssl x509 -in certs/codesign.crt -noout -subject -issuer -dates -text | grep -A3 "Extended Key Usage" +# 应输出:Code Signing +``` + +--- + +## 四、签名可执行文件 + +### 方式一:一键脚本 `sign.bat`(推荐) + +在 `go/` 目录下执行(cmd 或双击): + +```bat +sign.bat +``` + +- 自动扫描 `bin\*.exe`,逐个签名 + 时间戳后**原地覆盖**。 +- 输出:`[sign] SIGNED : excel-search-desktop.exe` 等。 +- 指定密码: + +```bat +set SIGN_PASSWORD=你的强密码 +sign.bat +``` + +### 方式二:集成到 `build.bat`(发布流程) + +`build.bat` 已内置可选签名步骤,构建后自动签名: + +```bat +set VERSION=v1.2.3 +set SIGN=1 +build.bat +``` + +构建三个 exe → 自动调用 `sign.bat` 全部签名 + 时间戳。 + +### 方式三:手动调用 osslsigncode(Git Bash) + +```bash +./tools/osslsigncode/osslsigncode.exe sign \ + -pkcs12 certs/codesign.pfx \ + -pass "ExcelSearch2026" \ + -n "Excel Keyword Search Tool" \ + -t http://timestamp.digicert.com \ + -in bin/excel-searcher.exe \ + -out bin/excel-searcher.signed.exe +mv -f bin/excel-searcher.signed.exe bin/excel-searcher.exe +``` + +> osslsigncode **不允许输入输出同一文件**,必须先生成临时文件再覆盖。 + +--- + +## 五、验证签名 + +### Git Bash(osslsigncode) + +```bash +./tools/osslsigncode/osslsigncode.exe verify bin/excel-searcher.exe +# 期望:Message digest 一致、Signer's certificate 正确、含时间戳信息 +``` + +### PowerShell(系统级,最权威) + +```powershell +Get-AuthenticodeSignature .\bin\excel-searcher.exe +# Status: Valid +# SignerCertificate: CN=Excel Keyword Search Tool, ... +# TimeStamperCertificate: CN=DigiCert Timestamp Responder, ... +``` + +--- + +## 六、时间戳说明 + +签名时使用 `-t http://timestamp.digicert.com`(RFC 3161 时间戳服务器): + +- **作用**:记录签名发生的准确时刻,即使未来证书过期,**历史签名依然有效**。 +- **必须加**:不加时间戳的签名会在证书到期后失效。 +- 备选时间戳服务器:`http://timestamp.sectigo.com`、`http://timestamp.apple.com`。 + +--- + +## 七、升级到公共证书(彻底消除误报) + +自签名证书只解决"结构误报",若要杀软完全信任并显示有效签名: + +1. 向 **Sectigo / DigiCert / 阿里云 / 腾讯云** 等购买 **OV/EV 代码签名证书**(EV 更优,需硬件 Key,签名前插 U 盾)。 +2. 拿到 `.pfx` 或证书+私钥后,替换 `certs/codesign.pfx`。 +3. 其余流程完全一致(`sign.bat` / `build.bat` / 验证方式不变)。 + +--- + +## 八、安全警示 + +- `codesign.key` 与 `codesign.pfx` 是**私钥材料**,一旦泄露,他人可冒名签名恶意程序。 +- **绝不要**提交进 git、发送给他人或放入发布包。 +- 建议: + - `certs/` 目录仅保留在受控构建机。 + - 密码定期更换(通过 `SIGN_PASSWORD` 注入,勿写死在文档/脚本明文)。 + - 发布包只包含**签名后的 exe**,不含任何 `certs/`、`tools/` 内容。 + +--- + +## 九、常见问题 + +**Q:签名后 Symantec 仍然拦截?** +- 自签名证书不被 Symantec 信任,部分机器仍可能报"未知发布者"。属预期;误报率已大幅下降。 +- 彻底解决走「七、升级到公共证书」,并向 Symantec 提交白名单申诉: + + +**Q:`subject name is expected to be in the format...`?** +Git Bash 把 `-subj` 的 `/C=CN` 当路径转换了。加 `MSYS_NO_PATHCONV=1` 前缀重试。 + +**Q:`Unable to load provider: legacy` 警告?** +osslsigncode 内置 OpenSSL 的提示,不影响 SHA256 签名结果,可忽略。 + +**Q:报 `Failed to add store lookup file`?** +验证命令的证书链查找提示,只要 `Message digest` 一致、`Signer's certificate` 正确即为签名有效,可忽略。 \ No newline at end of file diff --git a/go/build.bat b/go/build.bat index cf8609f..9fdff10 100644 --- a/go/build.bat +++ b/go/build.bat @@ -1,51 +1,64 @@ -@echo off -REM Excel Keyword Search Tool - Windows build script -REM Version can be overridden via the VERSION env var, defaults to "dev". -setlocal enabledelayedexpansion - -if "%VERSION%"=="" set VERSION=dev - -REM ---- Locate the go command ---- -where go >nul 2>nul -if not errorlevel 1 goto go_ready - -REM go is not on PATH. Locate the real go.exe under mise installs -REM (points directly at the toolchain, avoiding the mise shim stub which -REM itself requires the mise binary to be on PATH). -set "GO_BIN=" -for /d %%d in ("%APPDATA%\CherryStudio\Toolchain\mise\installs\go\*") do ( - if not defined GO_BIN if exist "%%d\bin\go.exe" set "GO_BIN=%%d\bin" -) -if defined GO_BIN ( - set "PATH=!GO_BIN!;!PATH!" - echo [build] Go toolchain auto-detected at !GO_BIN! - goto go_ready -) - -:no_go -echo [build] ERROR: go command not found. -echo Install Go from https://go.dev/dl/ and add it to PATH, -echo or ensure the mise-managed Go toolchain is installed. -pause -exit /b 1 - -:go_ready -if not exist bin mkdir bin -echo [build] Building version %VERSION% ... -go version - -go build -trimpath -ldflags "-s -w -H=windowsgui -X main.version=%VERSION%" -o bin\excel-search-desktop.exe .\cmd\desktop || goto failed -go build -trimpath -ldflags "-s -w -H=windowsgui -X main.version=%VERSION%" -o bin\excel-search-webui.exe .\cmd\webui || goto failed -go build -trimpath -ldflags "-s -w -X main.version=%VERSION%" -o bin\excel-searcher.exe .\cmd\searcher || goto failed - -echo. -echo [build] Build succeeded (version %VERSION%), artifacts in bin\: -dir /b bin -pause -exit /b 0 - -:failed -echo. -echo [build] Build failed. See the error messages above. -pause -exit /b 1 \ No newline at end of file +@echo off +REM Excel Keyword Search Tool - Windows build script +REM Version can be overridden via the VERSION env var, defaults to "dev". +setlocal enabledelayedexpansion + +if "%VERSION%"=="" set VERSION=dev + +REM ---- Locate the go command ---- +where go >nul 2>nul +if not errorlevel 1 goto go_ready + +REM go is not on PATH. Locate the real go.exe under mise installs +REM (points directly at the toolchain, avoiding the mise shim stub which +REM itself requires the mise binary to be on PATH). +set "GO_BIN=" +for /d %%d in ("%APPDATA%\CherryStudio\Toolchain\mise\installs\go\*") do ( + if not defined GO_BIN if exist "%%d\bin\go.exe" set "GO_BIN=%%d\bin" +) +if defined GO_BIN ( + set "PATH=!GO_BIN!;!PATH!" + echo [build] Go toolchain auto-detected at !GO_BIN! + goto go_ready +) + +:no_go +echo [build] ERROR: go command not found. +echo Install Go from https://go.dev/dl/ and add it to PATH, +echo or ensure the mise-managed Go toolchain is installed. +pause +exit /b 1 + +:go_ready +if not exist bin mkdir bin +echo [build] Building version %VERSION% ... +go version + +go build -trimpath -ldflags "-s -w -H=windowsgui -X main.version=%VERSION%" -o bin\excel-search-desktop.exe .\cmd\desktop || goto failed +go build -trimpath -ldflags "-s -w -H=windowsgui -X main.version=%VERSION%" -o bin\excel-search-webui.exe .\cmd\webui || goto failed +go build -trimpath -ldflags "-s -w -X main.version=%VERSION%" -o bin\excel-searcher.exe .\cmd\searcher || goto failed + +REM ---- Optional code signing (release builds) ---- +REM Enable with: set SIGN=1 && build.bat +if /i "%SIGN%"=="1" ( + echo. + echo [build] Signing artifacts with code signing certificate ... + call sign.bat + if errorlevel 1 ( + echo [build] Signing failed. + pause + exit /b 1 + ) +) + +echo. +echo [build] Build succeeded (version %VERSION%), artifacts in bin\: +dir /b bin +pause +exit /b 0 + +:failed +echo. +echo [build] Build failed. See the error messages above. +pause +exit /b 1 \ No newline at end of file diff --git a/go/sign.bat b/go/sign.bat new file mode 100644 index 0000000..026aaae --- /dev/null +++ b/go/sign.bat @@ -0,0 +1,56 @@ +@echo off +REM ============================================================ +REM Excel Keyword Search Tool - code signing script +REM Signs every exe in bin\ with Authenticode + RFC3161 timestamp +REM (timestamp keeps signature valid after cert expiry). +REM +REM Usage: +REM sign.bat sign bin\*.exe with default pfx password +REM set SIGN_PASSWORD=xxx && sign.bat use custom pfx password +REM +REM Prerequisites: +REM certs\codesign.pfx must exist (private key material, gitignored) +REM tools\osslsigncode\ portable build must be present +REM NOTE: keep this file pure ASCII to avoid cmd codepage garbling. +REM ============================================================ +setlocal enabledelayedexpansion + +set "ROOT=%~dp0" +set "PFX=%ROOT%certs\codesign.pfx" +set "SIGNEXE=%ROOT%tools\osslsigncode\osslsigncode.exe" +if "%SIGN_PASSWORD%"=="" set "SIGN_PASSWORD=ExcelSearch2026" +set "TS_SERVER=http://timestamp.digicert.com" +set "APPNAME=Excel Keyword Search Tool" + +if not exist "%PFX%" ( + echo [sign] ERROR: certificate not found at %PFX% + exit /b 1 +) +if not exist "%SIGNEXE%" ( + echo [sign] ERROR: osslsigncode not found at %SIGNEXE% + exit /b 1 +) + +set "COUNT=0" +set "FAILED=0" +for %%f in ("%ROOT%bin\*.exe") do ( + if exist "%%f" ( + "%SIGNEXE%" sign -pkcs12 "%PFX%" -pass "%SIGN_PASSWORD%" -n "%APPNAME%" -t "%TS_SERVER%" -in "%%f" -out "%%~dpnf.signed.exe" >nul 2>&1 + if errorlevel 1 ( + echo [sign] FAILED : %%~nxf + set /a FAILED+=1 + ) else ( + move /y "%%~dpnf.signed.exe" "%%f" >nul 2>&1 + echo [sign] SIGNED : %%~nxf + set /a COUNT+=1 + ) + ) +) + +echo. +if %FAILED% gtr 0 ( + echo [sign] Done: %COUNT% signed, %FAILED% failed. + exit /b 1 +) +echo [sign] Done: %COUNT% executable(s) signed and timestamped. +exit /b 0 \ No newline at end of file