PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

एप्लिकेशन उपयोगकर्ता बनाम पंक्ति स्तर सुरक्षा

कुछ दिनों पहले मैंने सुरक्षा समीक्षाओं के दौरान मिलने वाली भूमिकाओं और विशेषाधिकारों के साथ आम समस्याओं के बारे में ब्लॉग किया था।

बेशक, PostgreSQL सुरक्षा से संबंधित कई उन्नत सुविधाएँ प्रदान करता है, उनमें से एक पंक्ति स्तर सुरक्षा (RLS) है, जो PostgreSQL 9.5 के बाद से उपलब्ध है।

चूंकि 9.5 जनवरी 2016 में जारी किया गया था (इसलिए कुछ महीने पहले), आरएलएस काफी नई सुविधा है और हम वास्तव में अभी तक कई उत्पादन परिनियोजन से निपट नहीं रहे हैं। इसके बजाय आरएलएस "कैसे कार्यान्वित करें" चर्चाओं का एक सामान्य विषय है, और सबसे आम प्रश्नों में से एक यह है कि इसे एप्लिकेशन-स्तरीय उपयोगकर्ताओं के साथ कैसे काम किया जाए। तो आइए देखें कि क्या संभावित समाधान हैं।

आरएलएस का परिचय

आइए पहले एक बहुत ही सरल उदाहरण देखें, यह समझाते हुए कि आरएलएस क्या है। मान लें कि हमारे पास chat है उपयोगकर्ताओं के बीच भेजे गए संदेशों को संग्रहीत करने वाली तालिका - उपयोगकर्ता अन्य उपयोगकर्ताओं को संदेश भेजने के लिए इसमें पंक्तियाँ सम्मिलित कर सकते हैं, और अन्य उपयोगकर्ताओं द्वारा उन्हें भेजे गए संदेशों को देखने के लिए इसे क्वेरी कर सकते हैं। तो तालिका इस तरह दिख सकती है:

