逆向工程专业摄影平台水印技术

本文详细分析了专业摄影平台的水印实现机制,通过Base64解码和参数操控揭示了客户端控制水印显示的设计漏洞,并探讨了更安全的服务器端验证方案。

逆向工程专业摄影平台的水印

专业摄影师通常会在图片上添加水印,以便识别、标明版权、推广品牌等。在线图库商店常采用多种措施防止图片被盗,例如禁用JavaScript右键菜单、堆叠/覆盖DOM元素或其他混淆尝试。

当我收到家庭照片时,注意到摄影师使用平台的水印,并对它的工作原理产生了兴趣。立即想到两种可能:

  1. 生成离散的图像资源并输出到文件系统,然后由网络服务器直接在画廊中提供
  2. 使用服务器端处理动态生成带有叠加水印的新图像

深入分析

虽然不会直接指明具体网站,但让我们仔细查看画廊的示例标记:

1
2
3
<a class="thumb-image">
   <div style="background-image: url(&quot;https://example.com/image/eyJmZWF0dXJlZF9pbWFnZSI6ZmFsc2UsInNpemUiOiJtZWRpdW0iLCJ1dWlkIjoiMzk5NDg5MWUtNGQ2Yy0xMWVkLTk5NTItZmExNjNlOWMiLCJjcm9wIjoiZmFsc2UiLCJub19jcm9wIjoidHJ1ZSIsInYiOiIxNjY1OTM2MjczIiwid2F0ZXJtYXJrIjoxNjY1OTM3MTQ1LCJ0aHVtYiI6dHJ1ZX0=&quot;);" class="img-tag" data-id="81393248"></div>
</a>

这里通常期望使用img标签而不是带有背景图像的div,但有趣的是路径不以图像扩展名(如.png)结尾。

完整URL:https://example.com/image/eyJmZWF0dXJlZF9pbWFnZSI6ZmFsc2UsInNpemUiOiJtZWRpdW0iLCJ1dWlkIjoiMzk5NDg5MWUtNGQ2Yy0xMWVkLTk5NTItZmExNjNlOWMiLCJjcm9wIjoiZmFsc2UiLCJub19jcm9wIjoidHJ1ZSIsInYiOiIxNjY1OTM2MjczIiwid2F0ZXJtYXJrIjoxNjY1OTM3MTQ1LCJ0aHVtYiI6dHJ1ZX0=

对于有经验的人来说,路径参数立即显现为可能的Base64编码字符串。解码后确认:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
	"featured_image": false,
	"size": "medium",
	"uuid": "3994891e-4d6c-11ed-9952-fa163e9c",
	"crop": "false",
	"no_crop": "true",
	"v": "1665936273",
	"watermark": 1665937145,
	"thumb": true
}

这里有许多有趣的用户控制参数。为了确认它们可以被修改并被后端接受,我将size值编辑为"small"并重新编码:

1
2
3
[rw ~]$ JSON='{"featured_image":false,"size":"small","uuid":"3994891e-4d6c-11ed-9952-fa163e9c","crop":"false","no_crop":"true","v":"1665936273","watermark":1665937145,"thumb":true}'
[rw ~]$ echo -n $JSON | base64 -w 0
eyJmZWF0dXJlZF9pbWFnZSI6ZmFsc2UsInNpemUiOiJzbWFsbCIsInV1aWQiOiIzOTk0ODkxZS00ZDZjLTExZWQtOTk1Mi1mYTE2M2U5YyIsImNyb3AiOiJmYWxzZSIsIm5vX2Nyb3AiOiJ0cnVlIiwidiI6IjE2NjU5MzYyNzMiLCJ3YXRlcm1hcmsiOjE2NjU5MzcxNDUsInRodW1iIjp0cnVlfQ==

在路径中替换这个新编码的参数确实显示了较小的图像。接下来,我好奇是否支持来自客户端的任何额外参数——更具体地说,我想知道水印行为是否也是用户控制的。我在JavaScript源代码中搜索featured_image的提及,并找到了有用的结果:

1
2
3
4
5
6
featured_image_encoded = btoa(JSON.stringify({
    uuid: self.featured_image.uuid,
    width: 150,
    featured_image: true,
    ignore_watermark: true,
}));

这证实了我的怀疑——所有关于图像处理的控件,包括水印本身,都是由客户端指定的。

让我们在原始URL上添加ignore_watermark键,值设为true:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
	"featured_image": false,
	"size": "medium",
	"uuid": "3994891e-4d6c-11ed-9952-fa163e9c",
	"crop": "false",
	"no_crop": "true",
	"v": "1665936273",
	"watermark": 1665937145,
	"thumb": true,
	"ignore_watermark": true
}

重新编码为Base64并发出请求后,服务器成功响应了干净版本的图像。

替代方法

最终,我已经支付了照片费用并直接从摄影师那里收到了原件。我出于好奇偶然发现了这一点,不禁注意到平台对摄影师的保护存在根本性的设计缺陷。

更好的方法可能是让后端决定在哪些条件下可以显示原始照片。如果绝对需要客户端方法(可能由于使用单独的微服务进行资源生成),签名JWT将是确保客户端请求合法的更好选择。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计