Featured image of post A Record of My Blog Being Reverse Proxied

A Record of My Blog Being Reverse Proxied

I don't have much to say about scraping, but directly reverse proxying my website is just plain rude.

TL;DR / Geek Summary:

  • Incident: Detected a domain hijacking the entire blog via Cloudflare Workers reverse proxy.
  • Defensive Patch: Implemented a JavaScript domain validator in the <head> to force redirects.
  • Obfuscation Hack: Used obfuscator.io to encrypt the JS logic, preventing the proxy from rewriting validation rules.

Yesterday, I was checking my Google Analytics data in my free time and spotted a referral from a domain I had never seen before. Initially, I thought it was just a scraper site or someone referencing my article, so I decided to take a look. However, upon opening the page, I saw my entire blog right there (completely unmodified).

I wouldn’t just say the content was identical; even the page structure was exactly the same. I’ve seen scrapers and I’ve seen people referencing my work, but I’ve never seen an entire site being reverse-proxied like this before…


# At First

At first, I thought they had just scraped and downloaded the site, and I wasn’t going to care. But later I realized they were directly reverse proxying it using Cloudflare Workers, and they had even modified the host header. Because of this, standard anti-hotlinking measures were basically useless…

After some Googling, I found out that this kind of situation can be handled using a JavaScript script.

In the beginning, I just used JS to verify if the window’s domain was correct. If it wasn’t, it would automatically redirect to the correct domain.

The code is as follows. Please put it inside the <head> tag:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
const validDomains =[
 'blog.xpdbk.com',
 'vlblog.xpdbk.com',
 'lelfeng.netlify.app',
 'cfblog.xpdbk.com', 
'1x000.github.io',
 'adaewfd321fg3.cachefly.net',
 '127.0.0.1:1313',
 'localhost:1313'
] 
try {  
 if (validDomains.indexOf(document.location.hostname +':'+ document.location.port) === -1) {
 window.location.href = 'http://blog.xpdbk.com';
 }
} catch(e) {}

However, this guy didn’t play by the rules. Through the reverse proxy, he replaced all the domains in the files with his own domain, which resulted in an infinite loop.

Later, I used https://obfuscator.io/ to obfuscate the JS code. This successfully prevented the domains from being modified and replaced.

The obfuscated sample code is as follows:

1
const _0x43eb42=_0x27a7;(function(_0xafca11,_0x40b2b8){const _0x35c55e=_0x27a7,_0x15b338=_0xafca11();while(!![]){try{const _0x517e5b=parseInt(_0x35c55e(0x188))/0x1*(parseInt(_0x35c55e(0x196))/0x2)+-parseInt(_0x35c55e(0x189))/0x3+-parseInt(_0x35c55e(0x18c))/0x4+parseInt(_0x35c55e(0x194))/0x5+parseInt(_0x35c55e(0x1a6))/0x6+-parseInt(_0x35c55e(0x19c))/0x7*(parseInt(_0x35c55e(0x1a3))/0x8)+-parseInt(_0x35c55e(0x19a))/0x9*(-parseInt(_0x35c55e(0x19d))/0xa);if(_0x517e5b===_0x40b2b8)break;else _0x15b338['push'](_0x15b338['shift']());}catch(_0x6c5198){_0x15b338['push'](_0x15b338['shift']());}}}(_0x17e0,0x5e4df));const _0x130d92=(function(){let _0x2e53a6=!![];return function(_0x323b74,_0x490435){const _0x1c497f=_0x2e53a6?function(){if(_0x490435){const _0x33bf80=_0x490435['apply'](_0x323b74,arguments);return _0x490435=null,_0x33bf80;}}:function(){};return _0x2e53a6=![],_0x1c497f;};}()),_0x4b63bb=_0x130d92(this,function(){const _0x982257=_0x27a7;return _0x4b63bb[_0x982257(0x184)]()[_0x982257(0x192)](_0x982257(0x198))[_0x982257(0x184)]()[_0x982257(0x19f)](_0x4b63bb)[_0x982257(0x192)](_0x982257(0x198));});_0x4b63bb();const _0x3f0a06=(function(){let _0x2f2ee3=!![];return function(_0xf1a2dc,_0x12daa7){const _0x2c78dc=_0x2f2ee3?function(){if(_0x12daa7){const _0x1e1bbf=_0x12daa7['apply'](_0xf1a2dc,arguments);return _0x12daa7=null,_0x1e1bbf;}}:function(){};return _0x2f2ee3=![],_0x2c78dc;};}()),_0x11b84d=_0x3f0a06(this,function(){const _0x5958bf=_0x27a7;let _0x1c1520;try{const _0x48284c=Function(_0x5958bf(0x18d)+_0x5958bf(0x18a)+');');_0x1c1520=_0x48284c();}catch(_0x560e71){_0x1c1520=window;}const _0x4777cb=_0x1c1520['console']=_0x1c1520[_0x5958bf(0x1a5)]||{},_0x10f092=[_0x5958bf(0x1a4),_0x5958bf(0x1a0),_0x5958bf(0x187),_0x5958bf(0x18b),_0x5958bf(0x19b),_0x5958bf(0x193),_0x5958bf(0x185)];for(let _0x41e094=0x0;_0x41e094<_0x10f092[_0x5958bf(0x190)];_0x41e094++){const _0xa11f57=_0x3f0a06[_0x5958bf(0x19f)][_0x5958bf(0x197)]['bind'](_0x3f0a06),_0x5853a5=_0x10f092[_0x41e094],_0x418439=_0x4777cb[_0x5853a5]||_0xa11f57;_0xa11f57[_0x5958bf(0x1a1)]=_0x3f0a06['bind'](_0x3f0a06),_0xa11f57[_0x5958bf(0x184)]=_0x418439[_0x5958bf(0x184)]['bind'](_0x418439),_0x4777cb[_0x5853a5]=_0xa11f57;}});_0x11b84d();const validDomains=[_0x43eb42(0x191),_0x43eb42(0x195),_0x43eb42(0x18e),_0x43eb42(0x18f),_0x43eb42(0x19e),'adaewfd321fg3.cachefly.net',_0x43eb42(0x186),'localhost:1313'];function _0x27a7(_0x30b2be,_0x27f11a){const _0x2f8ec1=_0x17e0();return _0x27a7=function(_0x11b84d,_0x3f0a06){_0x11b84d=_0x11b84d-0x183;let _0x2ded53=_0x2f8ec1[_0x11b84d];return _0x2ded53;},_0x27a7(_0x30b2be,_0x27f11a);}function _0x17e0(){const _0x30092e=['__proto__','http://blog.xpdbk.com','248mjjPBK','log','console','2331390Rbmidg','location','toString','trace','127.0.0.1:1313','info','1hGmVnj','511494uNxHBt','{}.constructor(\x22return\x20this\x22)(\x20)','error','1689000vVCMXN','return\x20(function()\x20','lelfeng.netlify.app','cfblog.xpdbk.com','length','blog.xpdbk.com','search','table','2697315oyIMgb','vlblog.xpdbk.com','405444fEnPtY','prototype','(((.+)+)+)+$','hostname','422352iCyGvT','exception','119035WNGFBa','80LiPhiY','1x000.github.io','constructor','warn'];_0x17e0=function(){return _0x30092e;};return _0x17e0();}try{validDomains['indexOf'](document[_0x43eb42(0x183)][_0x43eb42(0x199)]+':'+document[_0x43eb42(0x183)]['port'])===-0x1&&(window[_0x43eb42(0x183)]['href']=_0x43eb42(0x1a2));}catch(_0x573349){}

By taking this encrypted code and randomly inserting it into one of the scripts referenced on your site, you’ll leave the trash running those mirror sites with no way to bypass it.

With this, the problem is basically solved. Let those jerks go cry about it.