टेबल चैट बनाएं (Message_uuid UUID प्राथमिक कुंजी डिफ़ॉल्ट uuid_generate_v4(), message_time TIMESTAMP NOT NULL DEFAULT now(), message_from NAME NOT NULL DEFAULT current_user, message_to NAME NOT NULL, message_subject VARCHAR(64) NOT NULL, message_body टेक्स्ट /पूर्व> 

क्लासिक भूमिका-आधारित सुरक्षा केवल हमें पूरी तालिका या इसके लंबवत स्लाइस (कॉलम) तक पहुंच को प्रतिबंधित करने की अनुमति देती है। इसलिए हम इसका उपयोग उपयोगकर्ताओं को अन्य उपयोगकर्ताओं के लिए इच्छित संदेशों को पढ़ने, या नकली message_from के साथ संदेश भेजने से रोकने के लिए नहीं कर सकते। फ़ील्ड.

और ठीक यही आरएलएस के लिए है - यह आपको नियम (नीतियां) बनाने की अनुमति देता है जो पंक्तियों के सबसेट तक पहुंच को प्रतिबंधित करता है। तो उदाहरण के लिए आप यह कर सकते हैं:

चैट का उपयोग करके चैट पर नीति बनाएं ((message_to =current_user) या (message_from =current_user)) चेक के साथ (message_from =current_user)

यह नीति सुनिश्चित करती है कि उपयोगकर्ता केवल उसके द्वारा भेजे गए या उसके लिए अभिप्रेत संदेशों को ही देख सकता है - USING में यही शर्त है खंड करता है। पॉलिसी का दूसरा भाग (WITH CHECK ) आश्वासन देता है कि उपयोगकर्ता केवल message_from . में अपने उपयोगकर्ता नाम के साथ संदेश सम्मिलित कर सकता है कॉलम, जाली प्रेषक वाले संदेशों को रोकना।

आप अतिरिक्त WHERE शर्तों को जोड़ने के लिए एक स्वचालित तरीके के रूप में RLS की कल्पना भी कर सकते हैं। आप इसे एप्लिकेशन स्तर पर मैन्युअल रूप से कर सकते हैं (और आरएलएस से पहले लोग अक्सर ऐसा करते थे), लेकिन आरएलएस इसे विश्वसनीय और सुरक्षित तरीके से करता है (उदाहरण के लिए, विभिन्न सूचना लीक को रोकने में बहुत प्रयास किया गया था)।

नोट :आरएलएस से पहले, कुछ ऐसा ही हासिल करने का एक लोकप्रिय तरीका तालिका को सीधे पहुंच योग्य बनाना (सभी विशेषाधिकारों को रद्द करना) था, और इसे एक्सेस करने के लिए सुरक्षा निश्चित कार्यों का एक सेट प्रदान करना था। इसने ज्यादातर एक ही लक्ष्य हासिल किया, लेकिन कार्यों के कई नुकसान हैं - वे अनुकूलक को भ्रमित करते हैं, और लचीलेपन को गंभीरता से सीमित करते हैं (यदि उपयोगकर्ता को कुछ करने की आवश्यकता है और इसके लिए कोई उपयुक्त कार्य नहीं है, तो वह भाग्य से बाहर है)। और निश्चित रूप से, आपको उन कार्यों को लिखना होगा।

एप्लिकेशन उपयोगकर्ता

यदि आप आरएलएस के बारे में आधिकारिक दस्तावेज पढ़ते हैं, तो आप एक विवरण देख सकते हैं - सभी उदाहरण current_user का उपयोग करते हैं , यानी वर्तमान डेटाबेस उपयोगकर्ता। लेकिन ऐसा नहीं है कि इन दिनों अधिकांश डेटाबेस एप्लिकेशन कैसे काम करते हैं। कई पंजीकृत उपयोगकर्ताओं के साथ वेब एप्लिकेशन डेटाबेस उपयोगकर्ताओं के लिए 1:1 मैपिंग को बनाए नहीं रखते हैं, बल्कि क्वेरी चलाने और एप्लिकेशन उपयोगकर्ताओं को स्वयं प्रबंधित करने के लिए एकल डेटाबेस उपयोगकर्ता का उपयोग करते हैं - शायद users में। टेबल।

तकनीकी रूप से PostgreSQL में कई डेटाबेस उपयोगकर्ता बनाने में कोई समस्या नहीं है। डेटाबेस को बिना किसी समस्या के इसे संभालना चाहिए, लेकिन कई व्यावहारिक कारणों से एप्लिकेशन ऐसा नहीं करते हैं। उदाहरण के लिए उन्हें प्रत्येक उपयोगकर्ता (जैसे विभाग, संगठन के भीतर स्थिति, संपर्क विवरण,…) के लिए अतिरिक्त जानकारी को ट्रैक करने की आवश्यकता होती है, इसलिए एप्लिकेशन को users की आवश्यकता होगी। वैसे भी टेबल।

एक अन्य कारण कनेक्शन पूलिंग हो सकता है - एकल साझा उपयोगकर्ता खाते का उपयोग करना, हालांकि हम जानते हैं कि विरासत और SET ROLE का उपयोग करके इसे हल किया जा सकता है। (पिछली पोस्ट देखें)।

लेकिन मान लें कि आप अलग डेटाबेस उपयोगकर्ता नहीं बनाना चाहते हैं - आप एकल साझा डेटाबेस खाते का उपयोग करना चाहते हैं, और एप्लिकेशन उपयोगकर्ताओं के साथ RLS का उपयोग करना चाहते हैं। यह कैसे करें?

सत्र चर

अनिवार्य रूप से हमें डेटाबेस सत्र में अतिरिक्त संदर्भ पारित करने की आवश्यकता है, ताकि हम बाद में इसे सुरक्षा नीति (current_user के बजाय) से उपयोग कर सकें। चर)। और PostgreSQL में ऐसा करने का सबसे आसान तरीका सत्र चर हैं:

सेट my.username ='tomas'

यदि यह सामान्य कॉन्फ़िगरेशन पैरामीटर से मिलता-जुलता है (उदा. SET work_mem = '...' ), आप बिल्कुल सही हैं - यह ज्यादातर एक ही बात है। कमांड एक नए नेमस्पेस को परिभाषित करता है (my ), और एक username adds जोड़ता है इसमें परिवर्तनशील। नया नाम स्थान आवश्यक है, क्योंकि वैश्विक नाम सर्वर कॉन्फ़िगरेशन के लिए आरक्षित है और हम इसमें नए चर नहीं जोड़ सकते हैं। यह हमें सुरक्षा नीति को इस तरह बदलने की अनुमति देता है:

