G.O.S.S.I.P 阅读推荐 2026-10-15 真假二维码
原创 GUESS@ENCU 2026-10-15 21:06 上海

神仙也难分辨真假美猴王,真假二维码你能识别吗

上面这张二维码图片,大家试试看,注意不要长按屏幕然后“识别二维码”,直接用微信的扫码功能解析一下看看是什么结果。然后,你在离二维码更远的位置(比如1米开外)再扫描,看看结果还一样吗?
这个奇怪的二维码(可能有些读者已经注意到了它里面的一些纹理图案)就是USENIX Security 2026的研究论文 What You Decode Depends on Where You Stand: Distance-Based Optical QR Code 揭示的奇异现象:在不同的位置扫描同一个二维码图案,会得到不一样的扫码结果,这简直是黑产狂喜的发现,让我们一同来阅读论文,寻找真相:

我们都假设同一张二维码,无论由检测系统还是用户手机扫描,无论用户扫码位置的远近,都只能解码出同样的内容。而本文介绍的 Optical Quick Response(OQR,光学二维码),在不同距离出能被扫描出不同的结果,例如下面这些二维码,你可以试试在不同的位置扫码,看是不是能得到不同的结果(“Moon”或者“Sun”,“Reduce”或者“Reuse”或者“Recycle”):

在揭示原理之前,我们要提一下二维码领域的一些增加二维码信息量的研究工作,例如彩色二维码,在使用不同的颜色(而非单纯的黑白)时,相同的图案能够表示更多的信息(当然这需要定制解码器来处理)。还有图案二维码,通过在标准二维码的二值模块中嵌入特殊黑白图案,能够编码次级信息,同时不影响标准二维码解码器对基础二维码的解码

搞安全研究的家伙,思路可能就是和别人不一样,大家想的是如何给二维码里面编码更多的信息,而安全研究人员想的是“如果二维码里面编码了更多的信息,有没有可能出错?”这就是本文的研究出发点!首先我们回顾一下二维码的标准解码过程,它包括以下步骤:
- 定位(Localization):
识别定位图案,确定二维码
- 透视变换(Perspective Transformation):
补偿由观看角度或表面不规则造成的畸变
- 网格划分(Grid Division):
将变换后的二维码划分为数据模块,每个数据模块在设计上是纯黑或者纯白的
- 确定每个模块的颜色(Determine color for each Module):
将变换后的图像转换为灰度图,并可能进行降噪处理。随后,解码器确定每个模块的颜色。模块颜色通过采样模块中心区域的像素,或对模块内中心附近的像素取平均来确定。最后,二值化算法依据采样值将每个模块归类为黑色或白色
- 解码:二值化之后,按照二维码标准提取原始二进制数据,利用掩码信息去除掩码,并使用纠错技术
恢复丢失或失真的数据。最后,依据编码模式(数字、字母数字、字节或汉字模式)对提取的二进制数据进行解码,并转换为可读信息
纠错,例如三次重复码(实际上二维码用的是Reed–Solomon 纠错码)
而本文提出的OQR,其构造的原理是这样的:我们知道一个标准二维码包含很多个模块,每个模块有一个唯一的颜色(例如黑或白),标准二维码的解码器通过采样模块中心区域的像素,或对模块内中心附近的像素取平均来确定每个模块的颜色。再利用二值化算法依据采样值将每个模块归类为黑色或白色(以黑白二维码为例)。而OQR中包含的新型模块,在这些模块中嵌入了新型光学图案。这些图案经过专门设计,利用相机镜头系统固有的分辨率限制,使其视觉表现随扫描距离改变(如下图所示):


实际上,可以设计出在不同距离处呈现三种甚至更多扫描结果的OQR:


这背后其实是我们这个物理世界的一些特性(嗯,可以用这个方法来检测你是否在盗梦空间中),物理学的瑞利判据(Rayleigh criterion) 解释了为什么二维码中的细小结构会随着扫描距离增大而变得不可分辨:当一个点光源形成的艾里衍射图样的中央主极大,恰好与另一个点光源形成的艾里衍射图样的第一极小重合时,认为这两个点“刚好可以分辨”。换言之,一个光斑的亮斑中心恰好落在另一个光斑的第一圈暗环上,就是“刚好能分清两个点”的界限:

