窗外又飘起雨,路灯把湿漉漉的柏油路面照得发亮。我坐在书桌前,屏幕上是 Charles 那个熟悉的灰色界面。32 岁了,还在干这种事。但没办法,好奇心像猫爪子一样挠着。满大街的橙色、黄色单车,它们到底是怎么被调度的?那些 App 轻轻一点,车锁就开了,背后的数据流是不是真的那么坚不可摧?
我给自己泡了杯浓茶,打开手机,连上电脑设置的代理。SSL 证书?装。信任设置?调。这一套流程早就烂熟于心,但每次做,手指尖还是有点发麻,像在准备拆一个不知道会不会炸的礼物。
App 启动了,地图加载出来,密密麻麻的单车图标。我点开一辆,请求开始像瀑布一样在 Charles 里刷出来。过滤,只看目标域名。然后,我看到了。一个毫不起眼的 POST 请求,响应体是明晃晃的 JSON。点开,格式化。经纬度、车辆编号、状态、甚至……电池电量?全都躺在那里,没加密,没混淆,就像超市货架上的商品一样摆着。
我愣了几秒,把茶喝下去,喉咙有点干。估值百亿的公司,接口做成这样?
这太……直接了。我拖动滚动条,仔细看那些字段。lat,lng,这是标准的 WGS-84 坐标吧。但国内地图为了合规,普遍要用 GCJ-02 火星坐标或者 BD-09 百度坐标进行偏移。他们是在客户端偏移,还是服务端直接返回了偏移后的值?我随手写了几行 Python,把抓到的经纬度丢进一个开源的坐标转换库试了试。果然,是已经处理过的 GCJ-02。这意味着,如果我想,我完全可以用脚本批量抓取这个接口,拿到这座城市里几乎所有单车的实时位置。
这念头让我后背一凉,又有点莫名的兴奋。这是黑客情结吗?不,我只是个焦虑的产品经理,想看看那些跑在前面的家伙,铠甲下面到底是什么质地。
我继续翻看其他请求。用户认证的 token,居然就放在一个叫 “access-token” 的 header 里,有效期长得吓人。附近的车辆列表接口,连个像样的频率限制都没有,我手动刷新几下,数据就哗哗地回来。我甚至尝试模拟了一个开锁请求,把抓到的参数原封不动地重放了一次。Charles 里显示 “200 OK”。当然,我没真去开一辆车,但那瞬间的“可能性”让我心跳都漏了一拍。
这不仅仅是技术问题。我靠在椅背上,盯着屏幕上流动的数据。这是商业逻辑的裸奔。他们的调度系统核心,就这么暴露在 HTTP 的明文传输里(尽管用了 HTTPS,但在我这里就是明文)。竞争对手如果有点心思,是不是能轻易摸清他们的车辆分布热力图?甚至,恶意攻击者呢?不需要多高深的技术,一个会用抓包工具的中学生,就能窥见这座移动帝国地基上的裂缝。
数据抓取的威力,从来不在工具本身有多高级,而在于你看到了别人视而不见的东西。
我突然觉得有点疲惫,也有一点悲哀。我们都在狂奔,追逐流量,追逐闭环,追逐估值。代码拼命地写,功能拼命地上。可最基本的数据安全交互逻辑,却像纸糊的一样。这是风口上的通病吗?还是说,速度太快了,有些东西注定要被甩在后面?
雨好像下大了,敲在玻璃上噼啪作响。我关掉 Charles,清除了代理设置。手机屏幕暗下去,恢复成一个普通的夜晚。那些流动的经纬度、token、状态码,都消失了。但它们在我脑子里留下了印记。一种冰冷的、关于真实世界的印记。
玩点野的,看到了野路子下的真实。然后呢?
然后我得更拼命地学。因为我知道,如果我不够“野”,下一个被轻易看穿的,可能就是我亲手做的东西。这种焦虑,比雨水还冷,丝丝缕缕渗进来。但今晚,至少我看到了。