चैट का उपयोग करके चैट पर नीति बनाएं (current_setting('my.username') IN (message_from, message_to)) चेक के साथ (message_from =current_setting('my.username'))

हमें केवल यह सुनिश्चित करने की आवश्यकता है कि कनेक्शन पूल / एप्लिकेशन जब भी कोई नया कनेक्शन प्राप्त करता है तो उपयोगकर्ता नाम सेट करता है और इसे उपयोगकर्ता कार्य के लिए असाइन करता है।

एक बार जब आप उपयोगकर्ताओं को कनेक्शन पर मनमाने ढंग से SQL चलाने की अनुमति देते हैं, या यदि उपयोगकर्ता एक उपयुक्त SQL इंजेक्शन भेद्यता की खोज करने का प्रबंधन करता है, तो यह दृष्टिकोण ध्वस्त हो जाता है। उस स्थिति में ऐसा कुछ भी नहीं है जो उन्हें मनमाना उपयोगकर्ता नाम सेट करने से रोक सके। लेकिन निराश न हों, उस समस्या के समाधान का एक गुच्छा है, और हम जल्दी से उनका समाधान करेंगे।

हस्ताक्षरित सत्र चर

पहला समाधान सत्र चर का एक सरल सुधार है - हम वास्तव में उपयोगकर्ताओं को मनमाना मूल्य निर्धारित करने से नहीं रोक सकते हैं, लेकिन क्या होगा यदि हम यह सत्यापित कर सकें कि मान को विकृत नहीं किया गया था? एक साधारण डिजिटल हस्ताक्षर का उपयोग करना काफी आसान है। केवल उपयोगकर्ता नाम संग्रहीत करने के बजाय, विश्वसनीय भाग (कनेक्शन पूल, एप्लिकेशन) कुछ ऐसा कर सकता है:

हस्ताक्षर =sha256 (उपयोगकर्ता नाम + टाइमस्टैम्प + गुप्त)

और फिर मान और हस्ताक्षर दोनों को सत्र चर में संग्रहीत करें:

सेट my.username ='यूजरनेम:टाइमस्टैम्प:हस्ताक्षर'

यह मानते हुए कि उपयोगकर्ता SECRET स्ट्रिंग (उदाहरण के लिए यादृच्छिक डेटा का 128B) नहीं जानता है, हस्ताक्षर को अमान्य किए बिना मान को संशोधित करना संभव नहीं होना चाहिए।

नोट :यह कोई नया विचार नहीं है - यह अनिवार्य रूप से हस्ताक्षरित HTTP कुकीज़ के समान ही है। Django के पास इसके बारे में काफी अच्छा दस्तावेज है।

SECRET मान को सुरक्षित रखने का सबसे आसान तरीका यह है कि इसे उपयोगकर्ता द्वारा दुर्गम तालिका में संग्रहीत किया जाए, और एक security definer प्रदान किया जाए। फ़ंक्शन, जिसके लिए पासवर्ड की आवश्यकता होती है (ताकि उपयोगकर्ता केवल मनमाने मूल्यों पर हस्ताक्षर न कर सके)।

फ़ंक्शन बनाएं set_username(unname TEXT, pwd TEXT) $DECLARE v_key TEXT के रूप में टेक्स्ट लौटाता है; v_value टेक्स्ट; रहस्यों से v_key में साइन_की चुनें; v_value :=uname || ':' || निकालें (अब से युग ())::int; v_value :=v_value || ':' || क्रिप्ट (v_value || ':' || v_key, gen_salt('bf')); PERFORM set_config('my.username', v_value, false); RETURN v_value;END;$ LANGUAGE plpgsql सुरक्षा परिभाषा स्थिर;

फ़ंक्शन केवल एक तालिका में हस्ताक्षर कुंजी (गुप्त) को देखता है, हस्ताक्षर की गणना करता है और फिर मान को सत्र चर में सेट करता है। यह अधिकतर सुविधा के लिए मान भी लौटाता है।

तो विश्वसनीय हिस्सा उपयोगकर्ता को कनेक्शन सौंपने से ठीक पहले ऐसा कर सकता है (जाहिर है 'पासफ़्रेज़' उत्पादन के लिए बहुत अच्छा पासवर्ड नहीं है):

सेट_यूज़रनेम चुनें ('टॉमस', 'पासफ़्रेज़')

