2016-01-03 5 views
10

मैं एक वेब-अनुप्रयोग का समर्थन करने वाले बहु-किरायेदार डेटाबेस में नई पंक्ति स्तर सुरक्षा सुविधा का उपयोग करने का सबसे अच्छा तरीका समझने के लिए तैयार हूं।PostgreSQL 9.5 - पंक्ति स्तर सुरक्षा/ROLE सर्वोत्तम प्रथाओं

वर्तमान में, इस एप्लिकेशन के अनुसार कुछ अलग-अलग ROLE उपलब्ध हैं, जो उस क्रिया के आधार पर उपलब्ध है।

एक बार जब एप्लिकेशन अपने स्वयं के ROLE का उपयोग कर कनेक्शन बनाता है, तो एप्लिकेशन उपयोगकर्ता द्वारा समर्थित प्रमाणीकरण पैरामीटर के आधार पर पंक्तियों को फ़िल्टर करने वाले विभिन्न कार्यों में प्रमाणीकरण पैरामीटर (उपयोगकर्ता द्वारा प्रदान किया जाता है) पास करता है। प्रणाली हजारों उपयोगकर्ताओं के साथ काम करने के लिए डिज़ाइन की गई है और ऐसा लगता है कि यह काम करता है; हालांकि, यह बदनाम रूप से घबराहट (और धीमी) है।

ऐसा लगता है कि अगर मैं नई पंक्ति स्तर की सुरक्षा सुविधा का उपयोग करना चाहता हूं तो मुझे डेटाबेस तक पहुंचने के लिए प्रत्येक वास्तविक दुनिया उपयोगकर्ता (केवल वेब एप्लिकेशन के लिए) के लिए एक नया ROLE बनाना होगा।

क्या यह सही है? और यदि हां, तो क्या डेटाबेस में हजारों ROLEs बनाना एक अच्छा विचार है? अब

CREATE USER application; 

CREATE TABLE t1 (id int primary key, f1 text, app_user text); 
INSERT INTO t1 VALUES(1,'a','bob'); 
INSERT INTO t1 VALUES(2,'b','alice'); 
ALTER TABLE t1 ENABLE ROW LEVEL SECURITY; 
CREATE POLICY P ON t1 USING (app_user = current_setting('app_name.app_user')); 
GRANT SELECT ON t1 TO application; 

SET SESSION AUTHORIZATION application; 

SET app_name.app_user = 'bob'; 

SELECT * FROM t1; 

id | f1 | app_user 
----+----+---------- 
    1 | a | bob 
(1 row) 

SET app_name.app_user = 'alice'; 
SELECT * FROM t1; 

id | f1 | app_user 
----+----+---------- 
    2 | b | alice 
(1 row) 

SET app_name.app_user = 'none'; 
SELECT * FROM t1; 

id | f1 | app_user 
----+----+---------- 
(0 rows) 

, मैं current_setting('app_name.app_user') द्वारा संदेह में हूँ के रूप में मैं थोड़ा कम था: टिप्पणी में a_horse_with_no_name के लिंक से


अद्यतन (धन्यवाद, कि धागे पर जगह है) इंप्रेशन यह केवल कॉन्फ़िगरेशन पैरामीटर के लिए था ... app_name कहां परिभाषित किया गया है?

+2

http://www.postgresql.org/message-id/[email protected] –

+0

@a_horse_with_no_name - इसे धन्यवाद, धन्यवाद; हालांकि, धागे में दिया गया उदाहरण थोड़ा सा गूढ़ है ... मैंने सवाल अपडेट किया है। – losthorse

+0

यह ** ** "कॉन्फ़िगरेशन" पैरामीटर के लिए है। इसके लिए उनका उपयोग अनिवार्य रूप से एक "हैक" है। आपको उन्हें हाथ से पहले परिभाषित करने की आवश्यकता नहीं है - यह गतिशील रूप से किया जा सकता है। ध्यान दें कि 'current_setting (' app_name.app_user ')' के परिणामस्वरूप पैरामीटर को पहले परिभाषित नहीं किया गया है। इसे रोकने के लिए, आप 'postgresql.conf' में एक डमी मान को परिभाषित कर सकते हैं –

उत्तर

6

