尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

用OG images证明文章非AI生成:签名、校验、二维码全攻略

用OG images证明文章非AI生成:签名、校验、二维码全攻略 最近越来越多的平台和个人开始问同一个问题你怎么证明这篇文章是人写的这个系列就是专门折腾这个问题的。系列名叫Going out of my way to prove Im not an AI第 1 期只盯一个东西OG images也就是社交分享卡片里的那张预览图。为什么选 OG images 当突破口因为它是内容对外展示的“门面”。公众号文章、博客页面、产品链接被分享到微信、X、LinkedIn 时平台会去抓页面里的 Open Graph 标签然后渲染出一张缩略图。这张图里既可以放标题、作者、发布时间也可以塞进签名、二维码、校验信息让阅读者扫码之后跳转到一个可验证的页面确认“这段内容确实来自这个作者、这个时间点、没有被 AI 改写”。也就是说OG image 不只承担美观功能它还能变成一种轻量级的内容归属标记。本文会完整走一遍这条链路先讲 OG image 的基础协议和配置方式再提供一个可落地的 Python 生成脚本把作者信息、SHA256 校验值、RSA 签名和验证二维码一次性画进 1200×630 的预览图里然后给出 Node 服务的实时生成方案、批量处理思路、接口调用示例以及部署后常见的缓存和抓取问题排查。适合阅读这篇文章的读者有三类写技术博客想给文章加“作者标识”的开发者做内容站、SaaS 工具需要用程序批量生成分享图的运营或后端以及看到 AI 生成内容泛滥想给原创内容增加一层可验证信息的创作者。下面直接进入正题。1. OG images 核心能力速览在开始部署前先用一张表把 OG images 方案的规格说清楚。这里说的不是某个需要下载的整合包而是一套基于 Open Graph 协议的工程方案。能力项说明项目类型内容标识与社交分享图生成方案核心功能为网页配置 Open Graph 标签生成带作者签名、校验值、二维码的分享预览图推荐硬件CPU 即可不需要 GPU不涉及模型推理显存显存占用0纯图片合成与哈希签名支持平台所有支持 Open Graph 抓取的社交平台、搜索平台、IM 工具启动方式静态图片脚本 / Web 服务路由 / 纯前端生成是否支持 API支持可单独起一个 OG image 服务接口是否支持批量任务支持按文章目录批量生成或按队列异步生成是否支持 50 系显卡无关不需要显卡主要依赖Python Pillow、cryptography、qrcode或 Node canvas / sharp适合场景原创博客、新闻站点、内容分发、产品分享落地页这里要重点强调一点OG images 方案解决的是“可验证的内容归属展示”不是“AI 内容检测”。它不是给 AI 生成内容打标而是让人类创作者在分享内容时多一个能被读者主动核验的入口。AI 检测工具存在大量误判靠一张图“免疫检测”不现实但通过签名和二维码让读者确认“内容确实由作者本人处理过”是可行的。2. 适用场景与使用边界先说什么场景适合这套方案。第一个人博客作者。每次发文章时自动生成一张带作者签名的 OG 图读者看到分享卡片的第一眼就能知道这是原创作者的站点内容而不是搬运号。第二内容平台和 SaaS 工具。平台需要为每个用户文章动态生成不同的分享预览图可以在服务端加一个/og-image接口按 URL 参数实时渲染。第三团队协作场景。技术团队发布版本公告、产品文案时在 OG 图里嵌入内部编号和发布时间方便对外追踪分发链路。不适合什么场景也要说清楚。如果目的是对抗司法取证或者合同纠纷那么一张 OG 图片上的签名和二维码只能说明“作者发布过这个内容”不能替代权威的电子存证服务。如果内容本身涉及人脸、他人声音、版权素材那么 OG 图里嵌入这些元素之前必须先拿到明确授权否则分享越广侵权风险越大。还有一个边界容易忽略OG image 不是内容防篡改的绝对保证。二维码里的校验值和签名只能证明“这段描述在生成图片的那一刻经过了作者私钥签名”不能阻止别人截取图片后重新配文发布。也就是说它提升了可追溯性但不能杜绝低成本的“截图式搬运”。这也是为什么建议把验证页面做成公开可访问的并让验证接口同时返回原文摘要和发布时间而不只是返回“验证通过”四个字。3. 环境准备与前置条件这套方案的部署成本很低但依赖项要做到心里有数。我建议在正式使用前先准备好四类东西运行环境、图片渲染依赖、网页配置入口、外部验证通道。3.1 运行环境推荐 Python 3.9 及以上版本或者 Node.js 18 及以上版本。两者都能完成同一件事选择哪个取决于你平时的技术栈。如果你更熟 Python用 Pillow 画图如果团队已有前端服务用 Node 的 canvas 或 sharp 更顺手。当前文档里的命令默认以 Python 为例Node 示例会单独给出。3.2 Python 依赖在终端执行pip install pillow cryptography qrcode[pil]三个库的分工很明确Pillow 负责绘制 1200×630 的底图、文字和布局cryptography 负责生成 RSA 密钥对、对文章信息做签名qrcode 负责把验证信息编码成二维码图片。qrcode 的 PIL 插件依赖 Pillow所以要一起安装。如果你不想装 cryptography可以退一步用 SHA256 哈希作为简化版校验。但要注意哈希只能防意外损坏不能防恶意篡改因为攻击者可以重新计算哈希。签名方案虽然多了一个密钥管理的步骤但安全性高很多。3.3 中文字体OG 图里通常要展示中文标题和作者名所以必须指定一个系统里存在的中文字体文件。Windows 常见路径是C:/Windows/Fonts/msyh.ttc微软雅黑macOS 常见路径是/System/Library/Fonts/PingFang.ttc苹方或/System/Library/Fonts/Helvetica.ttcLinux 常见路径是/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf。代码里最好写一个自动探测逻辑避免换机器就乱码。3.4 可公网访问的验证页社交平台抓取 OG 标签时要求图片 URL 是公网可访问的 HTTPS 地址。如果你只想做本地效果验证可以用curl模拟抓取但如果要真正发布到微信、X、LinkedIn必须有一个域名和 HTTPS 证书。验证页面可以是一个最简单的静态页面也可以走服务端接口。4. OG image 生成与部署启动方式这一节给出三种启动方式静态脚本、Web 服务、静态 HTML 模板。三种方式面向不同阶段前两种更适合生产。4.1 方式一静态 Python 脚本生成单张 OG 图这是最直接的方式。把文章信息写在一个 Python 字典里脚本会自动计算哈希、签名、二维码然后输出一张 PNG 图片。下面是一个可运行的参考实现# generate_og_image.py import hashlib import json from datetime import datetime, timezone from PIL import Image, ImageDraw, ImageFont import qrcode from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding, rsa # 文章基本信息 article { title: Going out of my way to prove Im not an AI - Ep. #1 - OG images, author: your_name, published_at: datetime.now(timezone.utc).isoformat(), url: https://example.com/posts/og-images, } # 按固定顺序序列化保证校验值稳定 raw_text json.dumps(article, ensure_asciiFalse, sort_keysTrue) digest hashlib.sha256(raw_text.encode(utf-8)).hexdigest() article[checksum] digest # 生成 RSA 密钥对。首次运行可以这样生成正式环境建议提前生成并妥善保存私钥 private_key rsa.generate_private_key(public_exponent65537, key_size2048) public_key private_key.public_key() # 对校验值签名 signature private_key.sign( digest.encode(utf-8), padding.PKCS1v15(), hashes.SHA256(), ) article[signature] signature.hex() # 生成验证二维码内容包含来源URL、校验值和签名 verify_payload { url: article[url], checksum: article[checksum], signature: article[signature], author: article[author], } qr qrcode.QRCode(version1, box_size6, border2) qr.add_data(json.dumps(verify_payload, ensure_asciiFalse)) qr.make(fitTrue) qr_img qr.make_image(fill_colorblack, back_colorwhite).convert(RGB) # 绘制 1200x630 OG 底图 canvas Image.new(RGB, (1200, 630), #1e1e1e) draw ImageDraw.Draw(canvas) def load_font(size): candidates [ C:/Windows/Fonts/msyh.ttc, /System/Library/Fonts/PingFang.ttc, /System/Library/Fonts/Helvetica.ttc, /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf, ] for path in candidates: try: return ImageFont.truetype(path, size) except OSError: continue return ImageFont.load_default() font_title load_font(42) font_text load_font(28) draw.text((80, 80), article[title][:60], fontfont_title, fillwhite) draw.text((80, 480), fAuthor: {article[author]}, fontfont_text, fill#cccccc) draw.text((80, 530), fTime: {article[published_at]}, fontfont_text, fill#cccccc) canvas.paste(qr_img, (940, 400)) canvas.save(og_image_v1.png, formatPNG) print(saved: og_image_v1.png) print(checksum:, digest) print(signature:, article[signature][:32] ...)运行方式很简单python generate_og_image.py脚本会生成一张og_image_v1.png同时打印出 checksum 和签名前缀。这张图里的二维码指向的信息可以在后续验证服务里用公钥重新验签。需要注意这段代码在字体路径上做了候选探测所以 Windows、macOS、Linux 都能找到一个可用字体但如果你的字体路径不在候选列表里需要自己补充。RSA 密钥对第一次运行是临时生成的生产环境不要这么做应该把私钥持久化保存只在签名时读取。4.2 方式二Node.js 实时 OG image 服务如果文章内容是动态的比如用户一提交就生成分享图那静态脚本就不够用了。可以起一个 HTTP 服务通过查询参数动态渲染 OG 图。下面用 Node 的 canvas 做示例// server.js const express require(express); const { createCanvas } require(canvas); const QRCode require(qrcode); const app express(); app.get(/og-image, async (req, res) { const width 1200; const height 630; const canvas createCanvas(width, height); const ctx canvas.getContext(2d); ctx.fillStyle #111; ctx.fillRect(0, 0, width, height); ctx.fillStyle #fff; ctx.font bold 48px Microsoft YaHei, PingFang SC, sans-serif; ctx.fillText(req.query.title || Default Title, 60, 120); const targetUrl req.query.url || https://example.com; const qrDataUrl await QRCode.toDataURL(targetUrl); const qrImage await canvas.loadImage(qrDataUrl); ctx.drawImage(qrImage, 920, 380, 220, 220); const buffer canvas.toBuffer(image/png); res.type(png).send(buffer); }); app.listen(3000, () { console.log(OG image service is running at http://127.0.0.1:3000); });启动命令npm install express canvas qrcode node server.js然后浏览器访问http://127.0.0.1:3000/og-image?titleHellourlhttps://example.com就能看到实时生成的图片。这个方案的优点是图片内容完全由 URL 参数决定可以很方便地接入到文章发布流程、CMS 系统或第三方工具里。要注意canvas这个 npm 包在安装时会尝试编译原生模块如果环境缺少编译工具链会失败。遇到这种问题可以用sharp替代或者部署到 Node 版本与预编译二进制匹配的容器里。4.3 方式三静态 HTML 配置无论用哪种方式生成图片最终都要把图片地址写进网页的 head 区域。一个最简的 Open Graph 配置是这样的head meta propertyog:title content我的非AI证明方案第1期OG images / meta propertyog:description content用Open Graph图片承载可验证的人类创作信息。 / meta propertyog:image contenthttps://your-domain.com/og-image?title...amp;url... / meta propertyog:type contentarticle / meta propertyog:url contenthttps://your-domain.com/posts/og-images / meta propertyog:image:width content1200 / meta propertyog:image:height content630 / /head这里的关键点是og:image必须是绝对地址不能写相对路径因为社交平台的抓取机器人不会知道“相对路径”指向哪个域名。如果使用 Node 服务直接把/og-image接口的完整地址填进去就行。5. 功能测试与效果验证部署完成不等于功能可用必须验证两个层面一是图片能否被正确渲染二是二维码里的签名能不能通过验签。5.1 本地检查 OG 标签先看页面 head 里是否正确输出了标签。可以在项目根目录执行curl -s https://your-domain.com/posts/og-images | grep -o meta propertyog:[^]* content[^]*如果返回结果包含og:title、og:description、og:image等标签说明 head 配置是通的。如果什么也没有优先检查模板文件是否被正确渲染或者 index.html 里是否真的写入了 meta 标签。5.2 验证签名链路服务端可以提供一个验签接口或者用本地脚本验证。下面是一个独立的 Python 验签脚本用来验证前面生成图片时打印的 signature# verify_signature.py import hashlib import json from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding, rsa from cryptography.hazmat.primitives import serialization # 公钥需要提前从私钥导出并安全发布到验证页 public_key_pem b-----BEGIN PUBLIC KEY----- ...你的公钥内容... -----END PUBLIC KEY----- public_key serialization.load_pem_public_key(public_key_pem) raw_text json.dumps({ title: Going out of my way to prove Im not an AI - Ep. #1 - OG images, author: your_name, published_at: 2025-01-01T00:00:0000:00, url: https://example.com/posts/og-images, }, ensure_asciiFalse, sort_keysTrue) digest hashlib.sha256(raw_text.encode(utf-8)).hexdigest().encode(utf-8) signature bytes.fromhex(...签名内容...) try: public_key.verify( signature, digest, padding.PKCS1v15(), hashes.SHA256(), ) print(签名验证通过) except Exception: print(签名验证失败)判断成功的标准是二维码里提取到的 url、checksum、signature 与原文信息能对应起来并且验签脚本输出“签名验证通过”。如果失败最常见的原因有三个序列化时字段顺序不一致、发布时间没有精确到秒、签名内容复制不完整。建议在生成图片时把raw_text也打印到日志里方便排查。5.3 社交平台调试工具验证在本地验证通过后还需要让社交平台真正抓取到最新图片。微信、X、LinkedIn 都有对应的调试入口。大致流程是把文章 URL 粘贴到调试工具点击“抓取/更新”后查看预览卡片。如果图片没更新通常是因为平台缓存了旧卡片需要使用调试工具强制刷新。预期结果是分享链接时卡片显示正常图片是 1200×630 且文字清晰、二维码可扫描。如果卡片显示旧图不急于重新生成先检查图片 URL 是否有变化。如果 URL 没变部分平台不会认为“图片变了”需要手动刷新缓存。6. 接口 API 与批量任务OG image 如果只做单张生成意义有限。真正的价值在于批量处理一个内容站每天发几十篇文章就需要程序自动遍历文章目录、逐篇生成分享图。6.1 批量生成脚本下面是一个 Python 批量示例它遍历articles文件夹下所有 JSON 文件为每篇文章生成独立 OG 图# batch_generate.py import json import os from pathlib import Path from generate_og_image import generate_for_article input_dir Path(articles) output_dir Path(outputs) output_dir.mkdir(exist_okTrue) for json_file in sorted(input_dir.glob(*.json)): with open(json_file, r, encodingutf-8) as f: article json.load(f) image_path output_dir / f{json_file.stem}.png generate_for_article(article, image_path) print(fgenerated: {image_path})这里的generate_for_article需要把上一节脚本里的绘图逻辑抽象成函数输入是文章字典输出是图片路径。批量执行时建议加日志记录每篇文章的 checksum方便后续追溯。6.2 接口调用示例如果走 Node 服务外部系统只需要 GET 请求就能拿到图片。一个通用调用示例如下curl -G \ --data-urlencode title批量生成测试 \ --data-urlencode urlhttps://example.com/posts/123 \ -o test_og.png \ http://127.0.0.1:3000/og-image也可以用 Python 请求import requests params { title: 我的非AI证明方案第1期OG images, url: https://example.com/posts/og-images, } response requests.get(http://127.0.0.1:3000/og-image, paramsparams, timeout30) if response.status_code 200: with open(remote_og.png, wb) as f: f.write(response.content) print(图片保存成功) else: print(请求失败:, response.status_code)6.3 批量任务设计建议当文章数量很大时直接在 HTTP 请求里同步渲染所有图片不是好选择渲染任务可能占用较长时间导致客户端超时。更稳妥的做法是引入一个任务队列接口收到请求后把任务写入 Redis 或数据库队列后台 Worker 逐个消费并渲染完成后通过回调通知前端。批量任务要特别关注三个指标并发数、失败重试、输出命名规则。并发数建议从 1 开始确认渲染端内存稳定后再逐步提高失败重试只重试超时或网络错误不要重试因为源数据缺失导致的任务输出文件建议使用文章 ID 加时间戳避免同名覆盖。7. 资源占用与性能观察这套方案不用 GPU也不涉及模型推理所以显存占用是 0。真正需要注意的是内存和文件大小。先说静态脚本方式。Pillow 生成一张 1200×630 的图片基础文字和色块绘制消耗的内存很小通常在几十 MB 以内运行时间主要取决于字体渲染和 PNG 压缩。如果文章的标题很长、需要绘制多行文本耗时会有少量增加但整体仍可以在秒级完成。因为是纯 CPU 任务生产环境可以放在任何常规服务器上。再说 Node 实时渲染方式。如果直接用canvas包每次请求都会创建一个 1200×630 的 canvas 对象内存开销可能会到几百 MB尤其是并发高的时候。优化思路有三个一是加一层图片缓存同一个 title 和 url 组合直接返回已生成的图片二是把图片输出格式改成 JPEG 或 WebP减少文件体积三是使用无头浏览器渲染 HTML 再截图时尽量复用浏览器实例不要每次请求都启动一个浏览器进程。如果使用 Playwright 或 Puppeteer 截图方式生成 OG 图内存占用会明显上升。这种方式在 4-8 个并发请求下就可能吃掉 1-2 GB 内存建议只在“页面模板复杂、CSS 布局要求高”的场景使用。纯文字和色块用 Pillow 或 canvas 就足够没必要上浏览器截图。从性能观察的角度建议在服务里记录两个时间指标图片渲染耗时和总接口耗时。渲染耗时稳定上升时优先检查字体加载和图片压缩尺寸总接口耗时异常时优先检查网络出口带宽和 CDN 缓存命中率。8. 常见问题与排查方法下面是这套方案里最常遇到的问题按现象、原因、排查方式、解决方案整理成表。问题现象可能原因排查方式解决方案社交平台分享时显示旧图片平台缓存了旧 OG Image复查图片 URL 是否变化使用平台调试工具强制刷新缓存分享卡片不显示图片og:image 不是 HTTPS 绝对地址检查 meta 标签内容改为完整的 HTTPS 图片地址图片里中文变成方块或乱码字体路径不存在或没有中文字体打印字体加载日志指定系统中文字体添加候选路径二维码扫描后内容为空二维码信息里含有特殊字符被截断检查二维码编码长度精简 payload使用 URL 短链验签失败序列化字段顺序或发布时间不一致对比生成时打印的 raw_text统一使用 sort_keys时间精确到秒npm install canvas 失败缺少原生编译工具链查看安装日志中的报错改用 sharp 替代或使用预编译环境批量生成一半卡住某个文章字段缺失或编码异常查看日志定位卡住的文件名增加 try/except 和失败计数图片文件过大PNG 压缩率低或尺寸过大查看输出文件大小改用 JPEG/WebP或降低导出比例接口请求超时同步渲染任务太多观察并发和耗时引入任务队列或加缓存其中最常见的其实是“平台缓存旧图”。很多人修改了 og:image 后重新分享发现还是旧图误以为生成代码有问题。实际上平台抓取机器人不会每次都重新抓取必须用各自的调试工具点击“抓取新信息”才能让分享卡片刷新。所以排查顺序建议是先 curl 确认页面元标签确实更新再去平台调试工具强制刷新最后才怀疑生成服务本身。9. 最佳实践与使用建议把 OG image 方案落地到生产环境有六条建议值得记住。第一第一次先小规模测试。不要一上来就批量生成几千张图先用 10 篇文章跑一遍检查标题长度、字体渲染、二维码清晰度确认输出稳定后再扩大规模。第二保留一套最小可运行配置。把generate_og_image.py和依赖列表整理成独立目录做到在新机器上两条命令就能恢复环境和运行方便排查问题时回退。第三模型素材和输出结果分目录管理。输入文章 JSON、生成的 PNG 图片、导出的公钥文件分别放在不同目录避免脚本误删或误覆盖。公钥文件要备份私钥更要严格保管。第四批量任务必须加日志和失败重试。每生成一张图就输出一行 JSON 日志记录文件名、checksum、耗时失败的任务不要无限重试设置最大重试次数。第五接口服务要限制访问范围。如果/og-image接口完全开放可能被其他人刷流量。建议在网关或服务里加一个简单的 Token 校验至少限制来源域名。第六涉及人脸、声音、版权素材时务必确认授权。OG 图会随链接被大量转发如果图中嵌入他人照片、录音、品牌 Logo没有授权就发布传播越广风险越高。这里还要特别强调不要使用本方案伪造他人身份或对内容做虚假归属签名验证体系只能保护真实作者不能为冒用行为提供便利。10. 总结与下一步这期内容把“证明不是 AI”这个大问题拆解成了一个可以落地的技术动作用 OG images 承载作者签名、校验值和二维码让每张分享卡片都自带一个可验证的身份入口。整套方案不需要 GPU不需要下载模型一个 Python 脚本或一个 Node 服务就能跑起来最值得先验证的是签名链路是否闭环也就是从生成图片、扫码提取信息到验签通过这三步是否能走通。最容易踩的坑有两个一是中文字体路径二是社交平台缓存旧图。前者会导致图片乱码后者会让你误以为生成服务没生效。建议把这两个问题提前写进上线检查清单。后续可以继续扩展的方向包括把签名密钥换成多作者体系每个作者独立密钥把二维码 payload 换成短链加上过期时间也可以把 OG image 生成接入到 CI/CD 流程中每次发布文章自动生成分享图。下一期可以做更深入的防 AI 误判标记方案但核心思路不变不要试图骗过检测器而是给内容建立一个能被验证的来源链条。收藏这份方案下次发文章时直接套用即可。
返回列表