एक 'read-only' अकाउंटेंट ओपन-सोर्स बुककीपिंग टूल Akaunting में इनवॉइस (invoices) को रद्द कर सकता था और भुगतान इतिहास (payment history) को मिटा सकता था, जिससे छोटे व्यवसाय डेटा के चुपचाप होने वाले नुकसान के जोखिम में आ सकते थे। इस खामी को वर्ज़न 3.2.0 में ठीक (patch) कर दिया गया था, लेकिन यह गलती—अनुमति जाँच (permission checks) को मेथड नामों की एक हार्ड-कोडेड सूची से जोड़ना—अभी भी उन सभी सिस्टम्स के लिए खतरा है जो रोल-आधारित एक्सेस कंट्रोल (role-based access control) पर निर्भर करते हैं।
बग कैसे निकल गया
Akaunting का API मेथड नामों की एक 'allowlist' का उपयोग करके उपयोगकर्ता के अधिकारों को सत्यापित करता है। इस सूची में सामान्य CRUD ऑपरेशन्स—create, read, update, delete—शामिल थे, लेकिन कई स्टेटस बदलने वाले एंडपॉइंट्स (endpoints) छूट गए थे:
markSentmarkCancelledmarkReceived
क्योंकि वे हैंडलर्स सूची में नहीं थे, इसलिए जब वे चलते थे, तो फ्रेमवर्क कभी भी अनुमति-जाँच (permission-checking) रूटीन को कॉल नहीं करता था। 'read-only' रोल वाले उपयोगकर्ता markCancelled एंडपॉइंट पर एक साधारण GET रिक्वेस्ट भेज सकता था और सिस्टम इसे एक वैध स्टेट चेंज (state change) के रूप में मान लेता था।
किसी इनवॉइस को रद्द करने का मतलब केवल दस्तावेज़ को अमान्य (void) घोषित करना नहीं है; यह उस इनवॉइस से जुड़े किसी भी भुगतान रिकॉर्ड को भी हटा देता है। परिणाम यह होता है: बिना एडिट अधिकार वाला उपयोगकर्ता किसी लेनदेन के वित्तीय विवरण (financial trail) को मिटा सकता है।
टेस्टिंग में क्या दिखा
यह भेद्यता (vulnerability) Akaunting के आधिकारिक Docker इमेज में दिखाई दी:
- इनवॉइस अपडेट करने के लिए एक मानक PUT रिक्वेस्ट ने 403 Forbidden रिटर्न किया, जिससे पुष्टि हुई कि नियमित अपडेट पाथ सुरक्षित था।
- कैंसलेशन एंडपॉइंट पर एक GET रिक्वेस्ट बिना किसी ऑथराइजेशन एरर के सफल रही, जिससे यह कमी उजागर हो गई।
यह क्यों महत्वपूर्ण है
वित्तीय विवरणों (financial statements) को बिना किसी स्पष्ट ऑडिट ट्रेल के बदला जा सकता है, जिससे धोखाधड़ी का पता लगाना और ईमानदार गलतियों को सुधारना कठिन हो जाता है।
समाधान
वर्ज़न 3.2.0 अनुमति मैप (permission map) का विस्तार करता है ताकि पहले छूटे हुए स्टेटस एक्शन को शामिल किया जा सके। उस रिलीज़ के बाद से, कोई भी रिक्वेस्ट जो दस्तावेज़ की स्थिति (state) बदलती है—चाहे उसे sent, cancelled, या received के रूप में मार्क किया गया हो—उसे एक मानक अपडेट की तरह ही उसी रोल वेरिफिकेशन से गुजरना होगा। इससे यह अपेक्षा फिर से बहाल होती है कि 'read-only' रोल वास्तव में डेटा को संशोधित नहीं कर सकता।
डेवलपर्स के लिए सबक
- मेथड नामों को कभी भी सुरक्षा के बराबर न समझें। एक नया एंडपॉइंट जोड़ने से उसे स्वचालित रूप से सुरक्षा नहीं मिलती; साइड इफेक्ट्स के लिए प्रत्येक पब्लिक मेथड का ऑडिट करें।
- Allowlists केवल उतनी ही पूर्ण होती हैं जितनी कि स्वयं सूची। "अच्छे" वर्ब्स (verbs) की एक स्थिर सूची चूक (oversights) के लिए रास्ता खुला छोड़ देती है।
- इरादे (intent) को HTTP verb से अलग रखें। GET केवल पढ़ने (read-only) के लिए होता है, लेकिन यहाँ इसने स्टेट चेंज किया। म्यूटेशन (mutations) को केवल POST, PUT, DELETE, PATCH तक ही सीमित रखें।
- परमिशन कवरेज चेक को ऑटोमेट करें। स्टैटिक एनालिसिस टूल्स उन कंट्रोलर मेथड्स को फ्लैग कर सकते हैं जिनमें ऑथराइजेशन कॉल की कमी है, जिससे शिपिंग से पहले ही कमियों को पकड़ा जा सकता है।
- न्यूनतम-विशेषाधिकार (least-privilege) वाले खातों के साथ टेस्ट करें। Docker-आधारित टेस्ट में 'read-only' यूजर का उपयोग किया गया था; CI पाइपलाइनों में ऐसे परिदृश्यों को दोहराने से समान समस्याएँ जल्दी सामने आ जाती हैं।
आगे क्या देखें
Akaunting के समुदाय ने पहले ही पैच किया हुआ वर्ज़न रिलीज़ कर दिया है। एडमिनिस्ट्रेटर्स को अपने इंस्टेंस के वर्ज़न की जाँच करनी चाहिए और तुरंत अपडेट लागू करना चाहिए।
किसी भी रोल-आधारित सिस्टम को बनाने वाले डेवलपर्स के लिए सबक स्पष्ट है: एक ऐसा परमिशन मॉडल जो हर संभव क्रिया को याद रखने पर निर्भर करता है, वह डिज़ाइन के मामले में कमज़ोर (fragile) होता है। स्पष्ट रूप से घोषित करें कि कौन से ऑपरेशन्स स्टेट को संशोधित करते हैं, फ्रेमवर्क स्तर पर जाँच लागू करें, और नियमित रूप से कोडबेस का ऑडिट करें। तभी "read-only" लेबल पर वित्तीय रिकॉर्ड को सुरक्षित रखने के लिए भरोसा किया जा सकता है।