और फिर निश्चित रूप से हमें एक और फ़ंक्शन की आवश्यकता होती है जो केवल हस्ताक्षर की पुष्टि करता है और या तो त्रुटियों को बाहर करता है या हस्ताक्षर से मेल खाने पर उपयोगकर्ता नाम लौटाता है।

CREATE FUNCTION get_username() टेक्स्ट को $DECLARE v_key टेक्स्ट के रूप में लौटाता है; v_parts टेक्स्ट []; v_uname पाठ; v_value टेक्स्ट; v_timestamp आईएनटी; v_signature TEXT;BEGIN -- इस बार कोई पासवर्ड सत्यापन नहीं है, गोपनीयता से v_key में साइन_की चुनें; v_parts:=regexp_split_to_array(current_setting('my.username', true), ':'); v_uname :=v_parts[1]; v_timestamp :=v_parts[2]; v_signature:=v_parts[3]; v_value :=v_uname || ':' || v_timestamp || ':' || v_key; IF v_signature =crypt(v_value, v_signature) फिर v_uname लौटाएं; अगर अंत; अपवाद उठाएँ 'अमान्य उपयोगकर्ता नाम / टाइमस्टैम्प';END;$ LANGUAGE plpgsql सुरक्षा परिभाषा स्थिर;

और चूंकि इस फ़ंक्शन को पासफ़्रेज़ की आवश्यकता नहीं है, उपयोगकर्ता बस यह कर सकता है:

गेट_यूज़रनेम चुनें ()

लेकिन get_username() फ़ंक्शन सुरक्षा नीतियों के लिए है, उदा। इस तरह:

चैट का उपयोग करके चैट पर नीति बनाएं (get_username() IN (message_from, message_to)) चेक के साथ (message_from =get_username ())

एक अधिक संपूर्ण उदाहरण, जिसे एक साधारण एक्सटेंशन के रूप में पैक किया गया है, यहां पाया जा सकता है।

ध्यान दें कि सभी ऑब्जेक्ट्स (टेबल और फ़ंक्शंस) एक विशेषाधिकार प्राप्त उपयोगकर्ता के स्वामित्व में हैं, न कि उपयोगकर्ता डेटाबेस तक पहुंचने वाले उपयोगकर्ता के पास है। उपयोगकर्ता के पास केवल EXECUTE है फ़ंक्शंस पर विशेषाधिकार, जिन्हें हालांकि SECURITY DEFINER . के रूप में परिभाषित किया गया है . यही कारण है कि यह योजना उपयोगकर्ता से रहस्य की रक्षा करते हुए काम करती है। फ़ंक्शंस को STABLE . के रूप में परिभाषित किया गया है , कॉल की संख्या को crypt() . तक सीमित करने के लिए फ़ंक्शन (जो जान-बूझकर क्रूर बल को रोकने के लिए महंगा है)।

उदाहरण कार्यों को निश्चित रूप से अधिक काम की आवश्यकता है। लेकिन उम्मीद है कि एक संरक्षित सत्र चर में अतिरिक्त संदर्भ को कैसे संग्रहीत किया जाए, यह प्रदर्शित करने वाली अवधारणा के प्रमाण के लिए यह काफी अच्छा है।

आप पूछें कि क्या ठीक करने की आवश्यकता है? सबसे पहले फ़ंक्शंस विभिन्न त्रुटि स्थितियों को बहुत अच्छी तरह से संभाल नहीं पाते हैं। दूसरे, जबकि हस्ताक्षरित मूल्य में टाइमस्टैम्प शामिल है, हम वास्तव में इसके साथ कुछ भी नहीं कर रहे हैं - इसका उपयोग मूल्य को समाप्त करने के लिए किया जा सकता है, उदाहरण के लिए। मूल्य में अतिरिक्त बिट्स जोड़ना संभव है, उदा। उपयोगकर्ता का एक विभाग, या यहां तक ​​कि सत्र के बारे में जानकारी (उदाहरण के लिए बैकएंड प्रक्रिया की पीआईडी ​​ताकि अन्य कनेक्शनों पर समान मूल्य का पुन:उपयोग न किया जा सके)।

क्रिप्टो

