周日晚上十点,阿杰的公众号自动化就差最后一步:封面图自动上传。
他翻遍了媒体库页面,连一个 input[type=file] 都没找到。整个上传区就是一块虚线框,上面一行小字:把图片拖到这里。
阿杰不慌。cda 有 upload_dragdrop,专门收拾这种只认拖拽的组件——派发 dragenter、dragover、drop,把文件塞进 dataTransfer,页面自己的 drop 处理器接手上传。他上周刚用过,一次成功。
这次他敲了命令,返回 success。页面上那个虚线框闪了一下,进度条跳出来又缩回去。
然后,没了。
图没上去。
阿杰盯着屏幕看了十秒,重跑。虚线框再闪一下,进度条再跳一次,图还是没上去。第三遍的时候他已经在 console 里埋好了日志——drop 处理器明明执行了,文件也在 dataTransfer.files 里躺着,可页面的上传逻辑就是装死。
他顺着断点往里翻,最后停在一行判断上:
if (!event.isTrusted) return;
event.isTrusted: false。
阿杰瞬间不困了,但也更糊涂了:事件是他发的,处理器也跑了,就差这一个布尔值,卡死了整个流程。
第二天早上,老陈端着咖啡路过,看见阿杰的黑眼圈,瞥了一眼屏幕上的断点。
「你在跟浏览器的信任体系较劲。」老陈说,「事件是有出身的。人手拖出来的,isTrusted 是 true,浏览器盖章认证;代码 dispatchEvent 合成的,永远是 false——不管你模拟得多像。」
「那我模拟得再像也没用?」
「没用。isTrusted 是只读属性,脚本改不了,这是浏览器的防伪设计。微信媒体库这类组件就查户口:你的 drop 处理器跑得再欢,出身不对,不收货。」老陈拉开椅子坐下,「这叫反自动化校验,拦的就是你这种脚本。」
「那怎么办,我雇个人肉拖图?」
「让浏览器替你拖。」老陈放下咖啡,「cda 前两天升到 v0.26.0,upload_dragdrop 加了 trusted 模式。它不走 dispatchEvent,走 CDP——浏览器调试协议。你等于站到浏览器里面去下指令:Chrome 自己读盘,构造一个真实的 File,用浏览器级输入完成整个拖放。」
「isTrusted 呢?」
「浏览器自己动手,章自然是真的。」
阿杰半信半疑,改了命令。之前是这么写的:
# 合成拖放:派发 dragenter/dragover/drop,处理器会跑,但 isTrusted=false
upload_dragdrop current '{"selector":".upload-area","data":{"base64":"<b64>","filename":"cover.jpg","mime":"image/jpeg"}}'
现在只改了两处——加 trusted: true,data 从 base64 换成本机路径:
# 真实拖放(v0.26.0):浏览器读盘构造真实 File,isTrusted=true
upload_dragdrop current '{"selector":".upload-area","trusted":true,"data":{"path":"/Users/jay/Pictures/cover.jpg"}}'
回车。返回里多了一个字段:
{
"success": true,
"data": {
"selector": ".upload-area",
"filename": "cover.jpg",
"x": 642,
"y": 318,
"trusted": true,
"settledMs": 806
}
}
trusted: true。
这一次,媒体库的缩略图安安静静地出现了。没有闪动,没有抗议,就像有人亲手拖进去的一样。
阿杰靠在椅背上,把这次升级跟之前的方案摆在一起,发现了几个「不一样」:
- 出身变了,不是演技变了。 合成事件是「让页面以为有人拖」,trusted 拖放是「让浏览器替你拖」。
isTrusted=true是浏览器亲手盖的章,脚本伪造不出来——但可以请浏览器自己盖。 - 文件是真的。
dataTransfer.files里是真 File,大小、类型、内容都对,任何一层校验都挑不出毛病。 - 细节也顺手补了。 旧的合成路径加了
dragleave收尾,拖完不再留下「亮灯」残留——就是那种高亮框悬在页面上死活不消失的尴尬。 - 上传三件套凑齐了。 找得到
input[type=file]用upload_file;只有拖拽区用upload_dragdrop合成路径;查出身的组件上trusted: true。三种武器,对应三级防御。 - 前提只有一条。 文件得在跑 Chrome 的那台机器上——毕竟是 Chrome 自己读盘。
阿杰忽然想明白一件事:以前他以为自动化是把人的动作「翻译」给页面,一层事件一层事件地模仿。现在才明白,最高效的路是让浏览器自己动手——它本来就是执行者,何必隔着一层合成事件去冒充人。
老陈喝完最后一口咖啡,站起来留下一句话:
「反自动化的本质是信任问题。你伪造不了浏览器的章,但可以让浏览器亲手盖章。」
cda 的 README 里有 upload_dragdrop 的完整参数表:合成路径(base64 / URL 拉取)和真实拖放(trusted + 本机路径)三种写法都在。下一个卡住你自动化的上传组件,可能就差一个 trusted: true。