2026-09-08 · 建站运维
这两天做了两件事:把博客的备份与记忆同步链路完整捋了一遍;给博客程序(emlog)做了一次授权机制的代码审查。前者牵扯出两个日常工具——sha256 与 GPG;后者回答了一个悬了很久的问题:没注册正版,程序到底会不会「搞事情」。三件事都值得展开说说,合在一起写一篇长的。
先讲一个场景
假设你从网上下载了一个几百 MB 的系统镜像,吭哧吭哧下载完,准备写入 U 盘安装。这时候你最担心什么?一是文件在传输过程中损坏了——网络抖动、服务器出错、磁盘坏道,都可能让某个字节悄悄改变;二是文件被掉包了——下载源被劫持,你以为的官方镜像其实是别人放上去的篡改版。前者是「完整性」问题,后者是「真实性」问题。
再假设你把一包重要的数据传到某个云盘或者代码托管平台。你最担心什么?平台账号被盗、误操作把私有仓库设成公开、平台内部人员越权、平台服务器被拖库——任何一环出问题,你的数据就可能裸奔到别人手里。这是「机密性」问题。
这两个场景,几乎概括了数字世界数据安全的所有焦虑:数据在传输和存储过程中,怎么保证「没被改」?怎么保证「别人看不懂」?如果还想更进一步,怎么证明「确实是我发的」?
sha256 和 GPG,就是回答这些问题的两件趁手工具。一个负责给数据按指纹,证明它没被调包;一个负责给数据装信封,保证只有持有钥匙的人能拆开。本站的备份体系把这两件工具组合起来用了大半年,期间还真的经历过一次「信封」立功的时刻——这些下文都会讲到。
sha256:数据的指纹
什么是哈希
哈希(hash)函数,是把任意长度的输入,计算出一个固定长度输出的函数。它有几个关键性质:
- 确定性:同样的输入,永远得到同样的输出;
- 单向性:从输出几乎不可能反推输入;
- 雪崩效应:输入哪怕只改一个比特,输出也会面目全非;
- 抗碰撞:理论上很难找到两个不同的输入,得到相同的输出。
SHA-256 是 SHA-2 家族里应用最广的一个,输出 256 位,写成十六进制是 64 个字符,像一串指纹:
$ echo -n "hello" | sha256sum
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
把输入从 hello 改成 hallo,输出立刻变成完全不同的一串:
$ echo -n "hallo" | sha256sum
b27c70fa5eb85340b7c8e03f00c7b0226bf0a1df0aab44da5abcf2f6a8a18df8
两个输出之间看不出任何关联。这正是哈希函数被称为「指纹」的原因:内容可以很长,指纹永远 64 个字符;内容稍有变动,指纹立刻对不上。
哈希家族的来龙去脉
哈希算法不是一天建成的,了解一点历史有助于理解为什么现在是 SHA-256 当家。
上世纪 90 年代初,MD5 由罗纳德·李维斯特设计,输出 128 位,一度是校验和的代名词,至今很多下载站还在用它。但 2004 年,中国密码学家王小云团队宣布找到了 MD5 的碰撞——也就是说,可以构造两个内容不同、但 MD5 完全一样的文件。这在密码学界投下重磅炸弹,MD5 从此被宣告死亡,只适合做非安全场景的快速校验。
同一时期,美国国家标准与技术研究院(NIST)在 1993 年发布了 SHA-0,次年修正为 SHA-1,输出 160 位。SHA-1 在很长一段时间里是 SSL 证书和 Git 的默认算法。但它的命运与 MD5 类似:2017 年,Google 和荷兰 CWI 研究所宣布了全球首例 SHA-1 碰撞(代号 SHAttered),构造出两个内容不同但 SHA-1 相同的 PDF 文件。从那以后,SHA-1 也被主流安全体系全面淘汰,浏览器不再信任 SHA-1 证书。
SHA-2 家族(2001 年发布)至今安然无恙,SHA-256 正是其中使用最广的一员。256 位的输出空间是 2 的 256 次方,这个数字有多大?宇宙中可见原子的总数大约是 10 的 80 次方,而 2 的 256 次方大约是 10 的 77 次方——也就是说,即便把全宇宙的原子都拿来做并行计算,想靠穷举找到一次碰撞,概率也低到可以忽略。这就是「抗碰撞」的底气来源。
2015 年,NIST 又标准化了 SHA-3(基于 Keccak 算法,采用与 SHA-2 完全不同的海绵结构),作为 SHA-2 的备胎。SHA-2 至今没有实质性的攻击,所以 SHA-3 更多是「战略储备」,日常使用中 SHA-256 依然是绝对主流。
哈希用在哪些地方
哈希大概是计算机世界里应用最广泛的密码学原语,随处可见:
- 下载校验:几乎所有的 Linux 发行版、软件镜像站都会在下载页给出 SHA256SUMS 文件,下载完执行
sha256sum -c SHA256SUMS,一行命令批量核对所有文件,传输损坏、下载不完整立刻现形; - Git 版本管理:Git 的每一次提交,其对象 ID 就是内容哈希。Git 历史上长期使用 SHA-1,如今新仓库已经可以选用 SHA-256,以彻底摆脱 SHA-1 的阴影。哈希让 Git 天然具备防篡改能力:任何历史提交被改动,后续所有提交的哈希都会对不上;
- 区块链:比特币的工作量证明就是对区块头做双重 SHA-256 计算,挖矿本质上是在暴力搜索一个满足难度条件的哈希;
- 内容寻址:IPFS 这类分布式文件系统直接用哈希当文件名,内容一样,地址就一样,天然去重;
- 密码存储:网站数据库里不应该存明文密码,而应该存密码的哈希。不过要注意,单纯 SHA-256 并不适合存密码——它太快了,攻击者可以每秒尝试几十亿次,配合彩虹表(预先算好的「密码→哈希」对照表)更是可以秒破弱密码。专业的做法是用 bcrypt、scrypt、argon2 这类刻意「慢」的算法,并且每个用户加不同的随机盐。记住一个原则:SHA 适合校验文件,不适合存密码;
- 消息认证:哈希结合密钥可以构造 HMAC(基于哈希的消息认证码),用来验证消息在传输中既没被改、发送方也确实持有密钥。为什么不能直接用哈希?因为哈希是公开的,任何人拿到文件都能重算,改完文件再重算一遍哈希就能骗过校验——哈希只防「意外损坏」,不防「故意篡改」。要防故意篡改,需要密钥参与的 HMAC,或者直接用 GPG 签名(下文会讲)。
命令行实操:三句口诀
日常使用 sha256,记住三句口诀就够:
- 算一个文件的指纹:
sha256sum 文件名,输出「哈希值 + 文件名」; - 批量校验:下载官方发布的 SHA256SUMS 文件后,
sha256sum -c SHA256SUMS,程序会自动比对每个文件并报告 OK 或 FAILED; - 生成自己的校验清单:
sha256sum 文件1 文件2 > SHA256SUMS,发布文件时连同清单一起给出去。
实操中还有两个容易忽略的细节:一是哈希字符串必须完整比对,粘贴时少一位都查不出来,严谨的做法是直接复制而不是手敲;二是哈希本身要通过可信渠道获取——官方下载页给的哈希,要配合 HTTPS 和(更理想的)发布者签名一起信任,否则攻击者改完文件顺手把页面上的哈希也改了,校验就失去了意义。这也是为什么「哈希 + 签名」常常成对出现。
本站怎么用 sha256
在 1dao 的备份体系里,sha256 承担的是「完整性把关人」的角色。
服务器每天凌晨由 backup-server.sh 把数据库、系统配置、凭据、站点数据等打成若干数据包;备份同步脚本在推送 Gitee 前后,都会对包做哈希记录。恢复演练时,restore 脚本先对拿到的包重算哈希、与记录比对,一致才继续往下走——确保从仓库拉回来的备份,和当初推上去的备份分毫不差。
最有意思的一次应用,是前几天把服务器助手的工作记忆导入本地助手。服务器助手从 8 月 9 日「出生」到 8 月 18 日的工作笔记,随备份体系一起打包加密,躺在 Gitee 私有仓里。本地助手导入时,流程是:先验 sha256,再 GPG 解密,然后才并入自己的记忆库。哈希在这里是信任的起点——先确认这份快照在仓库里躺了这么多天没有被任何人动过手脚,才敢把它当作自己记忆的一部分。
但必须清醒认识 sha256 的边界:它只证明「没被改」,不证明「别人看不懂」。明文文件配上哈希,照样是明文,谁拿到都能看。要防「看得懂」,得靠下一节的主角——加密。
GPG:数据的信封
加密的两千年简史
加密不是新鲜事。两千年前的凯撒大帝就发明了「凯撒密码」:把字母表平移若干位,收到信的人反向平移就能读。这种加密方式有一个共同的名字——对称加密:加密和解密用同一个「钥匙」,加密方怎么转的,解密方就得怎么转回来。
对称加密的问题显而易见:钥匙怎么安全地送到对方手里? 凯撒可以派亲信骑马送信顺便捎带钥匙,但放到互联网时代,你要给大洋彼岸的人发密文,总不能先把密钥发过去——密钥在传输过程中被截获,加密就形同虚设。这就是著名的「密钥分发难题」,困扰了密码学家几千年,直到 1976 年才被惠特菲尔德·迪菲和马丁·赫尔曼打破。他们提出了一个石破天惊的想法:能不能加密和解密用不同的钥匙?公钥公开给全世界,私钥自己藏好——别人用你的公钥加密,只有你能用私钥解密。这样钥匙根本不需要传递,分发难题迎刃而解。这就是「公钥密码学」(非对称加密),迪菲-赫尔曼密钥交换论文的发表,被视为现代密码学的诞生标志。
对称加密:快而简单
现代对称加密早已不是字母平移,而是基于复杂的置换和混淆运算,代表作是 AES(高级加密标准),提供 128/192/256 位密钥,至今未被有效攻破,是全世界用得最多的加密算法——你手机的 HTTPS、Wi-Fi 密码、硬盘加密,底层都是 AES。
对称加密的优点非常突出:快。AES 加解密几百 MB 的文件只要几秒,硬件还专门做了加速指令。它的弱点也直接:密钥管理。一把钥匙两个人用,十个人就要四十五把钥匙,人数一多就失控;而且密钥本身还得安全传递和保存。
用口令做密钥要特别注意:口令不是密钥。GPG 会把你的口令通过密钥派生函数(KDF)加工成真正的密钥材料,但加密强度最终受限于口令本身——「123456」这种口令,派生出的密钥再强也经不起字典攻击。所以用口令加密时,口令必须足够长、足够随机,建议用密码管理器生成,或者用骰子词表(Diceware)凑一句长口令。
非对称加密:慢而优雅
非对称加密用一对数学上关联的钥匙:公钥和私钥。用公钥加密的数据,只有配对的私钥能解开;反过来,用私钥签名的数据,大家用公钥就能验证签名确实出自私钥持有人。公钥可以大大方方贴在网上,私钥必须锁进保险箱。
现代非对称加密的主流是 RSA 和椭圆曲线(ECC)。RSA 的安全性建立在「大整数分解很难」之上——两个大质数相乘很容易,但拿到乘积反推是哪两个质数,难到超算也束手无策。椭圆曲线的安全性建立在「椭圆曲线离散对数很难」之上,同等安全强度下密钥更短、计算更快,所以新系统越来越偏爱 ECC。
非对称加密的缺点是慢,比 AES 慢几个数量级。所以实际系统几乎从不直接用公钥加密大段数据,而是采用「混合加密」:随机生成一个会话密钥,用 AES 加密数据本体,再用接收者的公钥加密这个会话密钥。收信人先解开会话密钥,再用它解数据。又安全又快,HTTPS 的 TLS 协议、PGP、几乎所有现代加密系统都是这个套路。
PGP 与 GPG:把公钥密码带到民间
1991 年,美国程序员菲尔·齐默尔曼写了一个叫 PGP(Pretty Good Privacy)的程序,把公钥加密、签名、压缩打包成一个普通人能用的工具,还免费分发。当时美国对密码出口管制极严,PGP 的源码被印成书出版(书籍不受出口管制),「用纸传播密码」成了密码学史上有名的一幕。齐默尔曼一度被调查数年,最终不了了之——而 PGP 已经传遍世界,成了「民间加密」的代名词。
PGP 后来商业化了,1997 年,德国程序员维尔纳·科赫发起 GNU Privacy Guard(GPG)项目,从零实现 OpenPGP 标准(RFC 4880),完全免费开源。今天 Linux 世界里说的 GPG,几乎都是指 GnuPG。它是 Debian/Ubuntu 软件源签名验证的基础设施,是邮件加密 Enigmail/Thunderbird 的底层引擎,也是无数运维脚本里加密备份的首选工具。
GPG 实操:五种最常见的用法
GPG 上手并不难,日常最常用的操作就五个:
1. 对称加密一个文件(用口令,不需要密钥对):
$ gpg -c secret.tar.gz # 提示输入口令,生成 secret.tar.gz.gpg
$ gpg -d secret.tar.gz.gpg # 解密到标准输出,可重定向回文件
2. 生成自己的密钥对:
$ gpg --full-generate-key # 交互式:选算法(默认 RSA/ECC 即可)、设长度、填身份、设私钥口令
3. 用对方的公钥加密(只有对方私钥能解):
$ gpg --export --armor alice@example.com > alice.asc # 导出公钥给别人
$ gpg --import alice.asc # 导入别人的公钥
$ gpg -e -r alice@example.com report.pdf # 用 Alice 的公钥加密
4. 签名与验签(证明文件确实出自你手、且未被改动):
$ gpg --detach-sign --armor release.tar.gz # 生成独立的 .asc 签名文件
$ gpg --verify release.tar.gz.asc release.tar.gz # 验签
5. 吊销证书:私钥丢失或泄露时,用预先备份的吊销证书声明「这把公钥作废了」,防止别人继续用旧公钥给你发密文。
密钥对管理:私钥是命根子
如果用了密钥对(而不是口令对称加密),管理责任就重了一层:私钥一旦丢失,所有用你公钥加密的数据都永远无法解开;私钥一旦泄露,所有依赖你私钥签名的信任瞬间崩塌。几条实操建议:
- 私钥要备份,且加密存放:
gpg --export-secret-keys --armor可以把私钥导出备份,导出的文件本身要用强口令加密,存到离线介质; - 公钥要分发:
gpg --export --armor导出的公钥可以贴到个人主页、放上公钥服务器,方便别人给你发加密邮件、验证你的签名; - 吊销证书要提前生成:
gpg --gen-revoke生成吊销证书并离线保存,私钥丢失时用来宣告旧公钥作废——没有它,别人无法知道你换钥匙了; - 私钥口令要与数据口令分开:很多场景下,加密数据的口令和私钥口令是两条独立的防线,混用会成倍放大泄露风险。
签名:补上哈希缺的那块拼图
上一节留了个尾巴:sha256 只防意外损坏,不防故意篡改——攻击者改完文件,重算一个哈希附上,校验照样通过。GPG 签名恰好补上这块:对文件的哈希做签名。私钥只有你持有,别人伪造不了你的签名;文件任何改动都会导致哈希变化、验签失败。所以「下载文件 → 验证 GPG 签名 → 再比对 sha256」是发布严肃软件的标准姿势,Debian 的 apt 每次装软件都在背后做这件事:用仓库公钥验证 Release 文件的签名,再按文件里的哈希核对每个包。
一句话总结三者的分工:sha256 证明文件没被改,签名证明改不了它的人没动过它,加密证明别人看了也白看。
本站怎么用 GPG
1dao 的备份走的是 GPG 对称加密路线:backup-server.sh 每天凌晨把数据库、系统配置、凭据、站点数据等打成几类数据包,随后同步脚本用 GPG 口令把每个包加密,才推上 Gitee 私有仓。加密口令单独存放在服务器的 root-only 文件里,与备份包物理隔离——备份包在仓库里,口令在机器上,两者不在一处。
为什么私有仓还要再加密一层?两个原因,都是教训换来的:
第一,仓库不等于保险箱。 平台侧的风险——账号被盗、误操作公开、平台故障——都不在自己掌控之内。而线上站点确实出过一次备份目录因 nginx 配置疏忽短暂对公网开放的事故,爬虫当场就把历史备份包抓走了。那次事故之后,「先加密,再上传」被写成本站的备份铁律:密文即使流出去,没有口令也只是一堆无法解读的字节。这正是「信封」的意义——它假设最坏情况已经发生,并提前让最坏情况变得无害。
第二,副本越多,暴露面越大。 备份讲究 3-2-1 原则:至少 3 份副本、2 种不同介质、1 份放在异地。本站的备份体系有本地留存、Gitee 主仓、四层独立快照仓(日/周/月/年),副本数量远超 3 份。每多一份副本,就多一个可能泄露的节点。只有数据本体是加密的,副本数量本身才不再构成安全风险——这个思路,和「把鸡蛋分篮子装之前,先给每个鸡蛋上锁」是一个道理。
恢复方向,restore 脚本把流程做成半自动:从仓库拉回加密包 → GPG 解密 → sha256 校验 → 按域还原。加密与校验在恢复链路上同样缺一不可。
关于密钥管理的三条忠告
用 GPG 加密数据,真正的风险往往不在算法,而在密钥管理。三条忠告:
- 口令丢了,数据就没了。 GPG 对称加密没有找回机制,没有后门,没有客服电话。口令必须单独妥善保存,最好写进密码管理器,并留一份离线副本;
- 加密不是备份。 加密保护的是机密性,不保护可用性。硬盘坏了、仓库被清了,密文再安全也变不回数据。加密要建立在可靠的备份之上,而不是替代备份;
- 先想恢复,再谈加密。 上加密之前,先在测试环境完整走一遍「加密 → 传输 → 解密 → 校验」的恢复演练,确认流程能闭环,再让加密进入生产。本站每次备份体系大改,都会跟着做一次恢复演练,演练中发现的问题,远比事故当天发现的问题便宜。
emlog 未注册:到底会不会删数据?
为什么会有这个疑问
本站的博客跑在 emlog Pro 上。emlog 是一款国产的轻量级博客程序,中文圈子用了十几年,以「小而美」著称——单文件后台、无需复杂环境、开箱即用,很适合个人博客。Pro 版是付费版本,通过购买授权获得一个 32 位的注册码(emkey),填入后台即可完成注册。
但本站的博客从上线第一天起,后台就一直挂着一行字:「未注册的版本」。博客照常发文、评论、换主题、装插件,一切功能都正常,唯独这行提示如影随形。它不会造成任何即时故障,却像仪表盘上一个常亮的黄灯,让人心里不踏实:程序会不会在某个时刻,因为我没付费,就悄悄做点什么?比如删掉文章、禁用插件、锁死后台?
这个疑问其实很有代表性。闭源或半闭源软件的用户,天然会对「未注册限制」产生两种担忧:一是惩罚性担忧——不付费会不会被「报复」,数据被删、功能被锁;二是隐私性担忧——程序会不会偷偷联网上报数据、甚至留后门远程操控。这两种担忧能不能解除,靠猜没用,得看代码。正好博客源码就在手边,工作区里有一份完整的 Git 仓库,于是花了一个晚上,把授权相关的代码从头到尾读了一遍。下面是完整的审查记录。
审查方法:像侦探一样追线索
代码审查不需要从头读整个程序——几万行 PHP 通读一遍不现实,也没必要。正确做法是沿着可疑的线索顺藤摸瓜:
第一步,全文搜索关键词。把「注册」「emkey」「授权」「未注册」这些词在代码库里搜一遍,凡是命中文件全部列出来。搜索结果很快就锁定了几个核心文件,其中最关键的是 include/lib/register.php——文件名直白地写着「注册」,整个授权逻辑大概率都在这里。
第二步,精读核心类。把 register.php 从头到尾读一遍,搞清楚它提供了哪些方法、每个方法做了什么。
第三步,反查调用点。在全文搜索 Register::(类名加双冒号),找出这个类的方法都被谁在什么条件下调用。这一步最重要——类本身定义了「能力」,调用点才决定这些能力在什么场景下被触发。
三步走完,整个授权机制的脉络就清晰了。下面按这个顺序汇报。
顺便记一个审查中的小插曲:第一次用「未注册」三个字在代码库里搜索时,竟然一无所获。反复确认后才发现,报错文案在源码里是 HTML 实体编码的——html_entity_decode("未注册..."),运行时才解码成中文。直接搜中文当然搜不到,换成 emkey、authcode、register 这些英文关键词,线索才纷纷浮出水面。这个细节提醒我们:搜索代码要中英文多路并进,界面文案经过编码或国际化包装后,不一定以你看到的样子存在于源码里。
Register 类:授权逻辑的全貌
include/lib/register.php 里定义了一个 Register 类,整个授权机制就六个方法:
isRegLocal() —— 本地注册检查。从缓存里取出 emkey,检查长度是否等于 32。注意它只查「长度」,不查「真实性」——只要填了一个 32 位的字符串,本地就算「已注册」。真正的真实性校验在下一个方法。
isRegServer() —— 服务器在线校验。把 emkey 发给 emlog 官方服务器(store.emlog.net)验证真伪。这个方法有个容易被忽略的细节:如果 emkey 为空或长度不对,它在发请求之前就本地返回 false——也就是说,未注册状态下的站点,根本不会因为这个校验而产生网络请求。只有填了 32 位 key 的站点,才会真正访问官方服务器。
doReg() —— 注册动作。后台提交 emkey 时调用,把 key 发给官方注册接口,返回结果。失败时会把 emkey 清空。
verifyDownload() —— 下载校验。从官方商店下载插件/模板前调用,向服务器验证当前 emkey 是否有下载权限。
verifyEmKey() —— emkey 真伪验证。isRegServer 的内部实现,校验失败时调用 clean()。
clean() —— 清理方法。内容只有两行:把 emkey 和 emkey_type 两个配置项清空,然后刷新缓存。
到这里,第一个问题的答案其实已经出来了:整个授权逻辑里,最「重」的操作就是 clean(),而它只是清空两个配置项——不碰文章表、不碰评论表、不碰插件目录、不碰任何文件。整个 register.php 里没有任何一行代码与删除内容有关。
但光读这一个文件还不够,万一删除逻辑藏在别的文件里、由注册状态触发呢?这就轮到第三步:反查调用点。
调用点清单:未注册状态到底触发了什么
全文搜索 Register:: 后,把所有调用点列成了一张表,逐个检查上下文。去除界面展示类的调用(比如后台横幅「未注册」的显示逻辑),真正影响功能的调用点如下:
api_controller.php(接口发文路径):
if (!Register::isRegLocal() && $sta_cache['lognum'] > 50) {
Output::error("未注册的版本");
}
含义:未注册且全站文章数大于 50 时,拒绝通过 API 发文。
article.php(后台写文章页):
if (!Register::isRegLocal() && $sta_cache['lognum'] > 50) {
FlashMsg::redirectAdmin('auth', 'error_article');
}
含义:同样的条件,后台打开写文章页面时直接跳转到注册引导页。
plugin.php / template.php(在线升级分支):
if (!Register::isRegLocal()) {
Output::error('emlog_not_registered');
}
含义:未注册时,禁止从官方商店在线下载/升级插件与模板。
store.php(应用商店):
if (false === Register::verifyDownload($source)) { ... }
含义:商店里下载应用前,先向官方验证 emkey 的购买/下载权限。
account.php / data.php:
Register::isRegServer();
含义:访问这两个后台页面时触发一次在线校验——但如前所述,未注册(空 key)时本地短路,不会产生网络请求。
把整张表看完,结论非常干净:未注册状态能触发的,只有「拒绝发文」「禁止商店下载」「跳转注册页」三类功能限制,外加一些界面提示。没有任何一条路径与删除文章、删除插件、清空数据有关。
作为交叉验证,我还在整个代码库里搜了删除类操作(文章删除、插件删除、目录清理等)的入口,确认它们都只由后台管理员的显式操作触发,与注册状态没有任何关联分支。同时检查了定时任务与计划任务机制——emlog 没有内建需要注册状态参与的定时清理逻辑,不存在「某天半夜自动执行惩罚」的代码路径。
三个限制,逐一说明
限制一:50 篇发文上限。 这是未注册状态最实质的限制:全站已发布文章(审核通过、非草稿)超过 50 篇后,后台写文章页面会被重定向到注册引导,API 发文接口直接报「未注册的版本」。本站目前文章数 52 篇,已经触发这个限制——但日常发文毫无感觉,原因是我们发文走的是自建的 publish-blog.sh 脚本,它直接调用 emlog 的模型层入库、再刷新缓存,根本不经过后台页面和 API 这两道检查。这也算一个「条条大路通罗马」的实例:限制锁的是门,没锁窗户。
需要提醒的是,如果未来接入 MCP 这类走标准 API 的发文通道,就会撞上这堵墙——要么注册正版解锁,要么让通道也走直插模型层的路线。
限制二:商店与在线升级受限。 未注册时,无法从 emlog 官方商店在线安装、升级插件和模板(本地已有的插件、模板不受影响,照常运行)。这条限制的实际影响要看使用习惯:如果插件模板都自己维护、或者只在初始化时装一次,几乎感觉不到;如果习惯频繁在线升级官方应用,就会比较难受。
限制三:后台横幅提示。 后台多处出现「未注册的版本」和注册引导链接,属于纯粹的界面提示,不影响任何操作,可以无视。
远程接口:全景盘点
第二个担忧——程序会不会偷偷联网、甚至留后门——同样用代码回答。把整个代码库里所有发起网络请求的位置全部搜出来(搜索 curl、文件抓取函数、HTTP 客户端等关键词),逐一核对目标地址和触发条件,结果如下:
| 接口 | 触发条件 | 说明 |
|---|---|---|
| store.emlog.net/proauth/register | 后台手动提交注册码 | 注册动作本身 |
| store.emlog.net/proauth/verify | 访问账号/数据页 | 在线校验;空 key 本地短路,不发包 |
| store.emlog.net/service/upgrade | 后台手动点「检查更新」 | 版本升级检查 |
| www.emlog.net 插件/模板下载 | 商店手动下载 | 需已注册 |
| www.emlog.net/docs/faq | 使用内置 AI 问答助手 | 抓取官方 FAQ 做资料 |
结论:所有外呼都是「用户手动操作触发的功能请求」,目标域名只有 emlog 官方两个。代码里没有任何定时外呼、没有启动即上报、没有远程指令接收与执行通道。升级功能确实会从官方拉取 SQL 脚本和代码包执行,但它做了双重防护:仅限管理员手动触发,且目标域名被硬编码白名单(isAllowedUpgradeHost)锁死,只允许 emlog.net 系的两个域名——即使后台被攻破,攻击者也很难借这个通道把下载地址指向第三方。
审查结论
把代码证据汇总,可以给出一个明确的结论:
emlog 未注册的本质是「功能试用限制」,不是「数据炸弹」,也不是「后门木马」。 它不会删除你的文章和插件,不会在半夜偷偷执行什么,不会把你的数据上报给谁;它只是诚实地告诉你:这是未付费版本,文章超过 50 篇就不能再通过常规入口发文了,商店的在线服务也不对你开放。
从产品逻辑上说,这也是合理的:免费版提供完整功能体验,用发文数量作为付费转化的临界点,属于温和的「先用后买」策略,而不是「先绑架再勒索」的流氓手法。前者催你付费,后者逼你付费,代码风格一望便知。
一些延伸思考
审查完 emlog,顺手想了几件事,也算给同类的「未注册焦虑」一个通用的解法:
- 焦虑的解除方式永远是读代码,而不是问客服。 闭源软件没法读,但可以观察它的网络行为(防火墙/抓包)、数据目录变化、定时任务;开源或半开源软件(源码可得)则可以直接审查。本站博客虽然是 Pro 版,但程序文件完整可得,这才有了这次审查;
- 付费是对可持续的投票。 免费版把功能做到这个程度,开发者的诚意是看得见的。50 篇上限对个人博客其实不算小气——多数人写几年也到不了。但如果你打算长期写、重度用,注册正版既是对开发者的支持,也让自己不再惦记那个黄灯;
- 把「未注册」写进运维清单。 这次审查的结论已经沉淀进站点的运维文档:未注册状态的限制与绕过方式、触发条件、以及未来接入 API 发文通道时的注意事项,都记录在案。以后无论谁接手这个站,都不用重新翻一遍代码。
一次演练:把三件工具串起来
讲了这么多原理,不如看一次实战。9 月初,本站做了一次完整的灾难恢复演练,sha256、GPG、以及「备份体系的正确性」在这条链路里各司其职,正好可以作为全文的收束案例。
演练的设定是「假设服务器整机不可用」:在一台本地虚拟机里,从 Gitee 备份仓库把整站 1:1 还原出来——数据库、站点代码、配置、数据目录,全部恢复到与线上一致的状态,连域名都解析到本地。这样做的目的,是验证一个残酷的问题:如果明天服务器没了,我们能不能凭备份把站重新撑起来?
还原的流程,每一步都踩在本文讲过的工具上:
第一步,拉取备份。从 Gitee 仓库 clone 加密备份包。仓库里躺着的是一堆 .gpg 结尾的密文——它们就是「信封」,在仓库里放多久都不怕人看。
第二步,GPG 解密。用服务器上保存的口令逐个解开。到这一步,如果口令文件丢了,演练当场就会失败——所以口令的保管,和备份本身同等重要。
第三步,sha256 校验。解出的数据包与备份时记录的哈希逐一比对。这一步验证的是「这份数据在仓库里躺了这些天,有没有缺胳膊少腿」。
第四步,还原数据。数据库导入、站点文件落位、数据目录恢复、权限修正。本站的站点程序走「源码仓 + 发布目录符号链接 + 独立数据目录」的结构,程序本体可以从源码仓随时重建,真正的持久数据只有数据库和数据目录——备份与还原都围绕这个认知展开,结构清晰,恢复就快。
第五步,验证。站点起来之后,页面、后台、接口逐个过一遍;为了区分演练环境与线上环境,还给演练机的页面加了红色徽标、线上加绿色徽标——谁响应页面谁盖章,一眼分清自己在哪台机器上操作。这一步治的是另一个真实的恐惧:不是怕恢复不了,而是怕恢复好了,却把演练环境当成线上环境一顿操作,那比恢复失败更糟。
演练中还踩到过一个典型的坑:站点程序通过发布系统部署后,如果只切换了程序目录而不重启 PHP 进程,PHP 会因缓存继续执行旧代码,造成「部署了但没生效」的假象。这类坑在演练环境里踩一次,记进手册,线上就再也不会踩第二次——演练的真正价值,是让错误发生在演习场,而不是战场。
值得一提的还有这次演练的「副产品」:服务器 AI 助手 8 月上旬的工作记忆,正是顺着这条「加密打包 → 仓库 → 解密 → 校验」的链路,被完整导入到本地助手的记忆库。备份体系原本为灾难恢复而设计,结果还客串了一把「记忆迁移」——数据链路只要可靠,能运的东西比想象中多。
常见误区 Q&A
最后整理几个关于哈希与加密的高频误区,每一条都是真实踩过或见过别人踩的:
「文件哈希一致,就说明文件安全。」 不对。哈希只证明文件与官方发布的一致,但如果发布源本身被攻破、或者校验通道被劫持,攻击者可以改完文件重算哈希,校验照样通过。严肃场景必须叠加签名(验明发布者身份),哈希+签名才是完整姿势。
「放私有仓库/私有云盘,数据就安全了。」 不对。平台侧风险(账号被盗、误设公开、内部越权、服务器被拖库)不在你掌控中。数据本体加密,才是把安全掌握在自己手里的唯一方式——这也是本文反复强调「先加密再上传」的原因。
「数据加密了,就不用备份了。」 恰恰相反。加密保护机密性,备份保护可用性,两者解决的是完全不同的问题。硬盘损坏不会因为文件是密文就不坏;勒索软件加密你的文件时,也不会因为你的文件本来就是密文就手下留情。正确的顺序是:先有可靠备份,再给备份加密。
「SHA-256 可以用来存用户密码。」 不建议。SHA-256 太快,GPU 集群每秒可尝试数十亿次,弱密码瞬间被破;彩虹表更是让无盐哈希形同虚设。存密码请用 argon2、bcrypt、scrypt 这类刻意慢的算法,并给每个用户加独立随机盐。
「哈希就是加密。」 不是。加密是可逆的(有密钥就能还原),哈希是不可逆的(单向)。哈希是「指纹」,加密是「信封」,用途完全不同,不能互相替代。
「对称加密不如非对称加密安全。」 不对。安全性与算法类型无关,取决于密钥长度与使用是否得当:256 位 AES 与 3072 位 RSA 目前都被认为足够安全。实际系统普遍混合使用两者——非对称传密钥、对称传数据,各取所长。
「GPG 是命令行老古董,普通人用不上。」 其实它就在你身边:Linux 系统每次 apt 安装软件都在用 GPG 验签;邮件客户端加密插件基于它;Git 提交签名也是它。命令行只是它的其中一副面孔。
「未注册的软件一定会偷偷删数据/留后门。」 不能一概而论,但「担忧」可以用方法代替:能读代码的读代码,不能读代码的观察网络行为与文件变化。本文对 emlog 的审查就是一个例子——结论不是猜出来的,是逐行读出来的。
「哈希越长越安全。」 不严谨。安全性取决于算法本身与具体用途,而不是单纯的输出长度:MD5 输出 128 位,早已被碰撞攻击击穿;SHA-1 输出 160 位,同样宣告退役;而 SHA-256 的 256 位至今坚挺。同为 256 位,一个设计良好的算法与一个有缺陷的算法,安全强度可以天差地别。选算法时,优先相信经过长期公开检验的主流选择,而不是盯着位数。
「公钥加密就是数字签名。」 两者用的都是密钥对,但语义完全不同:加密是用你的公钥锁数据,只有你的私钥能开,目的是保密;签名是用你的私钥盖戳,所有人用你的公钥验证,目的是防伪与不可否认——证明这份文件确实出自你手、且之后没人动过。一个把门锁上,一个把章盖上,方向正好相反。
「备份加密该用对称还是非对称?」 看场景:自己备份自己恢复,对称加密(GPG 口令模式)最简单可靠,口令管好即可;需要把加密数据分发给多方、或多人各自加密后汇总,非对称更合适——用对方的公钥加密,不需要共享任何秘密。本站备份属于前者,一条口令走到底;如果将来要跨机器、跨协作者传递备份,再引入密钥对不迟。
小结
一串指纹保完整,一个信封保机密,一次演练保可用,一次源码审查换安心。
工具本身都不复杂——sha256 一行命令,GPG 五个常用操作,审查不过是搜索加精读。复杂的是愿意在出事之前多想一步:备份之前先想恢复,上传之前先想泄露,使用闭源功能之前先想它会做什么。数字世界的安全感,从来不是某个工具给的,而是一整套「把最坏情况想好」的习惯给的。
(附:本文所有结论均基于 2026-09-07 对 emlog Pro 2.6.25 源码的审查与本站备份体系的实际配置,如版本更新导致行为变化,以最新源码为准。)
如果你只带走一句话,那就是:给数据按上指纹(哈希),装进信封(加密),提前演习过最坏情况(演练),再对不放心的软件读一遍源码(审查)——这四件事做完,夜里能睡踏实很多。