दो कार्य क्रिप्टोग्राफी पर निर्भर करते हैं - हम कुछ सरल हैशिंग कार्यों को छोड़कर अधिक उपयोग नहीं कर रहे हैं, लेकिन यह अभी भी एक साधारण क्रिप्टो योजना है। और हर कोई जानता है कि आपको अपना खुद का क्रिप्टो नहीं करना चाहिए। यही कारण है कि मैंने pgcrypto एक्सटेंशन का उपयोग किया, विशेष रूप से crypt() समारोह, इस समस्या को हल करने के लिए। लेकिन मैं क्रिप्टोग्राफर नहीं हूं, इसलिए मेरा मानना ​​है कि पूरी योजना ठीक है, शायद मुझे कुछ याद आ रहा है - अगर आपको कुछ पता चलता है तो मुझे बताएं।

साथ ही, हस्ताक्षर सार्वजनिक-कुंजी क्रिप्टोग्राफी के लिए एक महान मैच होगा - हम हस्ताक्षर के लिए पासफ़्रेज़ के साथ एक नियमित पीजीपी कुंजी का उपयोग कर सकते हैं, और हस्ताक्षर सत्यापन के लिए सार्वजनिक भाग का उपयोग कर सकते हैं। अफसोस की बात है कि हालांकि pgcrypto एन्क्रिप्शन के लिए PGP का समर्थन करता है, यह हस्ताक्षर का समर्थन नहीं करता है।

वैकल्पिक दृष्टिकोण

बेशक, विभिन्न वैकल्पिक समाधान हैं। उदाहरण के लिए, किसी तालिका में हस्ताक्षर रहस्य को संग्रहीत करने के बजाय, आप इसे फ़ंक्शन में हार्ड-कोड कर सकते हैं (लेकिन फिर आपको यह सुनिश्चित करने की आवश्यकता है कि उपयोगकर्ता स्रोत कोड नहीं देख सकता है)। या आप एक सी फ़ंक्शन में साइन इन कर सकते हैं, इस मामले में यह उन सभी से छिपा हुआ है जिनके पास स्मृति तक पहुंच नहीं है (जिस स्थिति में आप वैसे भी खो गए हैं)।

साथ ही, यदि आपको हस्ताक्षर करने का तरीका बिल्कुल भी पसंद नहीं है, तो आप हस्ताक्षरित चर को अधिक पारंपरिक "वॉल्ट" समाधान से बदल सकते हैं। हमें डेटा को स्टोर करने के लिए एक तरीके की आवश्यकता है, लेकिन हमें यह सुनिश्चित करने की आवश्यकता है कि उपयोगकर्ता एक परिभाषित तरीके को छोड़कर सामग्री को मनमाने ढंग से देख या संशोधित नहीं कर सकता है। लेकिन हे, यह एक एपीआई के साथ नियमित टेबल है जिसे security definer . का उपयोग करके लागू किया गया है कार्य कर सकते हैं!

मैं यहां संपूर्ण पुन:कार्य किए गए उदाहरण को प्रस्तुत नहीं करने जा रहा हूं (एक पूर्ण उदाहरण के लिए इस एक्सटेंशन की जांच करें), लेकिन हमें जो चाहिए वह एक sessions है तिजोरी की तरह काम करने वाली टेबल:

टेबल सत्र बनाएं ( session_id UUID प्राथमिक कुंजी, session_user NAME NOT NULL)

तालिका को नियमित डेटाबेस उपयोगकर्ताओं द्वारा एक्सेस नहीं किया जाना चाहिए - एक साधारण REVOKE ALL FROM ... इसका ख्याल रखना चाहिए। और फिर एक एपीआई जिसमें दो मुख्य कार्य होते हैं:

  • set_username(user_name, passphrase) - एक यादृच्छिक UUID उत्पन्न करता है, डेटा को तिजोरी में सम्मिलित करता है और UUID को एक सत्र चर में संग्रहीत करता है
  • get_username() - एक सत्र चर से UUID को पढ़ता है और तालिका में पंक्ति को देखता है (यदि कोई मिलान पंक्ति नहीं है तो त्रुटियाँ)

यह दृष्टिकोण यूयूआईडी की यादृच्छिकता के साथ हस्ताक्षर सुरक्षा को बदल देता है - उपयोगकर्ता सत्र चर को बदल सकता है, लेकिन मौजूदा आईडी को हिट करने की संभावना नगण्य है (यूयूआईडी 128-बिट यादृच्छिक मान हैं)।

