# JavaScript obfuscation की best practices

डिफ़ॉल्ट रूप से obfuscated JavaScript कैसे ship करें, अहम regions को directives से कैसे mark करें, और अपनी build को rotate करते रहें ताकि attackers आगे न निकल सकें।

Source: https://www.afterpack.dev/hi/docs/best-practices

## Web apps ship करते समय obfuscation डिफ़ॉल्ट होना चाहिए

आपके ship किए JavaScript में जो कुछ भी है, वह पढ़ा जा सकता है। Secrets, business logic, वह algorithm जिस पर आप निर्भर हैं: कोई भी bundle खोल सकता है, और कहने पर एक frontier LLM उसे लाइन-दर-लाइन समझा देगा। [Security scanner](https://www.afterpack.dev/hi/security-scanner) ठीक-ठीक दिखाता है कि एक असली production bundle से क्या निकलता है। इसे अपने bundle पर चलाकर देखें कि आप पहले से क्या दे रहे हैं।

उस bundle को obfuscate करने से ठोस, जाँचे जा सकने वाले गुण मिलते हैं:

- **आपके app के लिए लिखा patch आपकी releases के बाद टिक नहीं पाता।** आपके app को customize या automate करने वाले userscript, Tampermonkey script या extension को किसी स्थिर चीज़ पर टिकना पड़ता है: function का नाम, literal string, या कोई पहचाना जा सकने वाला आकार। Renaming और string encoding इन anchors को हटा देते हैं, और एक [नया seed](https://www.afterpack.dev/hi/docs/config#seed) हर build पर output का आकार बदल देता है। लेखक patch को एक release के लिए लिखता है; वह अगली release से match नहीं करता, और जिन users तक उसने उसे पहुँचाया, उनके पास फिर से लिखे जाने तक एक टूटी हुई script रह जाती है।
- **आपके code पर find-and-replace को match करने के लिए कुछ नहीं मिलता।** Simple text substitution, जो किसी web app को automate करने या बदलने का सबसे सस्ता तरीका है, `isSubscribed` और `"Upgrade to continue"` पर काम करता है। इनमें से कोई भी string आपकी ship की गई फ़ाइल में नहीं है।
- **आपकी strings पढ़ने योग्य text नहीं रहतीं।** String literals encode होते हैं, इसलिए किसी key, endpoint या किसी gate के आसपास के text के लिए `grep` कुछ नहीं लौटाता, और bundles को बड़े पैमाने पर पढ़ने वाले scanners और scrapers भी कुछ नहीं पाते। `light` पर numbers पढ़ने योग्य रहते हैं; `medium` और उससे ऊपर ज़्यादातर integers भी encode होते हैं।
- **Output एक नया आकार दिया गया program है।** AfterPack logic को ऐसे [समकक्ष](https://www.afterpack.dev/hi/docs/semantic-contract) रूपों में फिर से लिखता है जिन्हें आम tools वापस नहीं समेट पाते। Artifact पर मेहनत करने वाला reader एक काम करने वाला program recover कर सकता है, लेकिन केवल असली मेहनत के बाद, और नई build का मतलब है कि पिछली build के लिए लिखा गया tool अब मेल नहीं खाता।
- **लागत बार-बार आती है।** हर build की बनावट अलग होती है, इसलिए पिछली release के patterns के लिए लिखा गया tool या patch इस पर टूट जाता है। Code से कोई जो values पढ़ चुका है, वे पढ़ी जा चुकी रहती हैं।

इनमें से कुछ भी गारंटी नहीं है, और यह server-side authority का विकल्प नहीं है। कोई भी client code कुछ हद तक reverse किया जा सकता है, क्योंकि runtime को उसे चलाना ही पड़ता है। जो बदलता है वह उसे बदलने की कीमत है: एक build के patterns के लिए लिखा गया patch या tool अगली build पर टूट जाता है। इस पेज का बाकी हिस्सा बताता है कि उस सुरक्षा को वहाँ कैसे लगाएँ जहाँ उसकी अहमियत है।

## अपनी build rotate करें, attackers से आगे रहें

एक अकेली obfuscated release एक स्थिर निशाना है, जिसके हिसाब से captcha-breaker, cheat extension या scraper पर्याप्त मेहनत से ख़ुद को ढाल सकता है। हर build पर [एक नया seed](https://www.afterpack.dev/hi/docs/config#seed) डिफ़ॉल्ट है, इसलिए हर build की बनावट अलग होती है, और एक build के patterns के लिए लिखे गए tools अगली पर टूट जाते हैं। आपका code चलाने वाला व्यक्ति फिर भी उसमें इस्तेमाल होने वाली values पढ़ सकता है।

अगर आप कम ही ship करते हैं, तो releases के बीच यह बचाव ठहर जाता है। Code बदलावों से स्वतंत्र, schedule पर एक rebuild जोड़ें, ताकि deployed bundle फिर भी rotate होता रहे; [Build & CI](https://www.afterpack.dev/hi/docs/builds#rotate-on-a-schedule) इसे pipeline में wire करता है।

## एक preset चुनें, फिर जो अहम है उसे mark करें

डिफ़ॉल्ट preset [`light`](https://www.afterpack.dev/hi/docs/config#preset) है ([complexity target](https://www.afterpack.dev/hi/docs/config#complexity) 5): यह string literals को encode करता है, identifiers को rename करता है और syntax को दोबारा लिखता है, और कोई संरचनात्मक layer नहीं जोड़ता। पूरे app bundle के लिए यही सही preset है। इसे globally बढ़ाने से आपके pages जितना JavaScript load करते हैं और उनका startup समय, दोनों कई गुना हो जाते हैं ([load लागत](https://www.afterpack.dev/hi/docs/presets#load-cost)), इसलिए global `medium` या उससे ऊपर ship करने से पहले अपने pages ख़ुद मापें:

```bash
npx afterpack@latest dist/ --preset=hard
```

सीढ़ी है `minify` (0), `light` (5), `medium` (7), `hard` (12), `extreme` (25); देखें [Presets](https://www.afterpack.dev/hi/docs/presets)। [`--complexity=<number>`](https://www.afterpack.dev/hi/docs/config#complexity) उस target को override करता है जो preset साथ लाता है: `--preset=hard --complexity=40` target 40 पर `hard` है। इस तरह सेट किया गया मान हर token पर लागू होता है, `light` पर भी।

फिर, [Pro](https://www.afterpack.dev/hi/docs/tiers) पर, उन regions को mark करें जहाँ गलती सबसे महँगी पड़ती है, ताकि भारी treatment केवल वहीं लगे जहाँ वह अपनी load और size लागत के लायक है।

### Directive से किसी region को mark करें

```ts
/* @afterpack preset=hard */
function checkLicense(token: string): boolean {
  return verifySignature(token, PUBLIC_KEY);
}
/* @afterpack end */

const apiKey = /* @afterpack preset=extreme */ "YOUR_SECRET";
// only the rest of this line is covered
```

[Directives](https://www.afterpack.dev/hi/docs/directives) reference है: grammar, हर key जिसे एक directive सेट कर सकता है, [क्या mark करें और क्यों](https://www.afterpack.dev/hi/docs/directives#what-to-mark), और उस build में directive का क्या होता है जो उसे लागू नहीं कर सकती। Region overrides [Pro](https://www.afterpack.dev/hi/docs/tiers) builds पर प्रभावी होते हैं।

## दो anti-tamper transforms

Anti-tamper `preset=hard` का हिस्सा नहीं है। यह दो स्पष्ट Pro config flags हैं, दोनों डिफ़ॉल्ट रूप से बंद, और Free पर लागू नहीं होते:

- **[`transforms.comparisonHardening.enabled`](https://www.afterpack.dev/hi/docs/config#transforms-kind-enabled)** किसी build-time string literal के साथ strict equality (`x === "LIT"`) को एक one-way digest check में फिर से लिखता है, ताकि literal artifact में बिल्कुल मौजूद न रहे। इसे हर उस check के लिए इस्तेमाल करें जो ऐसे constant से तुलना करता है जिसे आप grep होकर बाहर आने नहीं देना चाहते।
- **[`transforms.selfIntegrity.enabled`](https://www.afterpack.dev/hi/docs/config#transforms-kind-enabled)** अपनी ही check table पर एक check जोड़ता है। बिना छेड़छाड़ के, behavior पर इसका कोई असर नहीं होता। यह केवल उस table में किए गए बदलाव को पकड़ता है; आपके code में कहीं और किया गया बदलाव नहीं पकड़ा जाता। इसे जुड़ने के लिए `medium` या उससे ऊपर का code चाहिए, इसलिए `light` build में यह केवल उसी region के अंदर होता है जिसे उस स्तर तक बढ़ाया गया हो। Engine 0.2.3 से, ऐसे code के बिना build [`DIAG_SELF_INTEGRITY_INERT`](https://www.afterpack.dev/hi/docs/diagnostics#complete-reference) के साथ fail होती है, बिना check के ship होने के बजाय।

दोनों को पूरे program के लिए सेट करें। देखें [Configuration](https://www.afterpack.dev/hi/docs/config#transforms-kind-enabled)।

## Domain-locked license या trial को protect करें

AfterPack में कोई built-in domain-lock या expiry transform नहीं है। Check आप ख़ुद लिखें, और AfterPack आपके लिखे JavaScript को protect करता है। Trial expiry के साथ per-domain license check के लिए:

```js
/* @afterpack preset=hard */
if (location.hostname !== "customer-domain.example.com") return;
if (Date.now() > TRIAL_EXPIRES_AT) return;
/* @afterpack end */
```

`transforms.comparisonHardening.enabled` चालू होने पर `location.hostname` की तुलना एक digest check बन जाती है, इसलिए अनुमत host artifact में कभी नहीं दिखता। Domain के लिए `grep` कुछ नहीं पाता। [`preset=hard`](https://www.afterpack.dev/hi/docs/config#preset) आसपास के logic को constants floor चालू रखते हुए complexity target 12 पर रखता है, और एक नया seed हर release पर उसका आकार बदल देता है।

> **Note**
>
> यह check को patch करने की लागत और आवृत्ति बढ़ाता है; यह check को attack surface से नहीं हटाता। Code चलाने वाला एक दृढ़ attacker अब भी तुलना को ढूँढकर patch कर सकता है, लेकिन उसे यह काम हर release पर फिर से करना पड़ता है। इसे trial में रुकावट मानें, और असली revenue को gate करने वाले हर check के साथ server-side entitlement call जोड़ें।

## Third-party code पर सुरक्षा बर्बाद न करें

Vendor bundles, जैसे React, Lodash, या कोई CSS-in-JS runtime, को ज़्यादा सुरक्षा की ज़रूरत नहीं। वे पहले से public हैं, आपका bundle फुलाते हैं, और अक्सर runtime reflection इस्तेमाल करते हैं जिसे acknowledge करना पड़ता है।

> **`paths.exclude` फ़ाइल-स्तर पर अलग रखने का तरीका है**
>
> [`paths.exclude`](https://www.afterpack.dev/hi/docs/config#paths-exclude) मेल खाने वाली फ़ाइल को parse होने से पहले ही पूरी तरह छोड़ देता है और उसे byte-दर-byte वैसे ही लौटाता है। Exclude की गई फ़ाइल `DIAG_PATH_EXCLUDED` के रूप में रिपोर्ट होती है। यह फ़ाइल स्तर पर काम करता है: जब कोई library build आपके code और किसी dependency को एक ही output फ़ाइल में जोड़ देती है, तो exclude करने के लिए अलग फ़ाइल नहीं होती। इसके बजाय [`identifiers.reserved`](https://www.afterpack.dev/hi/docs/config#identifiers-reserved) का उपयोग करें।

AfterPack क्या देखे, यह चुनने के चार तरीके:

- **फ़ाइल को exclude करें** [`paths.exclude`](https://www.afterpack.dev/hi/docs/config#paths-exclude) से, उदाहरण के लिए `["**/*.min.js", "dist/vendor/**"]`। `*` और `?` एक path segment के अंदर match करते हैं, पूरा `**` segment शून्य या अधिक segments से match करता है, और matching case-sensitive है।
- **CLI को उस directory पर चलाएँ जिसे आप protect करना चाहते हैं।** यह build directory में recursively जाता है और मिलने वाली हर `.js`/`.mjs`/`.cjs` फ़ाइल लेता है, nested `node_modules/` (इसे [`paths.include`](https://www.afterpack.dev/hi/docs/config#paths-include) से शामिल करें) और अपनी `.backup.<hash>` copies को छोड़कर। उस directory के बाहर का vendor chunk कभी नहीं छुआ जाता।
- **Vendor code को अपने bundler में एक अलग chunk में बाँटें**, फिर AfterPack को ऐसी directory पर चलाएँ जिसमें वह न हो। अगर आप लागत स्वीकार करना पसंद करें, तो vendor chunk भी ठीक से obfuscate हो जाता है।
- **Regions को [`skip`](https://www.afterpack.dev/hi/docs/config#skip) से mark करें** जहाँ किसी bundled dependency का code आपके code वाली फ़ाइल में ही है और उसे पहचानने योग्य रहना है।

आपके imports फिर भी resolve होते हैं।

AfterPack ES2022 private class fields और methods को पूरी तरह support करता है: `#field` और `#method()` सही ढंग से parse होते हैं और बाकी सब की तरह rename और protect होते हैं।

## जो पढ़ने योग्य रहना चाहिए, उसे बचाएँ

Runtime के काम करने के लिए कुछ code को अपने मूल नाम रखने पड़ते हैं। [Framework presets](https://www.afterpack.dev/hi/docs/config#reflection-allow) आम मामलों को कवर करते हैं। बाकी के लिए, सीमित दायरे में बचाएँ। Renaming को कभी globally बंद न करें, वरना आप अपने पूरे bundle में सुरक्षा की सबसे सस्ती layer गँवा देते हैं।

| स्थिति | क्या करें |
| --- | --- |
| Public exports जिन्हें callers नाम से import करते हैं | Export के चारों ओर `/* @afterpack skip */ … /* @afterpack end */`, या नामों को [`identifiers.reserved`](https://www.afterpack.dev/hi/docs/config#identifiers-reserved) से pin करें |
| Stack traces जिन्हें आप सच में debug करते हैं | Deploy tree से बाहर रखे source maps से symbolicate करें। [`identifiers.rename=false`](https://www.afterpack.dev/hi/docs/config#identifiers-rename) पूरे bundle में हर identifier को ज्यों का त्यों रखता है |
| Reflection-आधारित DI ([Angular](https://www.afterpack.dev/hi/docs/frameworks/angular), NestJS, Inversify) | किसी custom pattern को acknowledge करने के लिए config में [`reflection.allow`](https://www.afterpack.dev/hi/docs/config#reflection-allow); acknowledge न किया गया pattern एक build error है |
| `instanceof` / class-name के आधार पर switching | Class names के साथ `identifiers.reserved`, या declaration के चारों ओर [`/* @afterpack skip */`](https://www.afterpack.dev/hi/docs/config#skip) |
| आपके अपने code वाली फ़ाइल में ही bundled third-party API symbols (जैसे Rollup/Vite library build जो किसी dependency को inline करती है) | [`identifiers.reserved`](https://www.afterpack.dev/hi/docs/config#identifiers-reserved), पूरी build के लिए सादे नाम के साथ या मेल खाने वाली फ़ाइलों के लिए `{ glob, names }` entry के साथ |
| ऐसी script जिसमें बाहर से कुछ call नहीं करता | [`identifiers.globals.rename: true`](https://www.afterpack.dev/hi/docs/config#identifiers-globals-rename)। उस ambient global surface की renaming चालू करता है जिसे engine वरना बचाए रखता है। डिफ़ॉल्ट रूप से बंद, और केवल तब सुरक्षित जब बाहर का कुछ भी उन नामों को नहीं पढ़ता |

`identifiers.reserved` केवल आपके सूचीबद्ध नामों को बचाता है, वे जहाँ भी दिखें, किसी भी renaming से पहले source में लिखे नाम से match करके: exact, पूरा identifier, case-sensitive। Free पर उपलब्ध। इसका उपयोग तब करें जब आप पूरा region mark नहीं कर सकते, क्योंकि आपका code और कोई vendored dependency एक ही फ़ाइल में हैं।

नामों को केवल एक जगह बचाए रखने के लिए `identifiers.reserved` या [`/* @afterpack skip */`](https://www.afterpack.dev/hi/docs/config#skip) का उपयोग करें; देखें [आप क्या सेट कर सकते हैं](https://www.afterpack.dev/hi/docs/directives#what-you-can-set)।

हर ऐसा बचाव उन लाइनों पर सुरक्षा घटाता है। इसे केवल वहीं लागू करें जहाँ runtime को इसकी ज़रूरत है।

## Seed strategy

[Seed](https://www.afterpack.dev/hi/docs/config#seed) obfuscated output का आकार तय करता है। हर build पर random seed डिफ़ॉल्ट है। Production के लिए इसे ऐसा ही रहने दें: हर release पर बदलने वाली build मुख्य बचाव है।

Seed को ठीक एक जगह pin करें: CI में, जब cache hits या golden-snapshot tests के लिए आपको reproducible output चाहिए।

```bash
npx afterpack@latest dist/ --seed=git
```

[`--seed=git`](https://www.afterpack.dev/hi/docs/config#seed) seed को `git rev-parse HEAD` से निकालता है। Repository न होने पर यह build को विफल करने के बजाय एक नए random seed पर लौट आता है और एक notice print करता है। इससे output हर commit के लिए deterministic रहता है, फिर भी हर release पर rotate होता है।

Seed का एक environment variable भी है, [`AFTERPACK_seed`](https://www.afterpack.dev/hi/docs/config#seed), जिसके मान `--seed` वाले ही हैं। Multi-bundle builds अपने-आप एक seed साझा करती हैं, एक process के अंदर भी और इस variable के ज़रिए processes के पार भी। इसे ख़ुद केवल किसी खास build को reproduce करने के लिए सेट करें; स्पष्ट `--seed` या `seed` option फिर भी इस पर भारी पड़ता है।

Production को एक बार build करें और वही bytes qa → preprod → prod तक promote करें। Dev builds un-obfuscated होती हैं, इसलिए रोज़मर्रा का development अप्रभावित रहता है।

Production में constant seed ship न करें। इससे releases के बीच output का आकार बदलना बंद हो जाता है।

## Artifacts को deploy से बाहर रखें

AfterPack तीन तरह के local artifact लिखता है। हर एक उस bundle से ज़्यादा संवेदनशील है जिसका वह वर्णन करता है।

- **Protection Map** (`protectionMap.html`) में आपका मूल source embed होता है। चालू होने पर (डिफ़ॉल्ट रूप से केवल तब, जब build ने source map बनाया हो और वह CI में न चल रही हो, देखें [Protection Map](https://www.afterpack.dev/hi/docs/protection-map)), यह project root की gitignored [`.afterpack/`](https://www.afterpack.dev/hi/docs/cli#files) directory में लिखा जाता है, serve होने वाली build के साथ कभी नहीं, और [production build](https://www.afterpack.dev/hi/docs/config#build-mode) इसके चालू होने की चेतावनी देती है। इसे [`--protectionMap.enabled=false`](https://www.afterpack.dev/hi/docs/config#protectionMap-enabled) से बंद करें।
- **आपकी मूल फ़ाइलों का backup।** किसी फ़ाइल को उसी जगह फिर से लिखने से पहले CLI मूल फ़ाइल को `.afterpack/backups/` में copy करता है, साथ में एक manifest कि उसने हर फ़ाइल को किसमें obfuscate किया। वह directory ज्यों का त्यों आपका source है, build machine पर ही रहती है, और `npx afterpack@latest restore` मूल फ़ाइलें वापस रख देता है। [`--build.backup=false`](https://www.afterpack.dev/hi/docs/config#build-backup) से इसे बंद करें। Framework plugin डिफ़ॉल्ट रूप से कोई copy नहीं लिखता; वहाँ [`build.backup`](https://www.afterpack.dev/hi/docs/config#build-backup) को `true` करने पर इसके बजाय output के बगल में एक `.backup.<hash>` फ़ाइल लिखी जाती है, जहाँ वह build के साथ ship हो जाएगी।
- **Source maps** obfuscated output को सीधे मूल source तक वापस जोड़ते हैं। [`.map` फ़ाइल](https://www.afterpack.dev/hi/docs/config#sourceMap-enabled) production में डिफ़ॉल्ट रूप से बंद रहती है, और [`//# sourceMappingURL=` comment](https://www.afterpack.dev/hi/docs/config#sourceMap-emitUrl) भी production में डिफ़ॉल्ट रूप से बंद रहता है।

Plugins और CLI `.afterpack/` के अंदर एक `.gitignore` रखकर उसे git से बाहर रखते हैं, आपकी `.gitignore` में कभी बदलाव नहीं करते, और किसी artifact के serve होने वाले path के नीचे पहुँचने पर चेतावनी देते हैं। Build के बगल में मौजूद `.map` या `.backup.<hash>` फ़ाइल को git से बाहर रखना आपका काम है।

> **Source map या backup कभी deploy न करें**
>
> Source map या backup में आपका पूरा source होता है। इनमें से किसी को भी कभी deploy न करें।

Production build आपके bundler के लिखे source maps भी हटा देता है: `.map` files, hidden और inline maps, `sourceMappingURL` comments और CSS maps। CLI और हर plugin यह करते हैं, और जो map हटाया न जा सके वह build को fail कर देता है।

## Map publish किए बिना production traces debug करें

Production build न कोई `.map` लिखती है, न `//# sourceMappingURL=` comment, जो सही डिफ़ॉल्ट है, और इससे आपको stack traces हाथ से symbolicate करने पड़ते हैं। अगर आपकी team को production से असली traces चाहिए, तो map को छोड़ने के बजाय उसे build करें और private रखें।

Build के लिए map चालू करें और pointer बंद रखें, ताकि ship हुए JavaScript में कुछ भी यह न बताए कि कोई map मौजूद है:

```json
{
  "sourceMap": { "enabled": true, "emitUrl": false, "sourcesContent": true }
}
```

फिर `.map` फ़ाइलों को deployed directory से बाहर रखें: उन्हें अपने error tracker पर upload करें या CI artifact के रूप में रखें, और वहीं symbolicate करें। अगर आपका deploy पूरी build directory copy करता है, तो edge पर भी इन फ़ाइलों को deny करें, ताकि किसी के लिए request आने पर वह कभी न लौटे।

```nginx
location ~ \.map$ {
  return 404;
}
```

इसी नियम का समकक्ष हर जगह है: `*.map` से match करने वाला CDN या WAF नियम, proxy `deny`, या ऐसा storage bucket जिसमें ये फ़ाइलें कभी पहुँचती ही नहीं। अपने network के बाहर से `curl -I https://yoursite.example.com/assets/app.js.map` से इसे जाँचें, 404 की अपेक्षा के साथ, और [`npx afterpack@latest audit`](https://www.afterpack.dev/hi/docs/audit) से, जो पहुँच में आने वाले map को एक finding के रूप में रिपोर्ट करता है।

> **Denial नियम बचाव की दूसरी पंक्ति है, पहली नहीं**
>
> Edge नियम उन फ़ाइलों को protect करता है जो server पर हैं। जो कुछ भी उसे bypass करता है, जैसे गलत configure किया गया route, bucket का सीधा URL, या preview deployment, वह map को आपके मूल source समेत serve कर देता है। Maps को deploy न करना ही वह तरीका है जिसे गलत configure नहीं किया जा सकता।

## अगर आपने गलती से कोई secret ship कर दिया

आपके bundle तक पहुँची API key, token या password एक चालू incident है। AfterPack यह बदलता है कि reader को ship हुई फ़ाइल में क्या मिलता है। यह इस तथ्य को नहीं बदलता कि credential बाहर जा चुका है।

**AfterPack इसके साथ क्या करता है।** [डिफ़ॉल्ट preset](https://www.afterpack.dev/hi/docs/presets) पर string literals encode होते हैं, इसलिए किसी literal में रखी key आपकी deploy की गई फ़ाइल में पढ़ने योग्य नहीं होती। जो थोड़े-से literals हमेशा पढ़ने योग्य रहते हैं, उनकी सूची [Presets](https://www.afterpack.dev/hi/docs/presets#the-default-is-light) में है। Bundle में key, या उसके आसपास के text को खोजने पर कुछ नहीं मिलता। Automated secret scanners और bundle scrapers को भी कुछ नहीं मिलता, और ज़्यादातर leaked keys इन्हीं से पकड़ी जाती हैं।

**AfterPack क्या नहीं करता।** Credential अब भी build में है, और आपका code अब भी उसका उपयोग करता है। अपने नियंत्रण वाले browser में आपका application चलाने वाला कोई भी, code के उसका उपयोग करने के पल value तक पहुँच सकता है। Encoding आपको जवाब देने का समय देती है। यह client-side secret को सुरक्षित नहीं बनाती।

**क्या करें, इसी क्रम में:**

1. **Key को rotate करें।** जिस पल build बाहर गई, उसी पल से इसे compromised मानें। यही वह कदम है जो incident को बंद करता है।
2. **Authority को server-side ले जाएँ।** Credential आपका अपना backend रखे और वही तय करे कि किसी caller को नतीजा मिलना चाहिए या नहीं। जो key browser को कभी मिलती ही नहीं, वह leak नहीं हो सकती।
3. **जाँचें कि live क्या है।** अपनी deployed site पर [`npx afterpack@latest audit`](https://www.afterpack.dev/hi/docs/audit) चलाएँ। यह site के असल में serve किए JavaScript के लिए exposed secrets, leaked source maps और protection level रिपोर्ट करता है, ताकि आपको पता चले कि एक reader अभी production से क्या निकाल सकता है।
4. **Rebuild और redeploy करें**, ताकि पुरानी value वाला bundle serve होना बंद हो जाए।

> **Obfuscation rotation का विकल्प नहीं है**
>
> जो credential ship हो चुका है, उसे rotate करना ही होगा, चाहे उसे किसी भी preset ने build किया हो।

## Obfuscated build को test करें

अपने integration tests हमेशा obfuscated build पर चलाएँ। Obfuscation से पहले की build को test करने से आपको कुछ पता नहीं चलता कि क्या ship होता है।

जो test सादी build पर pass हुआ और obfuscated build पर fail हुआ, वह या तो बचाव में किसी कमी की ओर इशारा करता है (runtime को जिस नाम की अपेक्षा थी वह rename हो गया) या किसी अपरिचित reflection pattern की ओर। Diagnostic आमतौर पर उस config key का नाम बताता है जो इसे ठीक करती है। संक्षिप्त सारांश के बजाय हर [diagnostic](https://www.afterpack.dev/hi/docs/diagnostics) पूरा देखने के लिए [`--diagnostics.level=all`](https://www.afterpack.dev/hi/docs/config#diagnostics-level) के साथ चलाएँ।

> **Green build ही पूरा संकेत है**
>
> जो कुछ भी आपकी configure की गई सुरक्षा से कमज़ोर सुरक्षा ship करता, वह इसके बजाय build को रोक देता है, जिसमें वह फ़ाइल भी शामिल है जिसे engine obfuscate नहीं कर सकता और वह [Pro](https://www.afterpack.dev/hi/docs/tiers) build भी जो cloud तक नहीं पहुँच सकती। Exit contract और उसके पीछे का हर code [Diagnostics](https://www.afterpack.dev/hi/docs/diagnostics#exit-codes) में है।

## आगे

- [Build & CI](https://www.afterpack.dev/hi/docs/builds): वही bytes promote करने का lifecycle, artifact की साफ़-सफ़ाई, और समय-समय पर rebuilds।
- [Threat model](https://www.afterpack.dev/hi/docs/threat-model): attackers की वह सीढ़ी जिसके सापेक्ष ये directives तय किए गए हैं।
- [Configuration](https://www.afterpack.dev/hi/docs/config): हर config key एक जगह।
- [Directives](https://www.afterpack.dev/hi/docs/directives): ऊपर की तालिका के पीछे का पूरा region-marker grammar।
- [Presets](https://www.afterpack.dev/hi/docs/presets): पाँच-स्तरीय सीढ़ी जिसे ये directives हर region के लिए override करते हैं।
- [Protection Map](https://www.afterpack.dev/hi/docs/protection-map): जाँचें कि आपके mark किए regions पर वास्तव में कौन-सी class लगी।
- [Dashboard में builds](https://www.afterpack.dev/hi/docs/dashboard/builds): आपकी Pro Cloud builds के लिए, हर build के वही आँकड़े।
