ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

前端防复制与源码保护实战:屏蔽右键、动态渲染与防盗链方案

前端防复制与源码保护实战:屏蔽右键、动态渲染与防盗链方案

前阵子有个做内容站的朋友跟我倒苦水:自己辛辛苦苦整理的资料,被人用右键“查看源代码”整个扒走,还顺手复制粘贴到别处洗稿。他问我有啥办法能把网页的“源码显示”和“复制粘贴”彻底屏蔽掉。

我先说个扎心的结论:前端层面不存在“彻底”屏蔽,任何纯浏览器端的防护都只能提高门槛,防的是普通路人,防不了铁了心的老手。但这不代表这事儿不值得做。现实中,90%的随手盗用都是“快捷键一按、内容就到手”的低成本操作,我们把这90%拦下来,把门槛抬高,让顺手牵羊变成一件费劲的事,就达到了80%的预期效果。

这篇文章,我把实际项目中用过的几套方案完整梳理一遍,包括右键禁用、快捷键拦截、复制粘贴管控、源码混淆、资源防盗链,以及这些方案各自的局限和坑。内容不绕弯子,按可直接抄作业的标准来写。

1. 内容整体设计与思路拆解

1.1 核心需求解析:到底在防谁

动手之前,先搞清楚一个关键问题:你要防的人是谁?不同目标,技术选型完全不同。

  • 防普通人:就是那种习惯性右键、Ctrl+C、Ctrl+U看源码的访客。这类防护做起来最简单,一条contextmenu事件、一段keydown拦截就够。
  • 防半吊子:懂一点开发者工具、会看网络请求、会禁用JavaScript的人。对付这类需求,光靠拦截事件不够,还得做内容动态渲染、接口数据加密、资源防盗链。
  • 防专业开发者:说实话,这个目标基本无法通过前端实现。任何人只要控制了自己的浏览器,就控制了你的页面代码,内存里的数据、网络面板里的请求都是明晃晃的。你能做的只有后端鉴权、动态令牌、频繁更换接口签名,让爬取成本变得高于收益。

在项目启动前,我习惯先把“防盗目标”写进技术方案里,因为后面所有的代码设计和防护强度都要围绕这个目标来定。防普通人,方案复杂度可以控制在很小的范围内,部署成本也低;防半吊子,就需要引入服务端的配合,接受一定的开发量。

1.2 方案选型的核心思路:分层防护

我最终选择的是一套“三层防护”结构,思路类似小区安保:围墙拦普通人、门禁拦闲杂人、室内保险柜防专业盗贼。

第一层是交互拦截层,纯前端实现,负责干掉右键、快捷键、文本选择和复制动作。这一层成本最低,见效最快,但技术上也最容易被绕过。

第二层是内容伪装层,对源码里的正文做动态渲染和混淆处理,让即使打开开发者工具,看到的也只是乱码或者异步加载的空壳结构。这一层能挡住相当一部分“看代码扒数据”的行为。

第三层是数据校验层,通过后端接口鉴权、资源防盗链、动态水印,让非法获取的数据就算被拿走了,也带着可追溯的标记,能顺着源头找到责任人。

这三层不是全部一次做完的——先做第一层搭好基本防护,再根据业务需要增加第二层,有条件的再上第三层。这样对业务影响最小,也方便单独回滚。从实际经验看,强力防护通常会在上线一周内出现误伤用户的投诉,分层设计能让你精确定位是哪一层误杀,快速调整。

1.3 工具选型与兼容性考虑

技术选型上,纯原生JavaScript就能解决大部分问题,不需要引入额外的前端框架。关键在于事件监听的方式和CSS属性兼容性。

事件监听有两条路:一是直接在HTML标签里写内联oncontextmenu="return false"这类属性,简单粗暴;二是用addEventListener统一注册,代码更干净、可维护性高,但要注意在页面加载时机上做好处理。我推荐用第二种,并统一封装成一个模块,方便后续按业务开关。

