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

किसी फ़ंक्शन के अंदर गतिशील प्रश्नों के लिए प्रारूप () कितना सुरक्षित है?

एक चेतावनी का शब्द :यह शैली गतिशील SQL के साथ SECURITY DEFINER . में है कार्य सुरुचिपूर्ण और सुविधाजनक हो सकते हैं। लेकिन इसका अति प्रयोग न करें। कार्यों के कई स्तरों को इस तरह से नेस्ट न करें:

  • सादे SQL की तुलना में शैली अधिक त्रुटि प्रवण है।
  • संदर्भ स्विच के साथ SECURITY DEFINER एक मूल्य टैग है।
  • डायनामिक SQL EXECUTE . के साथ क्वेरी योजनाओं को सहेज और पुन:उपयोग नहीं कर सकता।
  • नहीं "फ़ंक्शन इनलाइनिंग"।
  • और मैं इसे बड़े टेबल पर बड़े प्रश्नों के लिए बिल्कुल भी उपयोग नहीं करना चाहूंगा। जोड़ा परिष्कार एक प्रदर्शन बाधा हो सकता है। जैसे:इस तरह क्वेरी योजनाओं के लिए समांतरता अक्षम है।

उस ने कहा, आपका कार्य अच्छा लग रहा है, मुझे SQL इंजेक्शन के लिए कोई रास्ता नहीं दिख रहा है। format() गतिशील एसक्यूएल के लिए मूल्यों और पहचानकर्ताओं को संयोजित करने और उद्धृत करने के लिए अच्छा साबित हुआ है। इसके विपरीत, आप इसे सस्ता बनाने के लिए कुछ अतिरेक को हटा सकते हैं।

फ़ंक्शन पैरामीटर offset__i और limit__i integer हैं . पूर्णांक संख्याओं के माध्यम से SQL इंजेक्शन असंभव है, वास्तव में उन्हें उद्धृत करने की कोई आवश्यकता नहीं है (भले ही SQL LIMIT के लिए उद्धृत स्ट्रिंग स्थिरांक की अनुमति देता है। और OFFSET ) तो बस:

format(' OFFSET %s LIMIT %s', offset__i, limit__i)

साथ ही, यह सत्यापित करने के बाद कि प्रत्येक key__v आपके कानूनी कॉलम नामों में से है - और जबकि वे सभी कानूनी, गैर-उद्धृत कॉलम नाम हैं - इसे %I के माध्यम से चलाने की कोई आवश्यकता नहीं है . बस %s हो सकता है

मैं इसके बजाय text का उपयोग करना चाहूँगा varchar . के बजाय . कोई बड़ी बात नहीं है, लेकिन text "पसंदीदा" स्ट्रिंग प्रकार है।

संबंधित:

COST 1 बहुत कम लगता है। मैनुअल:

जब तक आप बेहतर नहीं जानते, COST . छोड़ दें अपने डिफ़ॉल्ट 100 . पर ।

सभी लूपिंग के बजाय एकल सेट-आधारित संचालन

पूरे लूपिंग को एक SELECT से बदला जा सकता है बयान। काफ़ी तेज़ होना चाहिए। पीएल/पीजीएसक्यूएल में असाइनमेंट तुलनात्मक रूप से महंगे हैं। इस तरह:

CREATE OR REPLACE FUNCTION goods__list_json (_options json, _limit int = NULL, _offset int = NULL, OUT _result jsonb)
    RETURNS jsonb
    LANGUAGE plpgsql SECURITY DEFINER AS
$func$
DECLARE
   _tbl  CONSTANT text   := 'public.goods_full';
   _cols CONSTANT text[] := '{id, id__category, category, name, barcode, price, stock, sale, purchase}';   
   _oper CONSTANT text[] := '{<, >, <=, >=, =, <>, LIKE, "NOT LIKE", ILIKE, "NOT ILIKE", BETWEEN, "NOT BETWEEN"}';
   _sql           text;