当光线通过相机镜头等圆形孔径时,形成的不是理想点像,而是艾里衍射图样(Airy diffraction pattern)。该图样由中心亮斑及其周围的同心环组成。只有当两个相邻点的艾里图样充分分离时,才能分辨这两个点。
瑞利判据(Rayleigh criterion)的标准表述:当一个点光源的艾里衍射图样的中央主极大,恰好与另一个点光源的艾里衍射图样的第一极小重合时,认为这两个点光源“刚好可以分辨”。通俗来说,一个光斑的亮斑中心恰好落在另一个光斑的第一圈暗环上,就是“刚好能分清两个点”的界限 。瑞利判据说明,光源的无法分辨,并不只因为相机质量问题,而是由光的波动性引起的物理限制;即便是理想镜头,也无法突破衍射施加的这一边界。
拍照距离增大 → 拍照位置与两个点光源的夹角变小 → 两个光斑靠近 → 一个光斑的亮斑中心落在另一个光斑的第一圈暗环之内 → 小于“刚好能分清两个点光源”的界限 → 两个点光源“重合” → 点光源之间的暗区域逐渐模糊 → 模块中心的黑白判断改变 → 解码出另一条消息
二维码图案的实际尺寸不变,但扫码位置越远,终有一刻,两个点光源会逐渐靠近并重叠,点光源之间的暗区域逐渐模糊,从而使模块呈现不同的黑白结果。

也就是说,二维码图案的实际尺寸不变,但扫码位置越远,细小结构在镜头看来所占的角度越小。当这些细节低于相机的分辨能力时,就会逐渐混在一起,从而使模块呈现不同的黑白结果。
在具备了这样的“混淆”能力之后,我们就可以构造OQR了,实际上这是一个将不同的内容(比如三张标准的二维码)叠加在一起,然后用OQR中包含的新型模块特征来表征任意一个叠加的信息,可以证明,任何一种叠加的信息组合都可以找到一个特定的新型模块与之对应,因此我们可以在一个OQR图案中包含任意不同的信息的叠加组合!

具体的生成步骤可以描述为:
输入数据与分层二维码生成
每个数据层创建一个独立的标准二维码
二维码叠放
将两个(或三个)二维码按**特定顺序叠放:**用于远距离扫描的置于底部,用于近距离扫描的置于顶部
利用光学图案模块合并


在这种情况下,每当攻击者生成了一个OQR,扫码的人在离得最近的时候(或者那种手机上直接识别二维码图片的操作),能读到的是这个OQR“最内层”的光学图案,这个最内层的内容可以包含正常内容,例如合法 URL。而攻击者可以把包含恶意载荷(例如钓鱼 URL、恶意软件分发端点或含恶意Web代码的页面)的信息编码到其他层,如果用户在比较远的地方扫码,就会获取到恶意的信息,而且因为目前的大部分针对二维码的自动化检查系统只评估最内层内容,而不会去评估那种“站在远处扫码”的情况,因此就往往会忽略了恶意的内容。
在实际的实验中,作者测试了
- 6 款手机:Samsung Galaxy S25 Ultra 5G、OnePlus 15R、Motorola Edge 60 Fusion、Samsung Galaxy S23、iPhone 16、iPhone 17 Pro
- 两款手机扫码应用:QR & Barcode Reader、Paytm
- 纸质样本:Canon PIXMA MegaTank G6070 打印机,600 DPI 打印
- 数字样本:Apple MacBook M3 Pro,254 PPI 显示
- 软件解码器:ZXing-C++、QReader;中值模糊处理使用 OpenCV
其中最重要的实验当然是验证拿普通手机、常见扫码软件来扫OQR,能否在不同距离读出预先设定的不同内容?作者生成了一堆OQR,然后定义了Code Decodability Rate(CDR)这样一个指标,也就是 成功解码的样本数 / 样本总数,经过测试发现,不管手机如何、OQR是纸质还是数字展示,两款手机扫码应用 QR & Barcode Reader 和 Paytm 在大部分情况下都会在不同距离下解析出不同的结果,充分展示了OQR这种二维码的安全威胁!

论文:https://www.usenix.org/system/files/usenixsecurity26-garg-pulkit.pdf
本文转载自微信公众号「安全研究GoSSIP」,查看原文。版权归原作者所有,如有侵权请联系删除。