यह पारंपरिक भूमिका-आधारित सुरक्षा पर निर्भर करते हुए थोड़ा अधिक पारंपरिक दृष्टिकोण है, लेकिन इसके कुछ नुकसान भी हैं - उदाहरण के लिए यह वास्तव में डेटाबेस लिखता है, जिसका अर्थ है कि यह हॉट स्टैंडबाय सिस्टम के साथ स्वाभाविक रूप से असंगत है।

पासफ़्रेज़ से छुटकारा पाना

तिजोरी को डिज़ाइन करना भी संभव है ताकि पासफ़्रेज़ आवश्यक न हो। हमने इसे पेश किया है क्योंकि हमने मान लिया था set_username एक ही कनेक्शन पर होता है - हमें फ़ंक्शन को निष्पादन योग्य रखना होता है (इसलिए भूमिकाओं या विशेषाधिकारों के साथ खिलवाड़ करना कोई समाधान नहीं है), और पासफ़्रेज़ सुनिश्चित करता है कि केवल विश्वसनीय घटक ही वास्तव में इसका उपयोग कर सकता है।

लेकिन क्या होगा यदि हस्ताक्षर/सत्र निर्माण एक अलग कनेक्शन पर होता है, और केवल परिणाम (हस्ताक्षरित मूल्य या सत्र यूयूआईडी) को उपयोगकर्ता को दिए गए कनेक्शन में कॉपी किया जाता है? ठीक है, तो हमें अब पासफ़्रेज़ की आवश्यकता नहीं है। (यह थोड़ा वैसा ही है जैसा कि केर्बरोस करता है - एक विश्वसनीय कनेक्शन पर टिकट बनाना, फिर अन्य सेवाओं के लिए टिकट का उपयोग करना।)

सारांश

तो मुझे इस ब्लॉग पोस्ट को जल्दी से संक्षेप में बताएं:

  • जबकि सभी आरएलएस उदाहरण डेटाबेस उपयोगकर्ताओं का उपयोग करते हैं (current_user . के माध्यम से) ), आरएलएस को एप्लिकेशन उपयोगकर्ताओं के साथ काम करना बहुत मुश्किल नहीं है।
  • सत्र चर एक विश्वसनीय और काफी सरल समाधान हैं, यह मानते हुए कि सिस्टम में एक विश्वसनीय घटक है जो उपयोगकर्ता को कनेक्शन सौंपने से पहले चर सेट कर सकता है।
  • जब उपयोगकर्ता मनमाने ढंग से SQL निष्पादित कर सकता है (या तो डिज़ाइन द्वारा या भेद्यता के लिए धन्यवाद), एक हस्ताक्षरित चर उपयोगकर्ता को मान बदलने से रोकता है।
  • अन्य समाधान संभव हैं, उदा. सेशन वेरिएबल को टेबल स्टोरेज से बदलना, रैंडम यूयूआईडी द्वारा पहचाने गए सेशन के बारे में जानकारी।
  • एक अच्छी बात यह है कि सत्र चर कोई डेटाबेस नहीं लिखता है, इसलिए यह दृष्टिकोण केवल-पढ़ने के लिए सिस्टम (जैसे हॉट स्टैंडबाय) पर काम कर सकता है।

इस ब्लॉग श्रृंखला के अगले भाग में हम एप्लिकेशन उपयोगकर्ताओं का उपयोग करते हुए देखेंगे जब सिस्टम में एक विश्वसनीय घटक नहीं होता है (इसलिए यह सत्र चर सेट नहीं कर सकता है या sessions में एक पंक्ति नहीं बना सकता है। तालिका), या जब हम डेटाबेस के भीतर (अतिरिक्त) कस्टम प्रमाणीकरण करना चाहते हैं।


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. मुझे कैसे पता चलेगा कि मेरा PostgreSQL बैकअप अच्छा है?

  2. डायनेमिक SQL का उपयोग करके समग्र चर फ़ील्ड का मान कैसे सेट करें

  3. हाइबरनेट + पोस्टग्रेएसक्यूएल + नेटवर्क एड्रेस टाइप (इनेट, सीडीआईआर)

  4. SQLAlchemy के माध्यम से Postgresql के साथ कई कथनों को निष्पादित करना परिवर्तन जारी नहीं रखता है

  5. Oracle से PostgreSQL — कर्सर और ltree