22// @name CCW-Code-Injection-Risk-Warning
33// @description CCW代码注入风险警告,让你的账号更安全。
44// @author bddjr
5- // @version 20260127-1658
5+ // @version 20260509-1820
66// @match https://www.ccw.site/*
7- // @icon https:/m.ccw.site/community/images/logo-ccw.png
7+ // @match https://learn.ccw.site/*
8+ // @match https://m.ccw.site/*
9+ // @icon https://m.ccw.site/community/images/logo-ccw.png
810// @grant none
911// @run -at document-start
1012// @updateURL https://bddjr.github.io/CCW-Code-Injection-Risk-Warning/CCW-Code-Injection-Risk-Warning.user.js
1113// @downloadURL https://bddjr.github.io/CCW-Code-Injection-Risk-Warning/CCW-Code-Injection-Risk-Warning.user.js
1214// ==/UserScript==
15+ //@ts -nocheck
1316
1417// Source Code:
1518// https://github.com/bddjr/CCW-Code-Injection-Risk-Warning
1619
20+ if ( location . hostname == 'learn.ccw.site' ) {
21+ // 自动防御基于 iframe 的代码注入攻击,仅允许白名单网址
1722
18- //@ts -nocheck
23+ // 创作者学院编辑器提示:暂时只支持bilibili和西瓜视频以及站内链接
24+ // 查找并分析js文件
25+ // https://learn.ccw.site/_next/static/chunks/708-9a7dbfbb32eca7d3.js
26+ // https://learn.ccw.site/_next/static/chunks/5191-e0df96b8928838d4.js
27+ // https://learn.ccw.site/_next/static/chunks/app/(normal)/home/layout-a9cb46b1ff2d4762.js
28+ // 创作者学院前端支持插入的 URL origin :
29+ // [
30+ // "https://scratch.mit.edu",
31+ // "https://youtube.com",
32+ // "https://www.facebook.com",
33+ // "https://www.twitch.tv",
34+ // "https://twitter.com",
35+ // "https://qa.cocrea.world",
36+ // "https://www.ixigua.com",
37+ // "https://ixigua.com",
38+ // "https://bilibili.com",
39+ // "https://player.bilibili.com",
40+ // "https://www.bilibili.com",
41+ // "https://www.ccw.site",
42+ // "https://ccw.site",
43+ // "https://learn.ccw.site",
44+ // "https://learn-qa.xiguacity.cn"
45+ // ]
46+ // 或者 origin 包含 "ccw.site" 或 "xiguacity.cn" 。
47+ // 仅在编辑器里插入的时候会校验,但查看文章的时候加载iframe前不会校验。
48+ // 我不知道服务器会不会校验。
49+
50+ // 定义自己的白名单
51+ // 参考 https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy/frame-src
52+ const whitelist = [
53+ "https://www.ccw.site/embed" ,
54+ "https://ccw.site/embed" ,
55+ "https://player.bilibili.com/player.html" ,
56+ "https://www.bilibili.com/video/" ,
57+ "https://bilibili.com/video/" ,
58+ ]
59+ const meta = document . createElement ( 'meta' )
60+ meta . setAttribute ( 'http-equiv' , 'content-security-policy' )
61+ meta . setAttribute ( 'content' , `frame-src ${ whitelist . join ( ' ' ) || "'none'" } ;` )
62+ document . head . appendChild ( meta )
63+ console . log ( '【脚本 CCW代码注入风险警告】自动防御基于 iframe 的代码注入攻击,仅允许白名单网址\n' , meta , '\n' , whitelist )
1964
20- const allowExtensionURLPrefix = "https://static.xiguacity.cn/h1t86b7fg6c7k36wnt0cb30m/static/js/"
65+ } else if ( location . hostname == 'm.ccw.site' ) {
66+ // 基于svg的代码注入攻击
67+ // 脚本无法防御该攻击,因为攻击者的代码先执行。
68+ // 参考 https://github.com/bddjr/CCW-Code-Injection-Risk-Warning/issues/3
69+ if ( document . contentType == 'image/svg+xml' ) {
70+ try {
71+ window . stop ( )
72+ } catch ( e ) { }
73+ alert ( `【脚本 CCW代码注入风险警告】
2174
22- // let hasCCWDataCodeInjectionFix = null
23- // /** 检测是否已安装 CCWData-Code-Injection-Fix.user.js */
24- // function checkHasCCWDataCodeInjectionFix() {
25- // if (hasCCWDataCodeInjectionFix !== null) return hasCCWDataCodeInjectionFix
26- // const head = document.createElement('head')
27- // const script = document.createElement('script')
28- // script.src = "https://static.xiguacity.cn/h1t86b7fg6c7k36wnt0cb30m/static/js/scratch3_ccw_data.cbf43b4e.js"
29- // head.appendChild(script)
30- // return hasCCWDataCodeInjectionFix = !!(!script.hasAttribute("src") && script.innerHTML?.includes('ccwdataExtensionSafeEval'))
31- // }
75+ 您正在使用标签页访问svg,恶意代码可能已经执行。
76+ 建议您关掉该标签页,然后尽快修改您的账号的密码。
77+ 如果攻击者已经使用您的账号捣乱,请及时向共创世界管理员或鸭鸭院长申诉。` )
78+ }
3279
33- function checkHasExt ( extensions , id ) {
34- id = id . toLowerCase ( )
35- return extensions ?. some ( v => ( String ( v ) . toLowerCase ( ) == id ) )
36- }
80+ } else {
81+ // www.ccw.site
3782
38- let acceptLoadExt = null
83+ const allowExtensionURLPrefix = "https://static.xiguacity.cn/h1t86b7fg6c7k36wnt0cb30m/static/js/"
3984
40- const { parse } = JSON
85+ // let hasCCWDataCodeInjectionFix = null
86+ // /** 检测是否已安装 CCWData-Code-Injection-Fix.user.js */
87+ // function checkHasCCWDataCodeInjectionFix() {
88+ // if (hasCCWDataCodeInjectionFix !== null) return hasCCWDataCodeInjectionFix
89+ // const head = document.createElement('head')
90+ // const script = document.createElement('script')
91+ // script.src = "https://static.xiguacity.cn/h1t86b7fg6c7k36wnt0cb30m/static/js/scratch3_ccw_data.cbf43b4e.js"
92+ // head.appendChild(script)
93+ // return hasCCWDataCodeInjectionFix = !!(!script.hasAttribute("src") && script.innerHTML?.includes('ccwdataExtensionSafeEval'))
94+ // }
4195
42- JSON . parse = function myParse ( ) {
43- const out = parse . apply ( this , arguments )
44- if ( acceptLoadExt !== true && out ?. targets ?. [ 0 ] ?. blocks ) {
45- if ( acceptLoadExt === null ) {
46- const { targets, extensions, extensionURLs } = out
47- const hasCCWData = checkHasExt ( extensions , "CCWData" )
48- const hasWitCatJSSandBox = checkHasExt ( extensions , "WitCatJSSandBox" )
49- let hasCustomExt = false
50- let needWarn = false
51- const msg = [ '【脚本 CCW代码注入风险警告】' ]
52- // CCWData
53- if ( hasCCWData ) {
54- // needWarn = true
55- if ( hasWitCatJSSandBox ) {
56- needWarn = true
57- msg . push ( '漏洞链警告!作品可能会使用“白猫的JS沙箱”扩展调用“Gandi云数据”扩展的代码注入漏洞积木!' )
58- }
59- // 检测代码注入漏洞积木
60- let hasCodeInjectionBlock = false
61- const codeInjectionBlocksCount = {
62- CCWData_getValueInJSON : 0 ,
63- CCWData_setValueInJSON : 0
64- }
65- for ( const target of targets ) {
66- const { blocks } = target
67- for ( const id in blocks ) {
68- const block = blocks [ id ]
69- const { opcode } = block
70- if ( codeInjectionBlocksCount . hasOwnProperty ( opcode ) ) {
71- hasCodeInjectionBlock = true
72- codeInjectionBlocksCount [ opcode ] ++
96+ function checkHasExt ( extensions , id ) {
97+ id = id . toLowerCase ( )
98+ return extensions ?. some ( v => ( String ( v ) . toLowerCase ( ) == id ) )
99+ }
100+
101+ let acceptLoadExt = null
102+
103+ const { parse } = JSON
104+
105+ JSON . parse = function myParse ( ) {
106+ const out = parse . apply ( this , arguments )
107+ if ( acceptLoadExt !== true && out ?. targets ?. [ 0 ] ?. blocks ) {
108+ if ( acceptLoadExt === null ) {
109+ const { targets, extensions, extensionURLs } = out
110+ const hasCCWData = checkHasExt ( extensions , "CCWData" )
111+ const hasWitCatJSSandBox = checkHasExt ( extensions , "WitCatJSSandBox" )
112+ let hasCustomExt = false
113+ let needWarn = false
114+ const msg = [ '【脚本 CCW代码注入风险警告】' ]
115+ // CCWData
116+ if ( hasCCWData ) {
117+ // needWarn = true
118+ if ( hasWitCatJSSandBox ) {
119+ needWarn = true
120+ msg . push ( '漏洞链警告!作品可能会使用“白猫的JS沙箱”扩展调用“Gandi云数据”扩展的代码注入漏洞积木!' )
121+ }
122+ // 检测代码注入漏洞积木
123+ let hasCodeInjectionBlock = false
124+ const codeInjectionBlocksCount = {
125+ CCWData_getValueInJSON : 0 ,
126+ CCWData_setValueInJSON : 0
127+ }
128+ for ( const target of targets ) {
129+ const { blocks } = target
130+ for ( const id in blocks ) {
131+ const block = blocks [ id ]
132+ const { opcode } = block
133+ if ( codeInjectionBlocksCount . hasOwnProperty ( opcode ) ) {
134+ hasCodeInjectionBlock = true
135+ codeInjectionBlocksCount [ opcode ] ++
136+ }
73137 }
74138 }
75- }
76- // 生成警告消息
77- const thisMsgPrefix = '作品试图加载“Gandi云数据”扩展,'
78- if ( hasCodeInjectionBlock ) {
79- needWarn = true
80- const thisMsg = [ thisMsgPrefix + '并使用以下代码注入漏洞积木:' ]
81- for ( const opcode in codeInjectionBlocksCount ) {
82- const count = codeInjectionBlocksCount [ opcode ]
83- if ( count ) thisMsg . push ( JSON . stringify ( opcode ) + ' × ' + count + ' 块' )
139+ // 生成警告消息
140+ const thisMsgPrefix = '作品试图加载“Gandi云数据”扩展,'
141+ if ( hasCodeInjectionBlock ) {
142+ needWarn = true
143+ const thisMsg = [ thisMsgPrefix + '并使用以下代码注入漏洞积木:' ]
144+ for ( const opcode in codeInjectionBlocksCount ) {
145+ const count = codeInjectionBlocksCount [ opcode ]
146+ if ( count ) thisMsg . push ( JSON . stringify ( opcode ) + ' × ' + count + ' 块' )
147+ }
148+ msg . push ( thisMsg . join ( '\n' ) )
149+ } else {
150+ // msg.push(thisMsgPrefix + '但未检测到代码注入漏洞积木。')
84151 }
85- msg . push ( thisMsg . join ( '\n' ) )
86- } else {
87- // msg.push(thisMsgPrefix + '但未检测到代码注入漏洞积木。')
88152 }
89- }
90- // 自制扩展
91- if ( extensionURLs instanceof Object ) {
92- const customExtDisplayArray = [ '作品试图加载自制扩展:' ]
93- for ( const key in extensionURLs ) {
94- const url = new URL ( extensionURLs [ key ] , location ) . href ;
95- if ( ! url . startsWith ( allowExtensionURLPrefix ) ) {
96- hasCustomExt = true
97- customExtDisplayArray . push ( JSON . stringify ( key ) + '\n' + url )
153+ // 自制扩展
154+ if ( extensionURLs instanceof Object ) {
155+ const customExtDisplayArray = [ '作品试图加载自制扩展:' ]
156+ for ( const key in extensionURLs ) {
157+ const url = new URL ( extensionURLs [ key ] , location ) . href ;
158+ if ( ! url . startsWith ( allowExtensionURLPrefix ) ) {
159+ hasCustomExt = true
160+ customExtDisplayArray . push ( JSON . stringify ( key ) + '\n' + url )
161+ }
162+ }
163+ if ( hasCustomExt ) {
164+ needWarn = true
165+ msg . push ( ...customExtDisplayArray )
98166 }
99167 }
100- if ( hasCustomExt ) {
101- needWarn = true
102- msg . push ( ...customExtDisplayArray )
103- }
104- }
105- // 警告
106- if ( needWarn ) {
107- console . warn ( msg . join ( '\n\n' ) )
108- if ( hasCustomExt ) msg . push ( '如果要复制链接,请打开DevTools,查看控制台(Console)。\n如果控制台没有内容,请刷新页面。' )
109- msg . push ( '如果要继续加载作品,请输入“继续加载”,然后点击“确定”,\n否则点击“取消”。' )
110- for ( const message = msg . join ( '\n\n' ) ; ; ) {
111- let input = window . prompt ( message )
112- if ( input == null ) {
168+ // 警告
169+ if ( needWarn ) {
170+ if ( window !== window . top && ! location . pathname . startsWith ( '/embed' ) ) {
113171 acceptLoadExt = false
114- break
115- }
116- input = input . trim ( ) . toLowerCase ( )
117- if ( [ "继续加载" , "繼續加載" , "jixujiazai" ] . includes ( input ) ) {
118- acceptLoadExt = true
119- break
172+ console . log ( '【脚本 CCW代码注入风险警告】检测到在 iframe 里,且网址路径开头不是 /embed ,自动阻止加载可疑作品' )
173+ } else {
174+ console . warn ( msg . join ( '\n\n' ) )
175+ if ( hasCustomExt ) msg . push ( '如果要复制链接,请打开DevTools,查看控制台(Console)。\n如果控制台没有内容,请刷新页面。' )
176+ msg . push ( '如果要继续加载作品,请输入“继续加载”,然后点击“确定”,\n否则点击“取消”。' )
177+ for ( const message = msg . join ( '\n\n' ) ; ; ) {
178+ let input = window . prompt ( message )
179+ if ( input == null ) {
180+ acceptLoadExt = false
181+ break
182+ }
183+ input = input . trim ( ) . toLowerCase ( )
184+ if ( [ "继续加载" , "繼續加載" , "jixujiazai" ] . includes ( input ) ) {
185+ acceptLoadExt = true
186+ break
187+ }
188+ }
120189 }
121190 }
122191 }
192+ if ( acceptLoadExt === false ) throw Error ( "Reject by user script: CCW-Code-Injection-Risk-Warning" )
123193 }
124- if ( acceptLoadExt === false ) throw Error ( "Reject by user script: CCW-Code-Injection-Risk-Warning" )
125- }
126- if ( acceptLoadExt === true && JSON . parse === myParse ) {
127- // 取消劫持
128- JSON . parse = parse
194+ if ( acceptLoadExt === true && JSON . parse === myParse ) {
195+ // 取消劫持
196+ JSON . parse = parse
197+ }
198+ return out
129199 }
130- return out
131200}
0 commit comments