WordPress .htaccess सिक्योरिटी रूल्स जो वाकई काम आते हैं
WordPress .htaccess सिक्योरिटी के नाम पर जो ज़्यादातर बेचा जाता है वो बस भरावट है। जो रूल्स सच में आपकी attack surface बदलते हैं वो छोटे हैं — यहाँ जानिए कौन सा क्या है
Published
“WordPress .htaccess security” के नाम पर जो ज़्यादातर बेचा जाता है वो सिर्फ़ भरावट है। जो रूल्स सच में आपकी attack surface बदलते हैं वो छोटे हैं: wp-content/uploads के अंदर PHP execution को ब्लॉक करना, wp-config.php तक सीधी पहुँच को deny करना, और directory indexing बंद करना। जो पॉपुलर हैं — xmlrpc.php को “brute force रोकने के लिए” ब्लॉक करना, अपना WordPress version छुपाना, 200 लाइन की bad-bot user-agent लिस्ट पेस्ट करना — वो हल्के-फुल्के फ़ायदे से लेकर पूरी तरह दिखावा तक हैं। नीचे बताया है कि कौन सा क्या है, और क्यों।
एक बात पहले साफ़ कर लें: .htaccess सिर्फ़ Apache पर कुछ करता है (और LiteSpeed पर, जो इसे भी पढ़ता है)। nginx पर इसे पूरी तरह नज़रअंदाज़ कर दिया जाता है — फ़ाइल बस वहीं पड़ी रहती है और आप समझते रहते हैं कि आप सुरक्षित हैं। अगर आपका host nginx चलाता है, तो इसमें से कुछ भी लागू नहीं होता और आपको उसकी जगह server/location ब्लॉक्स की ज़रूरत है। curl -I https://yoursite.com से चेक करें और किसी फ़ाइल को एक घंटा एडिट करने से पहले Server: header देख लें, जिसे सर्वर कभी पढ़ता ही नहीं।
असल में जो रूल मायने रखता है: /uploads में कोई PHP नहीं
यही एक करने लायक चीज़ है। wp-content/uploads डिज़ाइन से ही world-writable है — हर media upload, हर वो plugin जो कोई फ़ाइल सेव करता है, यहीं लिखता है। अगर कोई attacker इस directory में कोई .php फ़ाइल डाल दे (किसी vulnerable upload handler के ज़रिए, किसी image field से जो MIME type validate नहीं करता, या किसी compromised plugin से), तो एक छोटी-सी परेशानी और पूरे remote-code-execution compromise के बीच का फ़र्क़ बस इतना है कि रिक्वेस्ट आने पर सर्वर उस फ़ाइल को execute करेगा या नहीं। execution को deny कर दें और अपलोड किया गया payload बस डिस्क पर पड़ी एक बेकार फ़ाइल भर रह जाता है।
इसे wp-content/uploads/.htaccess में डालें (अगर फ़ाइल मौजूद नहीं है तो बना लें):
<FilesMatch "\.php$">
Require all denied
</FilesMatch>
यह Apache 2.4 सिंटैक्स है। पुराने 2.2 पर इसका समकक्ष Order Deny,Allow / Deny from all है। एक ही फ़ाइल में दोनों dialect मिला देना “hardening” के बाद अचानक 500 Internal Server Error आने की सबसे आम वजह है — अगर सेव करते ही पूरी साइट बैठ जाए, तो लगभग हमेशा यही कारण होता है। अपना version apachectl -v से चेक करें।
wp-config.php को प्रोटेक्ट करें
wp-config.php में आपके database credentials और auth salts होते हैं। जब तक PHP चल रहा है, इस पर सीधी रिक्वेस्ट एक खाली पेज लौटाती है — PHP फ़ाइल को प्रिंट करने के बजाय execute करता है। खतरा failure केस में है: अगर PHP कभी crash हो जाए, किसी migration के दौरान misconfigure हो जाए, या handler डिसेबल हो जाए, तो Apache फ़ाइल को plaintext में परोस देता है और जो भी माँगे उसे आपका DB password दिखा देता है। access को deny करना एक बुरे पाँच मिनट के ख़िलाफ़ सस्ता बीमा है:
<Files wp-config.php>
Require all denied
</Files>
Directory indexing बंद करें
अगर कोई ऐसे फ़ोल्डर पर जाए जिसमें कोई index.php नहीं है और Apache पर Options +Indexes ऑन है, तो वह उसका कंटेंट लिस्ट कर देता है — हर backup फ़ाइल, हर वो अटकी हुई SQL dump जिसे आप भूल गए थे। इसे पूरी साइट पर बंद कर दें:
Options -Indexes
गंभीरता कम है, पर असली है, और इसकी कोई क़ीमत नहीं।
यही ईमानदार core लिस्ट है। इन्हें आप — साथ में सही 2.4-बनाम-2.2 सिंटैक्स के साथ ताकि आप अपनी साइट को 500 न कर दें — किसी फ़ोरम पोस्ट से कॉपी-पेस्ट करने के बजाय (जो शायद ग़लत Apache version के लिए लिखी गई हो) WordPress .htaccess generator से बना सकते हैं।
क्या नहीं करना चाहिए
xmlrpc.php को “brute-force protection के लिए” ब्लॉक करना। यह वो बड़ी बात है जिसे हर कोई दोहराता है और जैसे कही जाती है वैसे ग़लत है। हाँ, XML-RPC का system.multicall method पहले किसी attacker को एक ही रिक्वेस्ट में कई login guesses बंडल करने देता था — असली amplification। लेकिन brute-force का सबसे आम रास्ता wp-login.php पर साधारण POST रिक्वेस्ट हैं, और xmlrpc.php को ब्लॉक करने से उसके लिए कुछ नहीं होता। Brute force को rate limiting, मज़बूत पासवर्ड और 2FA से हराया जाता है — एक endpoint को मारने से नहीं। XML-RPC को डिसेबल करने की एक जायज़ वजह ज़रूर है: इसका pingback feature DDoS reflection के लिए दुरुपयोग किया जा सकता है, तो अगर आप Jetpack, मोबाइल ऐप, या pingbacks इस्तेमाल नहीं करते, तो इसे बंद करने से आपकी attack surface सिकुड़ती है। बस ख़ुद को यह मत बताइए कि यह आपकी brute-force defense है, क्योंकि यह नहीं है।
अपना WordPress version छुपाना / generator tag हटाना। readme.html और <meta name="generator"> tag हटाना hardening जैसा महसूस होता है। एक attacker आपका version enqueued asset query strings, block-editor markup, और दर्जनों दूसरे संकेतों से सेकंडों में पहचान लेता है। आप कुछ छुपा नहीं रहे; आप बस ख़ुद को व्यस्त महसूस करा रहे हैं।
विशाल bad-bot user-agent और referrer blocklists। User agent एक अकेला spoof किया जा सकने वाला HTTP header है। ये लिस्ट जिस दिन आप पेस्ट करते हैं उसी दिन बासी हो जाती हैं, वे किसी काबिल attacker को कुछ नहीं रोकतीं, और Apache हर रिक्वेस्ट पर हर regex को evaluate करता है — आप शून्य सिक्योरिटी के लिए असली performance टैक्स चुका रहे हैं। इन्हें छोड़ दें।
wp-login.php को IP से लॉक करना। तब तक बढ़िया जब तक आपका ISP आपका address बदल न दे और आप अपने ही admin से बाहर लॉक न हो जाएँ। सिर्फ़ सच में static IP के साथ ही व्यवहारिक है।
Author-enumeration redirects (?author=1)। लोग इसके लिए जो .htaccess rewrite पेस्ट करते हैं वो अकेला अधूरा है — REST endpoint /wp-json/wp/v2/users फिर भी usernames लिस्ट करता है। एक रास्ता ब्लॉक करना जबकि दूसरा खुला रहे, दिखावा है।
अभी भी अटके हैं?
अगर कोई रूल साइट को 500 कर दे, तो यह सिंटैक्स की बात है — आपने जो आख़िरी ब्लॉक जोड़ा था उसे हटाएँ और reload करें; इससे वह तुरंत अलग हो जाता है। अगर कोई रूल कुछ करता ही न दिखे, तो पुष्टि करें कि आप सच में Apache पर हैं और उस directory के लिए AllowOverride इनेबल है (कई managed hosts इसे रोक देते हैं)। किसी जाने-पहचाने, सही template से फ़ाइल बनाएँ .htaccess generator के साथ, वो तीन रूल्स रखें जो मायने रखते हैं, और बाक़ी छोड़ दें।