स्थापना सुरक्षा एक सत्र सेटिंग के आधार पर नीतियों एक बहुत ख़राब खराब विचार (मैं दोनों कैप्स नफरत और बोल्ड तो मुझ पर भरोसा है कि मैं यह मतलब है)। कोई भी उपयोगकर्ताSET SESSION 'app_name.app_user' = 'bob' कर सकता है, इसलिए जैसे ही कोई व्यक्ति यह बताता है कि "app_name.app_user" दरवाजा है (मेरा विश्वास करो, वे करेंगे) तो आपकी पूरी सुरक्षा द्वार से बाहर है।

एक ही रास्ता है कि मैं यह देखने के लिए एक मेज सुलभ उपयोग करने के लिए है अपने webadmin केवल जो सत्र टोकन (uuid प्रकार मन, उपयोग में आसानी के लिए text को कास्ट करने के लिए आता है) संग्रहीत करता है। login() फ़ंक्शन SECURITY DEFINER (स्वामी webadmin मानते हुए), टोकन को सेट करने के साथ-साथ सत्र SET टिंग सेट करना, और उसके बाद तालिका का स्वामित्व (या इसके लिए उपयुक्त विशेषाधिकार) webadmin उस तालिका और सत्र नीति को उसकी नीति में संदर्भित करता है।

दुर्भाग्य से, आप यहां अस्थायी (सत्र) टेबल का उपयोग नहीं कर सकते हैं क्योंकि आप अस्थायी तालिका पर नीतियां नहीं बना सकते हैं, इसलिए आपको "वास्तविक" तालिका का उपयोग करना होगा। यही कारण है कि निष्पादन दंड के बारे में कुछ है, लेकिन एक हैक की क्षति के विरुद्ध हो कि ...

अभ्यास में:

CREATE FUNCTION login (uname text, pwd text) RETURNS boolean AS $$ 
DECLARE 
    t uuid; 
BEGIN 
    PERFORM * FROM users WHERE user = uname AND password = pwd; 
    IF FOUND THEN 
    INSERT INTO sessions SET token = uuid_generate_v4()::text, user .... 
     RETURNING token INTO t; 
    SET SESSION "app_name.token" = t; 
    RETURN true; 
    ELSE 
    SET SESSION "app_name.token" = ''; 
    RETURN false; 
    END IF; 
END; $$ LANGUAGE plpgsql STRICT; 

और अब अपनी नीति लिंक होगा sessions रहे हैं:

CREATE POLICY p ON t1 FOR SELECT 
    USING (SELECT true FROM sessions WHERE token = current_setting('app_name.token')); 

(uuid एस को अद्वितीय माना जा सकता है, LIMIT 1 की आवश्यकता नहीं है। ऑर्डरिंग या अन्य जादू, यदि uuid तालिका में है, तो पॉलिसी पास हो जाएगी, अन्यथा विफल हो जाएगी।) uuid अनुमान लगाना असंभव है (वैसे भी आपके जीवनकाल में) और किसी भी व्यक्ति द्वारा पुनर्प्राप्त करना असंभव है लेकिन webadmin

+0

यह पूरी तरह सटीक नहीं है। नीतियों को किसी दिए गए भूमिका के लिए निर्दिष्ट किया जा सकता है, इसलिए, आपके उदाहरण में, नीति केवल 'वेबडमिन' भूमिका के लिए बनाई जा सकती है और फिर "app_name.app_user" GUC सेट करने से केवल उस भूमिका द्वारा जारी किए गए प्रश्नों को प्रभावित किया जाएगा। यह आपकी सुरक्षा आवश्यकताओं के लिए पर्याप्त हो सकता है या नहीं भी हो सकता है, लेकिन यह "किसी भी उपयोगकर्ता" को जीयूसी बदलकर तालिका में किसी भी रिकॉर्ड तक पहुंचने में सक्षम होने से रोक देगा। इसके लिए यह आवश्यक है कि "वेबडमिन" भूमिका का उपयोग करने वाले एप्लिकेशन को उपयोगकर्ता को सही ढंग से सत्यापित करें और निश्चित रूप से एसक्यूएल-इंजेक्शन बग से मुक्त रहें। –

+2

[द्वितीय क्वाड्रंट] (http://blog.2ndquadrant.com/application-users-vs-row-level-security/) में क्रिप्टोग्राफ़िक हस्ताक्षर का उपयोग करके प्राधिकरण को प्रबंधित करने के उदाहरण हैं जो उपयोगकर्ता बाईपास नहीं कर सकते हैं। – spiffytech

संबंधित मुद्दे