BEGIN
   SELECT concat('SELECT jsonb_agg(t) FROM ('
           , 'SELECT ' || string_agg(t.col, ', '  ORDER BY ord) FILTER (WHERE t.arr->>0 = 'true')
                                               -- ORDER BY to preserve order of objects in input
           , ' FROM '  || _tbl
           , ' WHERE ' || string_agg (
                             CASE WHEN (t.arr->>1)::int BETWEEN  1 AND 10 THEN
                                format('%s %s %L'       , t.col, _oper[(arr->>1)::int], t.arr->>2)
                                  WHEN (t.arr->>1)::int BETWEEN 11 AND 12 THEN
                                format('%s %s %L AND %L', t.col, _oper[(arr->>1)::int], t.arr->>2, t.arr->>3)
                               -- ELSE NULL  -- = default - or raise exception for illegal operator index?
                             END
                           , ' AND '  ORDER BY ord) -- ORDER BY only cosmetic
           , ' OFFSET ' || _offset  -- SQLi-safe, no quotes required
           , ' LIMIT '  || _limit   -- SQLi-safe, no quotes required
           , ') t'
          )
   FROM   json_each(_options) WITH ORDINALITY t(col, arr, ord)
   WHERE  t.col = ANY(_cols)        -- only allowed column names - or raise exception for illegal column?
   INTO   _sql;

   IF _sql IS NULL THEN
      RAISE EXCEPTION 'Invalid input resulted in empty SQL string! Input: %', _options;
   END IF;
   
   RAISE NOTICE 'SQL: %', _sql;
   EXECUTE _sql INTO _result;
END
$func$;

db<>fiddle यहां

SQLi के मुकाबले छोटा, तेज़ और अभी भी सुरक्षित है।

उद्धरण केवल वहीं जोड़े जाते हैं जहां सिंटैक्स के लिए या SQL इंजेक्शन से बचाव के लिए आवश्यक हो। केवल मानों को फ़िल्टर करने के लिए जलता है। अनुमत विकल्पों की हार्ड-वायर्ड सूची के विरुद्ध कॉलम नाम और ऑपरेटरों का सत्यापन किया जाता है।

इनपुट json है इसके बजाय jsonb . वस्तुओं का क्रम json . में सुरक्षित रहता है , ताकि आप SELECT . में कॉलम का क्रम निर्धारित कर सकें सूची (जो अर्थपूर्ण है) और WHERE स्थितियां (जो विशुद्ध रूप से कॉस्मेटिक हैं)। समारोह अब दोनों को देखता है।

आउटपुट _result अभी भी jsonb है . OUT का उपयोग करना चर के बजाय पैरामीटर। यह पूरी तरह से वैकल्पिक है, केवल सुविधा के लिए। (कोई स्पष्ट RETURN नहीं है बयान की आवश्यकता है।)

concat() . के रणनीतिक उपयोग पर ध्यान दें चुपचाप NULL और कॉन्सटेनेशन ऑपरेटर को अनदेखा करने के लिए || ताकि एनयूएलएल समेकित स्ट्रिंग को न्यूल बना सके। इस तरह, FROM , WHERE , LIMIT , और OFFSET जरूरत पड़ने पर ही डाला जाता है। एक SELECT कथन उनमें से किसी के बिना काम करता है। एक खाली SELECT सूची (कानूनी भी है, लेकिन मुझे अवांछित लगता है) एक वाक्यविन्यास त्रुटि में परिणाम देता है। सब कुछ इरादा।
format() . का उपयोग करना केवल WHERE . के लिए फ़िल्टर, सुविधा के लिए और मूल्यों को उद्धृत करने के लिए। देखें:

फ़ंक्शन STRICT नहीं है इसके बाद। _limit और _offset डिफ़ॉल्ट मान है NULL , इसलिए केवल पहला पैरामीटर _options आवश्यक है। _limit और _offset NULL या छोड़ा जा सकता है, फिर प्रत्येक को कथन से हटा दिया जाता है।

text का उपयोग करना varchar . के बजाय ।

वास्तव में स्थिर चर बनाए CONSTANT (ज्यादातर दस्तावेज़ीकरण के लिए)।

इसके अलावा फंक्शन वही करता है जो आपका ओरिजिनल करता है।



  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. पोस्टग्रेएसक्यूएल - ग्रुप बाय क्लॉज

  3. Django और PostgreSQL - टाइप कैरेक्टर अलग-अलग के लिए बहुत लंबा मान (512)

  4. PostgreSQL के लिए घंटों में टाइमस्टैम्प अंतर

  5. शून्य बराबर पूर्णांक WHERE में क्यों होता है?