CSS部分主要依赖user-select这个属性。它的兼容性在现代浏览器里都没问题,但前缀写法比较多,老版本浏览器可能需要-moz-user-select、-webkit-user-select这些私有前缀,编写时需要一并考虑。

另外,移动端和桌面端的交互习惯差异很大。移动端没有右键,但长按会出现系统菜单,需要监听contextmenu事件(移动端的长按会触发);桌面端主要是键盘快捷键和鼠标右键。设计时最好做一份“按设备类型生效”的配置,避免同一个策略在两边产生不同副作用。

2. 屏蔽源码显示:交互层的拦截与实现

2.1 禁用右键菜单的完整实现

右键菜单是“查看源代码”最直接的入口。在Chrome、Firefox、Edge这些主流浏览器里,网页空白区域和文本上的右键菜单都包含“查看页面源代码”选项,对非技术用户来说这是最常用的查看源码方式。

最经典也最兼容的做法是监听contextmenu事件并在事件处理器里调用preventDefault()阻止默认菜单弹出:

document.addEventListener('contextmenu', function (event) { event.preventDefault(); return false; });

这段代码放在<head>区域的<script>标签里,或者外部脚本文件里都可以。注意要确保脚本在任何用户交互发生前就加载完毕,否则可能出现页面先渲染、脚本还没生效的窗口期。

如果只是全站统一屏蔽,这段代码就够了。但我建议做得精细一点——很多博客和内容站还需要保留表单输入框、图片区域的常规右键操作,这时候按区域控制更合理:

