本專案為非官方的個人專案。本文件是我個人整理的安全實務建議,不構成任何法規符合性聲明,也不取代歐付寶官方的安全規範或你所屬組織的資安政策。
- 1. 金鑰處理原則
- 2. 絕對不要做的事
- 3. 不得把真實資料貼進 AI 對話
- 4. 金鑰外洩的處置流程
- 5. 傳輸與環境安全
- 6. 稽核與可追溯性
- 7. 漏洞回報
- 8. 本專案自身的安全承諾
- 9. 上線前安全檢查清單
歐付寶電子發票的敏感憑證有三個:MerchantID、HashKey、HashIV。
其中 HashKey 與 HashIV 是 AES-128 的金鑰與 IV,拿到這兩個就能偽造與解密所有請求。
| 位置 | 可否 | 說明 |
|---|---|---|
.env 檔(且已加入 .gitignore) |
✅ | 本機開發的標準做法 |
| Secret Manager / Vault | ✅ | 正式環境建議做法(AWS Secrets Manager、GCP Secret Manager、HashiCorp Vault 等) |
| CI/CD 的加密 secrets | ✅ | GitHub Actions Secrets 等 |
| 容器編排的 secret 物件 | ✅ | Kubernetes Secret(搭配加密的 etcd) |
| 環境變數(由上述來源注入) | ✅ | 程式只從 os.environ 讀 |
| 程式碼中的常數 | ❌ | 一旦 commit 就永久留在 git 歷史 |
| 前端 JavaScript / HTML / CSS | ❌ | 等同公開;官方文件明文禁止 |
| 設定檔且已 commit | ❌ | config.json、application.yml 一樣不行 |
| log 輸出 | ❌ | log 常被集中收集、長期保存、多人可讀 |
| 錯誤訊息 / stack trace | ❌ | 可能直接回傳給使用者 |
| 測試程式碼、fixture | ❌ | 測試碼一樣會進 git |
| Slack / Email / 工單系統 | ❌ | 這些系統的保存期限與存取控制通常比你想的寬鬆 |
# .gitignore 必須包含
.env
.env.*
!.env.example
*.pem
*.key
secrets/# ✅ 正確
import os
hash_key = os.environ["OPAY_HASH_KEY"]
# ❌ 錯誤
hash_key = "ejCk326UnaZWKisg" # 就算是測試值,也不要寫死在程式邏輯裡本 repo 的文件與 .env.example 中出現的以下數值,是歐付寶官方技術文件公開列出的測試環境值:
| 用途 | MerchantID | HashKey | HashIV |
|---|---|---|---|
| B2C 一般特店(僅測試環境) | 2000132 |
ejCk326UnaZWKisg |
q9jcZX8Ib9LM8wYk |
| 離線發票特店(僅測試環境) | 2045501 |
9XWzRmj7UJESChyn |
sriQzbe1llJqk67P |
它們只能用在 einvoice-stage.opay.tw。 正式環境的憑證必須向歐付寶申請,且永遠不得出現在任何 repo 中。
⚠️ 測試環境也會產生真實的發票紀錄、消耗真實的字軌號碼,且只能作廢不能刪除。不要把測試環境當沙箱亂打。
| # | 禁止事項 | 為什麼 |
|---|---|---|
| 1 | 把 HashKey / HashIV commit 進任何 git repo |
git 歷史難以徹底清除,即使 force push 也可能殘留於 fork、CI 快取、他人本機 |
| 2 | 把金鑰放進前端 JS / HTML / CSS | 任何人按 F12 就看得到;官方文件明文禁止 |
| 3 | 在正式環境用 Issue 做健康檢查或連線測試 |
會產生真發票、消耗字軌號碼,只能作廢不能刪除 |
| 4 | 對開立/作廢/折讓/註銷重開盲目重試 | 逾時不等於沒開立,重送可能開出兩張發票 |
| 5 | 把正式金鑰放在測試環境或 staging | 環境隔離失效,測試資料會污染正式帳務 |
| 6 | 在 log 中輸出完整的 Data 明文 |
明文含買受人 Email、手機、統編等個資 |
| 7 | 用同一組金鑰跑多個不相關的系統 | 一處外洩即全面外洩,且無法定位來源 |
| 8 | 把發票 PDF/截圖未脫敏就放進 repo 或工單 | 含發票號碼、統編、買受人資訊 |
| 9 | 讓 AI agent 自動對正式環境送出不可逆請求 | 開立/作廢/折讓皆不可復原 |
| 10 | 用 verify=False 或忽略 TLS 憑證驗證 |
中間人攻擊可直接取得你的 Data 與回應 |
Warning
不要把真實發票資料或買受人個資貼進任何 AI 對話。 這包含 Claude、ChatGPT、Gemini、Copilot、Cursor、以及任何雲端 AI 服務。
| 類別 | 具體項目 |
|---|---|
| 憑證 | 正式環境 MerchantID、HashKey、HashIV、廠商後台帳密 |
| 買受人個資 | Email、手機號碼、姓名、地址、統一編號、載具號碼 |
| 發票資料 | 真實發票號碼、隨機碼、金額明細、品項內容 |
| 內部資訊 | 內部系統網址、資料庫連線字串、內部訂單編號規則 |
| 原始封包 | 未脫敏的請求/回應 JSON、完整的加密 Data 字串 |
- 多數 AI 服務的對話可能被保存、可能被用於服務改善(依方案與設定而定)。
- 對話記錄可能被同組織其他成員存取。
- 個資外洩涉及《個人資料保護法》責任,責任在你不在 AI 廠商。
- 加密後的
Data配上金鑰即可還原——貼了金鑰又貼封包等於直接公開明文。
- 我的請求是 {"MerchantID":"3012345","HashKey":"aB3xK9pQ2mN7vL4z", ...}
- 開立失敗,發票號碼 AB12345678,買受人 wang@example.com,統編 12345678
+ 我的請求結構是 {"MerchantID":"<REDACTED>","HashKey":"<REDACTED>", ...}
+ 開立失敗,發票號碼 AA00000000,買受人 user@example.com,統編 00000000
+ 錯誤是 TransCode=0,訊息「時間戳記錯誤」脫敏對照表:
| 真實資料 | 貼給 AI 時用 |
|---|---|
正式 MerchantID |
<MERCHANT_ID> 或 2000132(公開測試值) |
HashKey / HashIV |
<REDACTED> |
| 發票號碼 | AA00000000 |
| 統一編號 | 00000000 |
user@example.com |
|
| 手機 | 0900000000 |
| 手機條碼載具 | /ABCD123 |
| 愛心碼 | 001 |
| 訂單編號 | ORDER-0001 |
錯誤訊息、欄位名稱、程式碼結構、狀態碼都可以貼——AI 需要的是這些,不是你的真實資料。
一旦懷疑 HashKey / HashIV 外洩(誤 commit、貼錯視窗、離職交接、第三方服務被入侵),立即依序執行:
- 登入歐付寶廠商後台:
- 依後台指示重新產生
HashKey/HashIV。 - 若後台無法自助輪換,立即聯繫歐付寶客服/業務窗口,說明是資安事件並要求緊急處理。
舊金鑰在新金鑰生效前仍然有效。時間就是損害範圍,不要為了「先查清楚」而延後輪換。
- Secret Manager /
.env/ CI secrets / 容器 secret 全部更新。 - 逐一重啟服務並確認新金鑰生效(跑一次唯讀 API,例如
GetInvoiceWordSetting)。 - 檢查有沒有遺漏的環境(排程主機、備援機、開發者本機)。
# 如果是誤 commit:先確認範圍
git log --all -S 'HashKey' --oneline
# 從歷史移除(會改寫歷史,需協調所有協作者重新 clone)
# 建議使用 git-filter-repo 或 BFG Repo-Cleaner
⚠️ 改寫 git 歷史不代表金鑰安全了。 只要曾經 push 到遠端(尤其是公開 repo),就必須假設它已經外洩——輪換是唯一的補救,清歷史只是善後。
- 到廠商後台查詢近期發票開立紀錄,確認有無非預期的開立、作廢、折讓。
- 比對自家稽核記錄與後台紀錄,找出差異。
- 檢查字軌剩餘量是否有異常消耗。
- 記錄事件時間軸、影響範圍、處置動作。
- 依你所屬組織的規範判斷是否需要通報。
- 補上防呆:pre-commit hook、secret scanning、CI 檢查。
# .git/hooks/pre-commit(記得 chmod +x)
#!/bin/sh
if git diff --cached | grep -nE 'Hash(Key|IV)\s*[=:]\s*["\x27][A-Za-z0-9]{16}["\x27]'; then
echo "❌ 偵測到疑似金鑰,已阻擋 commit。確認無誤請用 --no-verify。"
exit 1
fi也建議在 GitHub repo 設定中啟用 Secret scanning 與 Push protection。
| 項目 | 要求 |
|---|---|
| TLS | 僅支援 TLS 1.2 以上,僅開放 443 port。不得停用憑證驗證。 |
| 防火牆 | 以 FQDN 設定 einvoice.opay.tw、einvoice-stage.opay.tw——官方主機 IP 不固定,鎖 IP 會在對方換機時全面失效。 |
| 主機時間 | RqHeader.Timestamp 驗證區間只有 10 分鐘,主機必須跑 NTP。 |
| 環境隔離 | 測試與正式的金鑰、資料庫、log 完全分離。正式金鑰不得出現在非正式環境。 |
| 回傳網址 | 不支援中文網址,請用 punycode。 |
| 出站代理 | 若經由代理出網,確認代理不會記錄請求 body(Data 欄位是加密的,但仍屬敏感)。 |
| 相依套件 | 定期更新加密相關套件(pycryptodome、OpenSSL)。 |
發票是帳務憑證,不可逆操作必須留下可追溯的記錄。
- 開立(
Issue/DelayIssue/OfflineIssue) - 作廢(
Invalid/OfflineInvalid/AllowanceInvalid) - 折讓(
Allowance/AllowanceByCollegiate) - 註銷重開(
VoidWithReIssue) - 字軌設定變更(
AddInvoiceWordSetting/UpdateInvoiceWordStatus)
| 欄位 | 說明 |
|---|---|
| 時間戳記 | 含時區 |
| 操作者 | 使用者帳號或系統識別(不要只寫 system) |
| 操作類型 | 開立/作廢/折讓/… |
| 業務識別 | RelateNumber、發票號碼 |
| 請求摘要 | 不含金鑰、不含完整個資,只留必要欄位 |
| 回應結果 | TransCode、RtnCode、RtnMsg |
| 冪等鍵 | 用於逾時後比對 |
- 存取權限最小化,不要放進全公司可讀的日誌平台。
- 個資欄位(Email、手機、統編)遮蔽後再寫入。
- 保存期限依你所屬組織與相關法規規定辦理(發票相關憑證的法定保存年限請諮詢會計師或稅務專業人員,本文件不提供法律意見)。
- 不可修改(append-only)或有變更記錄。
本政策涵蓋本 repo 的內容:程式碼模板、文件中的安全建議、測試工具。
不涵蓋歐付寶的服務本身。若你發現的是歐付寶平台的漏洞,請直接聯繫歐付寶官方,不要在本 repo 公開。
Important
請勿開公開 issue 回報安全問題。 公開 issue 等於在修復前先告訴所有人怎麼利用它。
請走以下私下管道(擇一):
- GitHub Security Advisory(建議):在本 repo 的 Security → Report a vulnerability 提交私密回報。
- 透過維護者網站的聯絡方式:https://www.mitch.tw
- 問題描述與影響範圍
- 重現步驟(請用測試環境與脫敏資料)
- 受影響的檔案與版本
- 你認為的修復方向(若有)
| 階段 | 目標時間 |
|---|---|
| 確認收到 | 7 個工作天內 |
| 初步評估與回覆 | 14 個工作天內 |
| 修復並發布 | 視嚴重程度,高風險優先 |
本專案由我一個人在下班時間維護,無法承諾 SLA。以上是努力目標,不是保證。 我不提供漏洞獎金,但會在
CHANGELOG.md致謝(除非你希望匿名)。
- 文件中出現官方公開的測試環境金鑰(
2000132/ejCk326UnaZWKisg/q9jcZX8Ib9LM8wYk、2045501/9XWzRmj7UJESChyn/sriQzbe1llJqk67P)——這些是官方技術文件明列的公開值,僅適用測試環境。 - 模板程式碼未實作某項防護,但文件中已明確標示「這是模板,正式使用前請自行補強」。
- ✅ 本 repo 不含任何正式環境金鑰,也不接受含正式金鑰的 PR。
- ✅ 本 repo 不收集任何使用者資料,沒有 telemetry、沒有追蹤、沒有外部呼叫(除了你自己主動發出的 API 請求)。
- ✅ 模板程式碼的相依套件刻意最小化:Node.js 驗證器零相依、PHP client 只用內建擴充。
- ✅ 所有
.env.example中的金鑰皆為官方公開測試值,且逐處標註「僅測試環境」。 - ✅ 測試主控台的「開立測試發票」預設關閉,需同時設定環境變數與前端勾選確認才會送出。
金鑰
[ ] .env 已在 .gitignore 中,且 git status 看不到它
[ ] git log -S 'HashKey' 查不到任何真實金鑰
[ ] 正式金鑰存在 Secret Manager,不在程式碼、不在設定檔
[ ] 前端 bundle 中搜尋 HashKey / HashIV 無結果
[ ] 已啟用 GitHub secret scanning 與 push protection
環境
[ ] 測試與正式環境的金鑰、資料庫、log 完全分離
[ ] 主機 NTP 正常,時間偏移 < 1 分鐘
[ ] 防火牆以 FQDN 設定,非鎖 IP
[ ] TLS 憑證驗證未被停用
程式
[ ] 兩層回應碼(TransCode 與 RtnCode)都有檢查
[ ] 開立/作廢/折讓/註銷重開沒有自動重試
[ ] 逾時處理是「先用 GetIssue 查詢」而非直接重送
[ ] 每筆不可逆操作都有冪等鍵與稽核記錄
[ ] log 中沒有完整的 Data 明文、沒有金鑰、個資已遮蔽
[ ] 正式環境沒有任何以 Issue 作為健康檢查的排程
流程
[ ] 有金鑰輪換的操作手冊與負責人
[ ] 有字軌餘量告警與負責人
[ ] 團隊都知道「不可把真實資料貼進 AI 對話」
本文件為個人整理的實務建議,不構成法律或資安顧問意見,也不宣稱符合任何標準或法規。 正式環境的安全要求請以歐付寶官方規範、你所屬組織的資安政策,以及專業人員的意見為準。