前端不死水印的对抗方法 作者: Semesse 时间: 2022-06-24 分类: 千叶 评论 有时候企业不希望内网页面上的内容被截图泄漏出去,或者希望在事情闹大之后追踪到在产品上截图的员工 / 用户,这时候前端水印就派上用场了。使用纯前端添加的水印大抵有这么几种形式 - 明(文)水印 - 一类是非常直白的肉眼可见的水印,一般是为了警告用户这个页面包含敏感内容,不要截图分享 - 还有一些隐蔽性更强的水印,只会放在页面上部分关键区域,通过降低对比度隐藏自己,这种水印一般事后用于追溯  - 暗水印 - 前端使用的暗水印通常不是通过隐写的方式如 LSB、频域水印等,这样开销会比较大,此外也只能对单个图片生效,不能覆盖整个页面 - 一般使用非肉眼可辨识的图层重复覆盖整个页面,需要通过算法逆向提取出其中的水印内容,各家算法可能不一样 不过放在前端的水印都是比较容易被去除的,只要在浏览器 Devtools 中找到水印所在 DOM 元素删除即可。于是聪明的前端开发们使用 [MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) 造出了不死水印:只要水印被删除或者样式被修改,就会重新创建一个水印。 以某个国产[水印库](https://github.com/saucxs/watermark-dom)为例,不死水印的原理如下(有简化) ```tsx //监听dom是否被移除或者改变属性的回调函数 var domChangeCallback = function (records){ // ... if ((globalSetting && records.length === 1) || records.length === 1 && records[0].removedNodes.length >= 1) { // 如果被删除,则重新创建水印图层 loadMark(globalSetting); } }; var hasObserver = MutationObserver !== undefined; var watermarkDom = hasObserver ? new MutationObserver(domChangeCallback) : null; var option = { 'childList': true, // 防止被删除,水印外层需要额外包一层 div 'attributes': true, // 防止 style 被修改 'subtree': true, // 防止被删除 }; // ... watermarkDom.observe(document.getElementById(defaultSettings.watermark_id).shadowRoot, option); ``` 当水印被删除 (`childList`) 或者 style 被修改 (`attributes`) 时,`MutationObserver` 就会触发回调,重新绘制水印,让我们无法通过正常方式删除。当然还有一些变种的不死水印,在被删除 / 修改时会清空页面或者后台上报删除事件,让人防不胜防。对付这些水印,我们可以在控制台上禁用 JavaScript 来防止这些骚操作,然后尽情地去除水印再进行截图。 不过这样还是有点麻烦,如果想要一个没有水印的干净清爽的世界,有更好的方法吗? 既然不死水印使用的是 `MutationObserver`,我们可以通过油猴脚本,我们可以在页面脚本之前把这个东西干掉。 ```tsx // ==UserScript== // @run-at document-start // ==/UserScript== delete window.MutationObserver delete window.WebKitMutationObserver delete window.MozMutationObserver ``` 大公告成!不过有些站点本身就会使用 `MutationObserver` ,贸然删除会导致功能不可用,如果要精准控制的话就需要自己写 `Proxy` 劫持 `construct` 来处理了,这样又会麻烦起来。那么有没有一劳永逸的方法呢? 其实还是有的,也就是本文的正题了—— 水印制作者需要花费很大力气保证水印可见并且可以恢复出信息,而去除水印只需要让它不可见就可以了。那么有没有办法在不修改水印本身样式的情况下让它不可见呢?答案就是使用 CSS 从“旁路”攻击水印。 假设我们有一个水印图层长这样 ```html ``` 虽然水印已经内联了 `important` 样式防止被 `display: none` 掉,但我们还有非常多的方式可以让它不可见: ```css #wm_div_id { opacity: 0; visibility: hidden; width: 0; height: 0; position: absolute; top: -9999; // and much more } ``` 让水印不可见并不是我们对水印元素做了任何修改,我们只是让 CSS selector **命中**了这个元素并且让它看不见而已。`MutationObserver` 是不会触发任何回调的,而目前的 Web 规范中也暂时没有能监听*计算样式*变化的 API,好耶! 此外前端生成的水印图层常常会有很明显的特征可以被 CSS selector 选中,发动一点小脑筋很快就可以写出一个能处理掉大部分站点水印的样式规则,再使用 stylish 之类的浏览器插件加载到每个网页上,这下我们可以在完全不被水印影响的情况下尽情冲浪了。 尽管 CSS 样式攻击很难防御,JS 也不是没有应对方法:`Element.getComputedStyle()` 可以获取特定元素的计算样式,JS 获取到计算样式之后可以检查是否被修改再重新绘制水印。获取计算样式由于会触发 RecalculateStyle 和 Layout 所以对性能可能会有影响(不过可以在 rAF 里面处理)。这样做的成本真的很高,应该不会真的有人这么做吧.jpg 相信大家已经完全掌握了这门技术,学会编写自己的攻击样式了吧。我可没有传授什么去内网水印的教程( 冲浪愉快 :)
关于我的祖辈是哪里来的那些事 作者: Semesse 时间: 2022-02-07 分类: 百草 评论 > “这是舅公,这是表叔”,母亲把我领到众亲戚面前,“满嬷,表叔的老婆叫啥子,表嫂哇”,她扭头小声问奶奶。“表婶嘛”,奶奶也小声地应。 > > “舅公,表叔,表婶,幺爸幺妈”,我逐一叫完才得坐上桌。筷子刚到手里,舅公先开了口:“你在哪会读书嗄,华东石油大学?”,“是中国石油大学,在青岛”,我刚叫过的亲戚中的某位代我回答了。“嚯,高材生,我们屋头的高嗷嗷嗷材生”,满桌人都哄笑起来。 - 阅读剩余部分 -
废物再利用计划:使用 RTL-SDR 来收听 FM 广播 作者: Semesse 时间: 2021-09-22 分类: 千叶 评论 某天 [@moycat](https://moy.cat) 翻出来一个 RTL-SDR 的接收器(R820T2),天线已经烂掉了,但是粘一下还能用( 用 SDRSharp 调试了一晚上可以收到调频广播,但是比较可惜的是没有收到机场(估计是太远了)和附近出租车司机的对讲。眼看接收器没啥用了,不如用来做点东西 当然是用来搭个 webserver 坠吼啦,说干咱就开始找有没有现成的库。nodejs 有两个 sdr 的库,一个叫 node-rtlsdr,包了一层 librtlsdr;另一个叫 rtl-sdr,也是包了一层 librtlsdr,但是很可惜的是这两个库都很背时,完全跑不起来(其实还有一个极为申必的用 node-usb / WebUSB 做的库,但发现的时候已经太晚了 XD) - 阅读剩余部分 -
🌇快下班吧,趁太阳落山之前 作者: Semesse 时间: 2021-07-21 分类: 百草 6 条评论 > 当他走出公司的时候,太阳还暖,小学生刚放学,路边的狸花猫从大觉中醒来。 又咕咕了接近小半年了,再不写点什么总觉得对不起每个月 CF 回源在咕咕云上留下的几美分博客运营成本(事 RSS,博客的 90% 流量都事某个申必 RSS client 在拉 feed 流) 自从最近取消了大小周之后心态变好了,每一次小周都让人深刻地感觉到单休就是无休。一些事情本来只有在大周才方便做的,比如给房间降熵、睡一整天大觉,现在每个周末都可以了。 - 阅读剩余部分 -