2018 में GDPR के शहर में आने से पहले, उसके दौरान और बाद में, सॉफ़्टवेयर स्टैक की विभिन्न परतों का उपयोग करके, लेकिन विभिन्न तरीकों का उपयोग करके उपयोगकर्ता डेटा को हटाने या छिपाने की समस्या को हल करने के लिए कई विचार किए गए हैं। (हार्ड डिलीट, सॉफ्ट डिलीशन, गुमनामी)। अनामीकरण उनमें से एक रहा है जिसे PostgreSQL-आधारित संगठनों/कंपनियों के बीच लोकप्रिय माना जाता है।
जीडीपीआर की भावना में, हम कंपनियों के बीच व्यापार दस्तावेजों और रिपोर्टों के आदान-प्रदान की अधिक से अधिक आवश्यकता देखते हैं, ताकि उन रिपोर्टों में दिखाए गए व्यक्तियों को गुमनाम रूप से प्रस्तुत किया जा सके, यानी केवल उनकी भूमिका/शीर्षक दिखाया गया हो , जबकि उनका व्यक्तिगत डेटा छिपा हुआ है। यह संभवत:इस तथ्य के कारण होता है कि ये रिपोर्ट प्राप्त करने वाली कंपनियां जीडीपीआर की प्रक्रियाओं/प्रक्रियाओं के तहत इन आंकड़ों का प्रबंधन नहीं करना चाहती हैं, वे उन्हें संभालने के लिए नई प्रक्रियाओं/प्रक्रियाओं/सिस्टम को डिजाइन करने के बोझ से निपटना नहीं चाहती हैं। , और वे केवल पहले से अनामित डेटा प्राप्त करने के लिए कहते हैं। इसलिए यह गुमनामी न केवल उन व्यक्तियों पर लागू होती है जिन्होंने भूलने की इच्छा व्यक्त की है, बल्कि वास्तव में रिपोर्ट में उल्लिखित सभी लोगों पर लागू होता है, जो सामान्य जीडीपीआर प्रथाओं से काफी अलग है।
इस लेख में, हम इस समस्या के समाधान के लिए गुमनामी से निपटने जा रहे हैं। हम एक स्थायी समाधान प्रस्तुत करने के साथ शुरू करेंगे, यह एक ऐसा समाधान है जिसमें भूलने का अनुरोध करने वाले व्यक्ति को सिस्टम में भविष्य की सभी पूछताछों में छिपाया जाना चाहिए। फिर इसके ऊपर निर्माण करते हुए हम "ऑन डिमांड" यानी अल्पकालिक गुमनामी को प्राप्त करने का एक तरीका पेश करेंगे, जिसका अर्थ है कि सिस्टम में आवश्यक रिपोर्ट उत्पन्न होने तक पर्याप्त समय तक सक्रिय रहने के उद्देश्य से एक गुमनामी तंत्र का कार्यान्वयन। जिस समाधान में मैं इसे प्रस्तुत कर रहा हूं उसका वैश्विक प्रभाव होगा, इसलिए यह समाधान एक लालची दृष्टिकोण का उपयोग करता है, सभी अनुप्रयोगों को कवर करता है, न्यूनतम (यदि कोई हो) कोड पुनर्लेखन के साथ (और पोस्टग्रेएसक्यूएल डीबीए की प्रवृत्ति से ऐसी समस्याओं को हल करने के लिए केंद्रीय रूप से ऐप छोड़कर आता है) डेवलपर्स अपने वास्तविक कार्यभार से निपटते हैं)। हालांकि, यहां प्रस्तुत विधियों को सीमित/संकीर्ण क्षेत्रों में लागू करने के लिए आसानी से बदला जा सकता है।
स्थायी गुमनामी
यहां हम गुमनामी हासिल करने का एक तरीका पेश करेंगे। आइए एक कंपनी के कर्मचारियों के रिकॉर्ड वाली निम्न तालिका पर विचार करें:
testdb=# create table person(id serial primary key, surname text not null, givenname text not null, midname text, address text not null, email text not null, role text not null, rank text not null);
CREATE TABLE
testdb=# insert into person(surname,givenname,address,email,role,rank) values('Singh','Kumar','2 some street, Mumbai, India','[email protected]','Seafarer','Captain');
INSERT 0 1
testdb=# insert into person(surname,givenname,address,email,role,rank) values('Mantzios','Achilleas','Agiou Titou 10, Iraklio, Crete, Greece','[email protected]','IT','DBA');
INSERT 0 1
testdb=# insert into person(surname,givenname,address,email,role,rank) values('Emanuel','Tsatsadakis','Knossou 300, Iraklio, Crete, Greece','[email protected]','IT','Developer');
INSERT 0 1
testdb=#
यह तालिका सार्वजनिक है, हर कोई इसे क्वेरी कर सकता है, और यह सार्वजनिक स्कीमा से संबंधित है। अब हम गुमनामी के लिए बुनियादी तंत्र बनाते हैं जिसमें निम्न शामिल हैं:
- संबंधित तालिकाओं और विचारों को धारण करने के लिए एक नई स्कीमा, चलिए इसे अनाम कहते हैं
- एक टेबल जिसमें उन लोगों की आईडी होती है जिन्हें भुला दिया जाना चाहते हैं:anonym.person_anonym
- एक दृश्य जो public.person:anonym.person का अनाम संस्करण प्रदान करता है
- नए दृश्य का उपयोग करने के लिए search_path का सेटअप
testdb=# create schema anonym;
CREATE SCHEMA
testdb=# create table anonym.person_anonym(id INT NOT NULL REFERENCES public.person(id));
CREATE TABLE
CREATE OR REPLACE VIEW anonym.person AS
SELECT p.id,
CASE
WHEN pa.id IS NULL THEN p.givenname
ELSE '****'::character varying
END AS givenname,
CASE
WHEN pa.id IS NULL THEN p.midname
ELSE '****'::character varying
END AS midname,
CASE
WHEN pa.id IS NULL THEN p.surname
ELSE '****'::character varying
END AS surname,
CASE
WHEN pa.id IS NULL THEN p.address
ELSE '****'::text
END AS address,
CASE
WHEN pa.id IS NULL THEN p.email
ELSE '****'::character varying
END AS email,
role,
rank
FROM person p
LEFT JOIN anonym.person_anonym pa ON p.id = pa.id
;
आइए search_path को हमारे ऐप्लिकेशन पर सेट करें:
set search_path = anonym,"$user", public;
चेतावनी :यह आवश्यक है कि search_path एप्लिकेशन में डेटा स्रोत परिभाषा में सही ढंग से सेटअप हो। पाठक को खोज पथ को संभालने के लिए और अधिक उन्नत तरीके तलाशने के लिए प्रोत्साहित किया जाता है, उदा। एक फ़ंक्शन के उपयोग के साथ जो अधिक जटिल और गतिशील तर्क को संभाल सकता है। उदाहरण के लिए, आप डेटा प्रविष्टि उपयोगकर्ताओं (या भूमिका) का एक सेट निर्दिष्ट कर सकते हैं, और उपयोगकर्ताओं के प्रबंधकीय/रिपोर्टिंग सेट को परिभाषित करते हुए, उन्हें अनामीकरण अंतराल के दौरान public.person तालिका का उपयोग करते रहने दें (ताकि वे सामान्य डेटा देखते रहें)। (या भूमिका) जिनके लिए गुमनामी का तर्क लागू होगा।
अब अपने व्यक्तिगत संबंध के बारे में पूछताछ करते हैं:
testdb=# select * from person;
-[ RECORD 1 ]-------------------------------------
id | 2
givenname | Achilleas
midname |
surname | Mantzios
address | Agiou Titou 10, Iraklio, Crete, Greece
email | [email protected]
role | IT
rank | DBA
-[ RECORD 2 ]-------------------------------------
id | 1
givenname | Kumar
midname |
surname | Singh
address | 2 some street, Mumbai, India
email | [email protected]
role | Seafarer
rank | Captain
-[ RECORD 3 ]-------------------------------------
id | 3
givenname | Tsatsadakis
midname |
surname | Emanuel
address | Knossou 300, Iraklio, Crete, Greece
email | [email protected]
role | IT
rank | Developer
testdb=#
अब, मान लेते हैं कि श्री सिंह कंपनी छोड़ देते हैं और एक लिखित बयान द्वारा स्पष्ट रूप से भूल जाने के अपने अधिकार को व्यक्त करते हैं। एप्लिकेशन अपनी आईडी को "भूलने के लिए" आईडी के सेट में डालकर ऐसा करता है:
testdb=# insert into anonym.person_anonym (id) VALUES(1);
INSERT 0 1
आइए अब ठीक वही क्वेरी दोहराएं जो हम पहले चलाते थे:
testdb=# select * from person;
-[ RECORD 1 ]-------------------------------------
id | 1
givenname | ****
midname | ****
surname | ****
address | ****
email | ****
role | Seafarer
rank | Captain
-[ RECORD 2 ]-------------------------------------
id | 2
givenname | Achilleas
midname |
surname | Mantzios
address | Agiou Titou 10, Iraklio, Crete, Greece
email | [email protected]
role | IT
rank | DBA
-[ RECORD 3 ]-------------------------------------
id | 3
givenname | Tsatsadakis
midname |
surname | Emanuel
address | Knossou 300, Iraklio, Crete, Greece
email | [email protected]
role | IT
rank | Developer
testdb=#
हम देख सकते हैं कि श्री सिंह के विवरण आवेदन से उपलब्ध नहीं हैं।
अस्थायी वैश्विक गुमनामी
मुख्य विचार
- उपयोगकर्ता गुमनामी अंतराल (एक छोटी अवधि) की शुरुआत को चिह्नित करता है।
- इस अंतराल के दौरान, टेबल के नाम वाले व्यक्ति के लिए केवल चुनिंदा लोगों की अनुमति है।
- सभी एक्सेस (चयनित) व्यक्ति तालिका में सभी रिकॉर्ड के लिए अज्ञात हैं, भले ही किसी भी पूर्व अज्ञातकरण सेटअप की परवाह किए बिना।
- उपयोगकर्ता गुमनामी अंतराल के अंत को चिह्नित करता है।
बिल्डिंग ब्लॉक्स
- दो चरण की प्रतिबद्धता (उर्फ तैयार लेनदेन)।
- स्पष्ट टेबल लॉकिंग।
- उपरोक्त अनामीकरण सेटअप जो हमने "स्थायी अनामीकरण" अनुभाग में किया था।
कार्यान्वयन
एक विशेष व्यवस्थापक ऐप (उदाहरण के लिए:markStartOfAnynimizationPeriod कहा जाता है) प्रदर्शन करता है
testdb=# BEGIN ;
BEGIN
testdb=# LOCK public.person IN SHARE MODE ;
LOCK TABLE
testdb=# PREPARE TRANSACTION 'personlock';
PREPARE TRANSACTION
testdb=#
उपरोक्त क्या करता है साझा मोड में टेबल पर लॉक प्राप्त करता है ताकि INSERTS, UPDATES, DELETES अवरुद्ध हो जाएं। इसके अलावा दो चरण प्रतिबद्ध लेनदेन शुरू करके (एकेए तैयार लेनदेन, अन्य संदर्भों में वितरित लेनदेन या विस्तारित आर्किटेक्चर लेनदेन एक्सए के रूप में जाना जाता है) हम लेनदेन को गुमनामी अवधि की शुरुआत को चिह्नित करते हुए सत्र के कनेक्शन से मुक्त करते हैं, जबकि अन्य बाद के सत्रों को होने देते हैं। अपने अस्तित्व के प्रति जागरूक है। तैयार लेनदेन एक सतत लेनदेन है जो कनेक्शन/सत्र के डिस्कनेक्ट होने के बाद जीवित रहता है जिसने इसे शुरू किया है (PREPARE TRANSACTION के माध्यम से)। ध्यान दें कि "तैयारी लेनदेन" कथन वर्तमान सत्र से लेनदेन को अलग करता है। तैयार लेनदेन को बाद के सत्र तक उठाया जा सकता है और या तो रोलबैक किया जा सकता है या प्रतिबद्ध किया जा सकता है। इस प्रकार के एक्सए लेनदेन का उपयोग एक प्रणाली को कई अलग-अलग एक्सए डेटा स्रोतों से विश्वसनीय रूप से निपटने में सक्षम बनाता है, और उन (संभवतः विषम) डेटा स्रोतों में लेनदेन संबंधी तर्क निष्पादित करता है। हालाँकि, इस विशिष्ट मामले में हम इसका उपयोग करने के कारण:
- सत्र को समाप्त करने और उसके कनेक्शन को डिस्कनेक्ट करने/मुक्त करने के जारीकर्ता क्लाइंट सत्र को सक्षम करने के लिए (एक कनेक्शन को छोड़ना या इससे भी बदतर "जारी रखना" वास्तव में एक बुरा विचार है, जैसे ही यह प्रदर्शन करता है, कनेक्शन को मुक्त कर दिया जाना चाहिए इसके लिए आवश्यक प्रश्न)
- बाद के सत्रों/कनेक्शन को इस तैयार लेनदेन के अस्तित्व के लिए पूछताछ करने में सक्षम बनाने के लिए
- समापन सत्र को इस तैयार लेनदेन को करने में सक्षम बनाने के लिए (इसके नाम के उपयोग से) इस प्रकार चिह्नित करना:
- शेयर मोड लॉक का विमोचन
- गुमनामीकरण अवधि की समाप्ति
यह सत्यापित करने के लिए कि लेन-देन जीवित है और हमारी व्यक्तिगत तालिका पर SHARE लॉक से जुड़ा है, हम करते हैं:
testdb=# select px.*,l0.* from pg_prepared_xacts px , pg_locks l0 where px.gid='personlock' AND l0.virtualtransaction='-1/'||px.transaction AND l0.relation='public.person'::regclass AND l0.mode='ShareLock';
-[ RECORD 1 ]------+----------------------------
transaction | 725
gid | personlock
prepared | 2020-05-23 15:34:47.2155+03
owner | postgres
database | testdb
locktype | relation
database | 16384
relation | 32829
page |
tuple |
virtualxid |
transactionid |
classid |
objid |
objsubid |
virtualtransaction | -1/725
pid |
mode | ShareLock
granted | t
fastpath | f
testdb=#
उपरोक्त क्वेरी क्या करती है यह सुनिश्चित करने के लिए कि नामित तैयार लेनदेन व्यक्ति लॉक जीवित है और वास्तव में इस वर्चुअल लेनदेन द्वारा आयोजित टेबल व्यक्ति पर संबंधित लॉक इच्छित मोड में है:साझा करें।
तो अब हम दृश्य में बदलाव कर सकते हैं:
CREATE OR REPLACE VIEW anonym.person AS
WITH perlockqry AS (
SELECT 1
FROM pg_prepared_xacts px,
pg_locks l0
WHERE px.gid = 'personlock'::text AND l0.virtualtransaction = ('-1/'::text || px.transaction) AND l0.relation = 'public.person'::regclass::oid AND l0.mode = 'ShareLock'::text
)
SELECT p.id,
CASE
WHEN pa.id IS NULL AND NOT (EXISTS ( SELECT 1
FROM perlockqry)) THEN p.givenname::character varying
ELSE '****'::character varying
END AS givenname,
CASE
WHEN pa.id IS NULL AND NOT (EXISTS ( SELECT 1
FROM perlockqry)) THEN p.midname::character varying
ELSE '****'::character varying
END AS midname,
CASE
WHEN pa.id IS NULL AND NOT (EXISTS ( SELECT 1
FROM perlockqry)) THEN p.surname::character varying
ELSE '****'::character varying
END AS surname,
CASE
WHEN pa.id IS NULL AND NOT (EXISTS ( SELECT 1
FROM perlockqry)) THEN p.address
ELSE '****'::text
END AS address,
CASE
WHEN pa.id IS NULL AND NOT (EXISTS ( SELECT 1
FROM perlockqry)) THEN p.email::character varying
ELSE '****'::character varying
END AS email,
p.role,
p.rank
FROM public.person p
LEFT JOIN person_anonym pa ON p.id = pa.id
अब नई परिभाषा के साथ, यदि उपयोगकर्ता ने लेनदेन पर्सनलॉक तैयार करना शुरू कर दिया है, तो निम्नलिखित चयन वापस आ जाएगा:
testdb=# select * from person;
id | givenname | midname | surname | address | email | role | rank
----+-----------+---------+---------+---------+-------+----------+-----------
1 | **** | **** | **** | **** | **** | Seafarer | Captain
2 | **** | **** | **** | **** | **** | IT | DBA
3 | **** | **** | **** | **** | **** | IT | Developer
(3 rows)
testdb=#
जिसका अर्थ है वैश्विक बिना शर्त गुमनामी।
टेबल पर्सन के डेटा का उपयोग करने की कोशिश करने वाले किसी भी ऐप को वास्तविक वास्तविक डेटा के बजाय "****" नाम दिया जाएगा। अब मान लेते हैं कि इस ऐप का एडमिन तय करता है कि गुमनामी की अवधि समाप्त होने वाली है, इसलिए उसका ऐप अब जारी करता है:
COMMIT PREPARED 'personlock';
अब कोई भी बाद का चयन वापस आ जाएगा:
testdb=# select * from person;
id | givenname | midname | surname | address | email | role | rank
----+-------------+---------+----------+----------------------------------------+-------------------------------+----------+-----------
1 | **** | **** | **** | **** | **** | Seafarer | Captain
2 | Achilleas | | Mantzios | Agiou Titou 10, Iraklio, Crete, Greece | [email protected] | IT | DBA
3 | Tsatsadakis | | Emanuel | Knossou 300, Iraklio, Crete, Greece | [email protected] | IT | Developer
(3 rows)
testdb=#
चेतावनी! :लॉक समवर्ती लेखन को रोकता है, लेकिन लॉक जारी होने पर अंतिम लेखन को नहीं रोकता है। इसलिए ऐप्स को अपडेट करने, डेटाबेस से '****' पढ़ने, एक लापरवाह उपयोगकर्ता, हिटिंग अपडेट के लिए संभावित खतरा है, और फिर प्रतीक्षा की कुछ अवधि के बाद, SHARED लॉक रिलीज़ हो जाता है और अपडेट '*** लिखने में सफल हो जाता है। *' के स्थान पर जहां सही सामान्य डेटा होना चाहिए। बेशक उपयोगकर्ता आँख बंद करके बटन न दबाकर यहाँ मदद कर सकते हैं, लेकिन कुछ अतिरिक्त सुरक्षा यहाँ जोड़ी जा सकती हैं। ऐप्स को अपडेट करने से निम्न समस्याएं हो सकती हैं:
set lock_timeout TO 1;
अपडेट करने वाले लेन-देन के प्रारंभ में । इस तरह 1ms से अधिक प्रतीक्षा/अवरुद्ध करने से अपवाद उत्पन्न होगा। जो अधिकांश मामलों के खिलाफ रक्षा करनी चाहिए। एक और तरीका यह होगा कि किसी भी संवेदनशील क्षेत्र में '****' मान के विरुद्ध जांच करने के लिए एक चेक बाधा हो।
अलार्म! :यह अनिवार्य है कि तैयार लेनदेन अंततः पूरा किया जाना चाहिए। या तो उस उपयोगकर्ता द्वारा जिसने इसे शुरू किया (या कोई अन्य उपयोगकर्ता), या यहां तक कि एक क्रॉन स्क्रिप्ट द्वारा जो हर 30 मिनट में भूले हुए लेनदेन की जांच करता है। इस लेन-देन को समाप्त करने के लिए भूलने से भयावह परिणाम होंगे क्योंकि यह VACUUM को चलने से रोकता है, और निश्चित रूप से ताला तब भी रहेगा, जिससे डेटाबेस को लिखने से रोका जा सकेगा। यदि आप अपने सिस्टम के साथ पर्याप्त रूप से सहज नहीं हैं, यदि आप लॉक के साथ तैयार/वितरित लेनदेन का उपयोग करने के सभी पहलुओं और सभी दुष्प्रभावों को पूरी तरह से नहीं समझते हैं, यदि आपके पास पर्याप्त निगरानी नहीं है, खासकर एमवीसीसी के संबंध में मेट्रिक्स, तो बस इस दृष्टिकोण का पालन न करें। इस मामले में, आपके पास व्यवस्थापक उद्देश्यों के लिए एक विशेष टेबल होल्डिंग पैरामीटर हो सकता है जहां आप दो विशेष कॉलम मानों का उपयोग कर सकते हैं, एक सामान्य ऑपरेशन के लिए और एक वैश्विक लागू गुमनामी के लिए, या आप पोस्टग्रेएसक्यूएल एप्लिकेशन-स्तरीय साझा सलाहकार लॉक के साथ प्रयोग कर सकते हैं:पी>
- https://www.postgresql.org/docs/10/explicit-locking.html#ADVISORY-LOCKS
- https://www.postgresql.org/docs/10/functions-admin.html#FUNCTIONS-ADVISORY-LOCKS