document.addEventListener('contextmenu', function (event) { // 允许在输入框区域使用系统右键,方便编辑文本 var tagName = event.target.tagName; if (tagName === 'INPUT' || tagName === 'TEXTAREA' || event.target.isContentEditable) { return true; } event.preventDefault(); return false; });

另外一个容易被忽略的入口是键盘上的上下文菜单键,就是部分键盘上位于右Ctrl左边的那个按键,功能等同于右键。它不触发contextmenu事件吗?实际会触发的,上面的监听可以一并拦下。但如果浏览器是旧版,最好再加一层keydown监听,把键码93(上下文菜单键)和快捷键Shift+F10一起拦住:

document.addEventListener('keydown', function (event) { var code = event.keyCode || event.which; // 93是上下文菜单键,Shift+F10也被部分系统识别为右键 if (code === 93 || (event.shiftKey && code === 121)) { event.preventDefault(); } });

这里我想强调一个坑:很多教程只教禁用右键,却不提上下文菜单键和快捷键,导致实际测试时发现右键被拦住了,键盘一按又原形毕露。完整方案一定要把右键事件、菜单键、Shift+F10这几个入口都覆盖到。

2.2 拦截开发者工具快捷键

“查看源代码”的另一个高频入口是Ctrl+U(查看源代码)、Ctrl+Shift+I(打开开发者工具)、F12(打开开发者工具)。这三个入口如果能拦住,能拦下一大批好奇的访客。

document.addEventListener('keydown', function (event) { if (event.ctrlKey && event.shiftKey && event.keyCode === 73) { // Ctrl+Shift+I event.preventDefault(); } if (event.ctrlKey && event.keyCode === 85) { // Ctrl+U event.preventDefault(); } if (event.keyCode === 123) { // F12 event.preventDefault(); } });

但这里我要说实话:这套拦截对开发者工具基本无效。原因很简单——F12的开发者工具快捷键是浏览器层面的功能,JavaScript的preventDefault拦不住所有浏览器上的这个默认行为。实测来说,Chrome新版能拦住F12,但某些场景下还是会弹出开发者工具;Firefox、Edge对快捷键的处理也不完全一致。

更“硬核”一些的做法是检测开发者工具是否打开,比如监听窗口尺寸变化、比较窗口内外尺寸,一旦发现就清空页面内容。这属于“对抗型”方案,副作用是各种误判,用户体验会变得很差。我个人的建议是:不要在这条路上走太远,象征性拦截一下就够了。真正想看源码的人,永远有别的办法,比如在浏览器地址栏输入view-source:,这个是前端JS完全无法拦截的。

如果需求优先级确实很高,另一个务实的策略是把重要内容移除出静态源码,改成接口动态渲染。一个人打开开发者工具看到的是空的<div>,里面什么都没有,加上源码显示屏蔽也形同虚设——没有实货,看也白看。这个思路我在第三节详细展开。

2.3 禁止文本选择与拖拽

除了直接阻止用户查看源码,还要防止文本被方便地选中、拖拽复制。CSS层面首先控制选中行为:

body { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }

这个样式让页面上所有的文本都无法用鼠标选中,视觉上配合cursor: default,效果非常明显。但注意,这也是最容易被用户吐槽的一条。很多内容站点只是不想让人复制,但阅读时高亮选中一段文字来辅助阅读是刚需,全部禁止会严重削弱阅读体验。

我的建议是分成两档:

  • 内容区(文章正文):完全不禁止选中,只禁止复制动作,让读者可以正常划线做笔记。
  • 非内容区(导航、页脚、侧边栏):可以放开user-select限制,让交互正常。
  • 付费内容或关键核心数据区:使用user-select: none,同时禁止拖拽选择。

禁止拖拽选择需要额外监听selectstart和dragstart事件:

document.addEventListener('selectstart', function (event) { event.preventDefault(); return false; }); document.addEventListener('dragstart', function (event) { event.preventDefault(); return false; });

这里有个细节:selectstart事件拦截的是用鼠标拖拽选择文本的过程,一旦触发就直接取消选择。如果已经允许选中但还要阻止复制,千万别把selectstart也禁了,否则文本根本选不中,读者使用体验会非常差。切记区分“禁止选中”和“禁止复制”是两码事。

2.4 处理框架页面与局部白名单

页面里如果有iframe,事件监听需要考虑到跨域限制。同域iframe可以直接在内部页面上挂同样的监听,跨域iframe父页面无法干预内部行为。这个点很容易被忽略,很多站点做了全站右键禁用,但嵌了个第三方地图或视频iframe进去,结果人家右键照样弹菜单,看起来防护就是漏的。

处理方法要么是给iframe加oncontextmenu="return false"属性(跨域也生效),要么把需要防护的内容放到不嵌套iframe的主文档里。对于真正需要嵌入第三方服务的情况,可以在iframe标签上加pointer-events: none禁止用户直接交互,或用透明遮罩层盖在上面,彻底切断右键操作。

白名单区域的设计也很重要。不要把全站的右键都禁掉,至少保留以下例外:

  • 输入框、文本域内的右键(剪切、粘贴、拼写检查是用户刚需)
  • 联系方式、订单编号等需要用户复制的业务数据
  • 后台管理界面的所有交互(管理员自己不能被防护误伤)

3. 内容层防护:让源码即使被看到也拿不走

3.1 数据动态渲染:源码里不放正文

交互拦截做得再密,开发者工具打开后,页面源码里直接躺着一大段正文,那等于把版权内容公开挂在墙上。最有效的内容层防护就是让源码里不出现正文数据。

具体做法:把原本写在HTML里的文字内容抽出去,放到接口返回的数据里,前端拿到数据后再渲染到页面上。比如一个商品详情页,静态源码里只有一个<div id="product-detail"></div>,正文内容由JavaScript请求接口后动态写入。此时别人看源码,看到的结构就是空壳,真正的文本在开发者工具的“网络”面板里才能看到。

接口返回的数据还可以做一层“字符编码混淆”,把明文变成字符编码拼接:

// 服务端返回数据时,将部分关键内容做编码处理 { "title": "\u67d0\u5546\u54c1\u6807\u9898", "content": "\u8fd9\u662f\u6b63\u6587\u7b2c\u4e00\u6bb5..." }

这段JSON里的\u开头是Unicode编码,渲染时JavaScript的JSON.parse会自动解码成中文,但直接看源码的人看到的就是天书。这个思路成本极低,服务端多写一个转换函数就行,却能挡掉一大批顺着源码找数据的人。

再进阶一点,可以根据用户权限动态拼接内容。比如某个核心段落只对登录用户可见,涉及敏感数据的关键句子由接口实时拼装返回,没权限的请求直接返回不含关键内容的版本。这样即使数据被拿到,别人拿到的也不是完整可用的版本。

3.2 文本混淆的几种常见方案

纯粹的文本混淆有三个常用做法,按实现成本从低到高排列:

做法一:字符拼接。在JavaScript里把一段话拆成多个片段,运行时再拼起来。

var part1 = '这个页面的核心说明在前面的'; var part2 = '概述部分,但索引来自后台'; var part3 = '系统推送,静态源码里并没有这段'; var fullText = part1 + part2 + part3; document.getElementById('content').innerText = fullText;

这种做法对“直接看源码”的人非常奏效,他们看到的只是零散的字符串,根本拼不出上下文。

做法二:Base64编码。把正文用Base64编码后嵌入到script标签里,前端运行时解码再渲染。

// Base64不是加密,只是编码,肉眼无法直接阅读 var encodedText = '6L+Z5piv5q2k6Imy6K+06Zeu6aKY57uT5p6E...'; var decodedText = decodeURIComponent(escape(atob(encodedText))); document.getElementById('content').innerText = decodedText;

但要注意,Base64非常容易解码,开发者工具里一行命令就能还原,它的作用仅限于增加肉眼阅读源码的难度。

做法三:动态混淆算法。用简单的位移、异或之类的算法对文本做处理,密钥藏在前端JS里。这个成本最高,但同样挡不住专业逆向——所有密钥都在浏览器里,考验的只是对方的耐心。

我的经验是:文本混淆的意义不在于让数据无法被获取,而在于提高获取成本。编码不是加密,这个认知一定要清楚。如果业务数据价值极高,应该优先考虑后端加密接口+权限校验,而不是依赖前端混淆。

3.3 图片与多媒体资源的防盗链

很多人只顾着防文字复制,忘了图片才是被扒的重灾区。一张高质量的商品图、一个精心制作的图表,往往比几段文字更有价值。图片防盗链的核心手段是HTTP Referer校验,在服务器或CDN层面配置:只有当请求来源是本站域名时才返回图片资源,其他来源一律返回403。

以Nginx配置为例:

location ~* \.(jpg|jpeg|png|gif|webp)$ { valid_referers none blocked server_names *.example.com example.com; if ($invalid_referer) { return 403; } }

这段配置的意思是:没有Referer的请求直接放行,有关联Referer但域名不是本站的请求一律返回403。这样做之后,别人把图片地址贴到自己网站上,图片会直接裂开,因为他们站点的请求Referer不在白名单内。

但要注意两个坑:

  • none表示允许空Referer请求,这样做是为了兼容用户在地址栏直接输入图片地址的场景。如果你发现图片总是显示不了,要先检查是不是none被误加了。
  • CDN通常会改写Referer头,如果你用了多层CDN或云厂商的图片加速服务,可能需要在CDN控制台里单独配置Referer防盗链,而不是只改源站的Nginx。

图片防盗还有一个辅助技巧是切割拼合显示。把一张关键图片横向切成几段,前端用CSS拼合显示,单独下载任何一段都看不到完整图。代价是多几个请求、维护稍复杂,适用于核心视觉素材的防护,对普通的多图页面不太划算。

3.4 前端“防复制”与源码“防查看”的边界

关于前端防护,我踩过最大的坑就是“无限堆代码”。我曾经见过某项目把右键拦截、快捷键拦截、选中禁用、F12检测、Debugger断点、iframe覆盖全上了一遍,结果页面加载后3秒钟内,用户的鼠标不能动、快捷键失灵、表单无法填写,投诉率暴涨。

现实是,你不可能在前端实现“物理级”的源码保护。浏览器为了渲染页面,必须把HTML、CSS、JS全部下发给用户,只要内容到达了用户设备,就是“可被阅读”的状态。“查看源码”只是把这份内容用一种更原始的格式呈现给你罢了。

所以内容层防护的价值排序应该是:

  • 高价值:后端权限校验。谁可以访问接口、谁可以拿到完整数据,这个在前端完全不可控,必须交给服务端。
  • 中价值:动态渲染+资源防盗链。让内容不出现在静态源码里,提升手动拿取的成本。
  • 低价值:右键禁用+快捷键拦截。只能防“顺手党”,且容易伤及正常用户。

心里清楚了这条边界,就不会再纠结于“为什么我都屏蔽了,开发者工具还能看到”,也不会去做那些副作用很大的激进操作。

4. 复制粘贴屏蔽的落地细节与策略

4.1 复制事件拦截与剪贴板控制

屏蔽复制最简单的实现是监听copy事件,阻止默认复制行为:

document.addEventListener('copy', function (event) { event.preventDefault(); });

这段代码可以阻止Ctrl+C、右键菜单复制、浏览器菜单复制,相当于把复制这条路整个堵死。

但又有另一个经典问题:如果连复制都不允许,用户怎么保存订单号、提取联系方式、摘抄重点?纯“禁”的方案过于僵硬。更合理的思路是“有条件的放行”:

var copyEnabled = false; document.addEventListener('copy', function (event) { if (!copyEnabled) { event.preventDefault(); showToast('内容受保护,请前往阅读模式复制'); } });

页面默认禁复制,用户可以点击一个“开启复制权限”的按钮,通过人机验证或登录之后,动态放开某一部分的复制权限。这样既限制了机器人批量采集,又给了真实用户一条明路。

剪贴板还有一种“受控复制”方案:用户点击复制按钮时,程序把指定的内容(比如一段简洁的文本或带水印的引用文案)写入剪贴板,而不是让用户随意选择复制页面任意区域。

document.getElementById('copyBtn').addEventListener('click', function () { var text = '内容来自某网站,原文链接:https://example.com/article/123'; navigator.clipboard.writeText(text).then(function () { alert('已复制,感谢分享'); }); });

这样即使内容被复制出去了,剪贴板里也带着出处和链接,天然形成了传播追踪。这是我觉得比“一刀切禁复制”更聪明的做法。

4.2 粘贴行为限制的适用场景

“禁止粘贴”和“禁止复制”是两件事。有些场景需要禁用粘贴:比如某个输入框只允许用户手动输入,不希望用户粘贴大段文本或预设内容进来。

document.querySelectorAll('.no-paste-input').forEach(function (element) { element.addEventListener('paste', function (event) { event.preventDefault(); }); });

不过“禁止粘贴”很容易造成严重体验问题。典型反例是验证码输入框——很多人会从短信里复制验证码再粘贴进去,如果你给验证码输入框绑了禁止粘贴,大批用户会被卡住,直接弃用。

所以禁用粘贴的适用边界要极为小心。建议只在后台管理、敏感操作确认这些场景使用,前端表单绝大多数情况下不要禁止粘贴。真正需要保护的数据,后端校验才是可靠的,而不是前端拦截一下“看起来安全”就完事。

4.3 移动端长按菜单的单独处理

移动端的复制方式跟桌面端完全不同:桌面端是Ctrl+C和右键,移动端是长按选中文本后弹出系统菜单。桌面端做的事件拦截,到移动端不一定生效,尤其要检查contextmenu事件在移动端WebView和微信内置浏览器里的表现。

移动端需要的具体处理包括:

  • 监听contextmenu,在移动端也会触发,需要一并禁止。
  • 使用user-select: none禁止文本被长按选中。
  • 针对图片,设置draggable="false",并监听touchstart/touchmove中阻止默认行为,避免长按图片弹出“保存图片”菜单。
  • 如果业务真的要允许复制,也要提供自定义的复制按钮,引导用户点击按钮复制指定内容,而不是依赖系统长按菜单。

移动端的坑通常出现在iOS Safari和部分安卓浏览器上,同样的CSS属性在不同内核上的行为不一致。最稳妥的方式还是发版后在真机上逐个过一遍主要机型,不要只靠开发工具的设备模拟器验证。

4.4 防复制与SEO收录的平衡

这里有一个非常隐蔽的陷阱:你把文本复制功能屏蔽得很彻底,搜索引擎的蜘蛛也可能受影响。

蜘蛛机器人模拟的是浏览器行为,它也需要读取页面上的文本内容。如果你的页面上所有内容都是JavaScript动态渲染的,而搜索引擎的爬虫又不会去执行JavaScript(部分会执行,部分只抓静态页面),那收录效果可能大打折扣。

更好的实践是:

  • 首屏关键内容保留一部分在静态源码中,次要内容动态渲染。
  • 使用noscript标签为不支持JavaScript的访问者提供内容的纯文本版本,对SEO友好。
  • 不在正文区域使用user-select: none,只对核心付费内容启用。

数据表明,很多CMS的SEO排名问题不是出在原创性上,而是因为“内容被过度JS化,蜘蛛根本没抓到正文”。这项平衡在内容站的项目里必须提前想清楚,不然防护做了,流量没了,得不偿失。

5. 常见问题与排查技巧实录

5.1 用户反馈页面选不中、复制不了订单号

这是最常见的落地问题。很多开发者在做“全站禁复制”的时候,没有区分内容区域和功能区域。我处理过的最典型案例是:某站点给全站绑了copy事件的preventDefault,结果用户连自己的订单号都复制不出去,每天几十个客服工单全是“怎么复制订单号”。

排查路径:

  1. 检查copy事件监听器是否绑给了document。
  2. 检查该监听器是否对所有event.target都一视同仁。
  3. 检查页面是否有把user-select: none放到全局。

修复方案很简单,给业务数据区域添加例外标记,比如加一个>document.addEventListener('copy', function (event) { var target = event.target; if (target.closest('[data-copyable]')) { return true; // 放行业务数据复制 } event.preventDefault(); });

同理,表单输入框应该永远允许用户自由操作,千万不要把防复制逻辑一股脑塞给输入类元素。

5.2 F12打开后依然能看到全部内容

这个问题必然出现,而且无法通过前端修复。很多人会反复问:明明禁了右键、禁了F12,为什么开发者工具还是能看到内容?

原因有两点:

  • 浏览器开发者工具的快捷键无法被网页JS完全拦截(前面已经说过)。
  • 只要内容被渲染到页面上,就会存在于内存和网络面板中,开发者工具的Elements、Sources、Network都能看到。

这时候唯一有效的防护在后端。比如做一个接口鉴权,没登录或token过期的时候,接口不给核心数据;核心内容接口返回的数据带有时效加密,过期作废。真正想让“看”这件事变得困难,靠的是服务端控制数据分发,而不是给浏览器加一堆限制。

但我不建议把“防不住”作为不做防护的理由。防护本来就是延缓与拦截——“防小白”这件事依然有巨大的现实价值,因为大量内容盗用根本不是攻击者所为,而是随手复制党。把顺手党拦住了,保护的投入就回本了。

5.3 浏览器升级后原先的拦截失效

跨浏览器版本升级会导致部分快捷键键位、开发者工具快捷键变化,或者新版浏览器对preventDefault的行为做了调整。如果发现拦截脚本在某个新版本浏览器上失效,不要急着堆更多代码,先按这个顺序排查:

  1. 确认事件有没有触发:在keydown、contextmenu处理器里加console.log,看浏览器升级后事件是否还能正常冒泡。
  2. 确认preventDefault是否被其他脚本覆盖:有些第三方统计脚本、UI框架的全局事件可能会导致冲突。
  3. 确认事件监听顺序:如果你绑定了一个全局处理器,之后又有别的类库调用了stopPropagation,你的拦截逻辑可能被短路。

更稳健的做法是只维护一份独立的“防护模块”,推荐用“早期绑定 + 文档级事件”的模式,在页面初始化阶段优先注册,减少被其他库干扰的概率。

5.4 扩展插件和油猴脚本的绕过

浏览器扩展可以绕过几乎所有前端交互层防护。用户安装一个“启用右键”或“强制可复制”的扩展,直接在你的页面注入一段脚本,把contextmenu事件里的preventDefault干掉,一切防护就失效了。

面对这类绕过,前端基本无解。你虽然可以用MutationObserver监听DOM变化、尝试检测注入脚本,但这会陷入持续对抗的泥潭,投入产出比极低。

我的实际建议是,把对抗扩展的精力省下来,转投到水印和溯源上。给页面正文区域打上可变的水印,把用户名和ID混入其中,通过半透明的背景图片或动态叠加层呈现在页面上:

  • 文字水印:字体很小、间距很大、颜色浅淡,不影响正常阅读,却能在截图时留下用户身份。
  • 动态水印:每次页面加载时,根据登录状态生成随机的字符组合,从后台日志可以精确追踪是哪次会话泄露的内容。
  • 不可见水印:通过像素级的色值差异或编码信息隐藏在背景中,别人很难发现,但你有原图可以比对。

水印不能阻止别人拿走内容,但能给拿走的人带来被追溯的风险。对内容方来说,追踪比拦截更关键——复制行为可以防,但一旦防不住了,溯源是最后一道防线。

5.5 常见问题的速查表

现象可能原因解决思路
右键菜单禁了但还能用快捷键查看源码只监听了contextmenu,未处理F12/Ctrl+U/菜单键补全keydown监听,并按浏览器差异调整
表单输入框无法粘贴给全局绑了paste拦截,未区分目标元素增加输入框、文本域的例外判断
移动端长按仍能复制只处理了PC事件,未处理移动端contextmenu和user-select补全触屏事件和CSS属性,真机测试
页面在搜索引擎排名下降内容完全JS渲染,蜘蛛抓取不到静态文本静态保留核心首屏内容,使用noscript
开发者工具打开后动态加载的内容被直接看到内容在内存中明文存在服务端权限控制+数据摘要化,前端无法根治
嵌入第三方iframe后防护失效跨域iframe不受父页面事件限制对iframe加内联属性或使用透明遮罩

写在最后的几条实操心得

做了几年内容防护相关的小项目,我最深的体会是:别把用户的正常需求当成攻击行为来看待。真正大量复制你内容的人,大概率不是那些偶尔想要复制一段联系方式的人;真正想看源码的程序员,你也拦不住。防护手段的价值不在于“绝对安全”,而在于“让大多数人觉得没必要折腾”,同时给你自己留下溯源能力。

回到项目本身,如果你只是要做一个简单的“屏蔽右键和复制”,一页代码就够。但如果想要一套真正“能用”的防护体系,我的建议按以下优先级推进:

  1. 交互拦截层做好基础体验:区分内容区和功能区的白名单,不要伤害表单和订单操作。
  2. 内容渲染层把核心数据抽到接口里,加一层简单的编码混淆。
  3. 一劳永逸的水印溯源方案:哪怕防护被绕过了,你也能知道内容是从哪个账号、哪个会话泄露出去的。
  4. 最后才是那些高成本的加密、断点反调试、动态混淆——它们适合高价值核心业务,普通站点用了容易伤身,慎用。

如果这篇文章对你有帮助,不妨在执行完整套方案之后,装一个去右键的扩展插件试试看效果。你会发现,在你投入大量精力做防护的同时,总有人用最廉价的工具绕过它——这恰恰是“前端防线”这个概念最真实的注脚:它赶走的是君子,拦不住的是小人,但能把君子和小人的鉴别成本降到最低,就已经值回票价了。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进