अपने ship किए गए JavaScript में paywall bypass रोकें

Bundle में paywall gate एक नामित function है जो boolean लौटाता है, और उसे पलटना एक पंक्ति का patch है। Obfuscation और per-build seed उसे ढूँढने और patch को काम करता रखने के बारे में क्या बदलते हैं।

Browser में चलने वाला paywall या entitlement check ढूँढने और patch करने में तभी महँगा होता है जब आप उसे ऐसा बनाते हैं। Minified output उसे इनमें से कुछ भी नहीं बनाता।

Paywall gate एक पंक्ति का patch क्यों है

सादे या minified output में paywall gate आमतौर पर एक नामित function होता है जो boolean लौटाता है। Bundle पढ़ने वाला कोई भी उस शब्द को search कर सकता है जो उसका नाम है: isSubscribed, hasAccess, checkEntitlement। मिल जाने के बाद सबसे सस्ता हमला एक पंक्ति का patch है जो return value को पलट देता है।

वह patch हर user की फ़ाइल की copy पर काम करता है, और अगर फ़ाइल का आकार नहीं बदला तो आपकी अगली release पर भी काम करता रहता है। Gate ढूँढने की मेहनत एक बार चुकाई जाती है और उसके बाद की हर build पर दोबारा इस्तेमाल होती है।

Build के बाद ship की गई फ़ाइल कैसी दिखती है

Default build identifiers को rename करती है और string literals को encode करती है, इसलिए जिस function का नाम पहले isSubscribed था उसके पास अब वह नाम नहीं रहता और उसके आसपास की strings अब पढ़ने योग्य text नहीं रहतीं। Ship की गई फ़ाइल में नाम या message search करने पर patch करने को कुछ नहीं मिलता।

यहाँ सबसे अहम गुण per-build polymorphism है। Seed हर build पर नया होता है जब तक आप उसे pin न करें, इसलिए एक release के ख़िलाफ़ लिखा patch अगली release से मेल नहीं खाता। जो attacker पता लगा लेता है कि gate कहाँ है, उसे हर बार आपके ship करने पर वह लागत फिर से चुकानी पड़ती है।

Gate पर protection बढ़ाएँ

Default preset पहले से ही कम complexity target पर rename और encode करता है। पूरे bundle को एक पायदान ऊपर ले जाने के लिए:

$ npx afterpack@latest dist/ --preset=hard

बाकी bundle को छुए बिना केवल gating function को ऊपर ले जाने के लिए, उसे एक directive से mark करें:

/* @afterpack preset=hard */
function checkEntitlement(token: string): boolean {
  return validateSubscription(token);
}
/* @afterpack end */

Directives Pro builds पर प्रभावी होते हैं।

जाँचें कि gate protected निकला

Build के बाद Protection Map खोलें और gating function ढूँढें। उसका रंग आसपास के code से ज़्यादा मज़बूत होना चाहिए, जो उस region के लिए आपके सेट किए ऊँचे complexity target को दर्शाता है। अगर वह बाकी bundle जैसा ही दिखता है, तो build के diagnostics पढ़ें: जो directive पढ़ा गया लेकिन जिसका कोई असर नहीं हुआ, वह वहाँ report होता है।

Client-side gate की सीमा कहाँ है

इसका टिकाऊ हिस्सा per-build rotation है। हर release पर नए seed का मतलब है कि gate ढूँढने और patch करने की मेहनत कभी आगे नहीं जाती, इसलिए एक build के ख़िलाफ़ लिखा patch, script या userscript अगली build पर लागू नहीं होता। एक अकेली build पर काम करने वाला static reader फिर भी एक equivalent computation recover कर सकता है, क्योंकि gate को browser में सही ढंग से चलना ही होता है, इसलिए revenue को gate करने वाली किसी भी चीज़ के लिए client-side check के साथ server-side entitlement call भी रखें।

आगे