Date post: | 23-Jan-2018 |
Category: |
Technology |
Upload: | sambit-banerjee |
View: | 174 times |
Download: | 0 times |
ADDRESSING DATA PRIVACY CHALLENGES
IN GLOBAL APPLICATIONS A Technical Solution Approach
Sambit Banerjee https://www.linkedin.com/in/sambitkbanerjee
October 15, 2016
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 1 of 37
1. Overview
Maintaining Data Privacy with application footprints in multiple countries is often a challenge for global organizations. Whereas
in the current age of global economy, sharing of data through international boundaries is extremely important, there is also a
great deal of emphasis on Anti-Money Laundering (AML), which relies on data sharing, as well as on the Data Privacy (DP) aspect,
a blend of which applies to protecting personal data (often referred to as Personally Identifiable Information, i.e., PII data) of
the customers from identity theft, and other misuses. To achieve the goal of maintaining a balance between these two (i.e.,
AML and DP) competing requirements, while most countries have mandated reasonable regulatory measures in the areas of
AML and DP, some other countries have imposed further restrictions mandating that the PII data of their citizens / clients must
remain within the geographical borders of their countries (we call such countries as ‘DP countries’ in this article).
Most global organizations comply with such regulatory mandates from the DP countries by deploying end-to-end system
(application and database) instances within the DP countries so that the PII data of the clients of the DP countries physically
remain within the DP countries, and only non PII and aggregated client data is sent across the country-border to the countries
of their global corporate offices.
Besides the complexities and the additional cost of deploying such distributed instances of the same application in multiple
countries, there are a few common operational challenges involving the DP countries.
1) Typically, such globally deployed systems are designed and developed in the countries with global corporate offices where
Subject Matter Experts (SMEs) and key developments resources are located. These resources may need access to the
instances hosted in the DP countries for investigation and resolution related to the application issues. Common measures
adopted to overcome the remote access issues for the DP countries include –
a. Series of Q&A and hand-holding between the local support teams of the DP countries and the global SMEs located
outside the DP countries
b. At times, local support teams manually remove PII data from log and data files, if exists, before providing those
files to the global SMEs for investigation, in order to comply with the local DP rules
c. Some level of screen sharing takes place after the local support teams do their due diligence to ensure that the PII
data of the DP country is not accidentally exposed to the global SMEs
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 2 of 37
These makes lives of the global SMEs difficult as they –
o depend on the availability (e.g., due to different time zones) and standard operating procedures of the local
support teams
o do not get a holistic view of the current state of the data and the system of the end-to-end application instance of
the DP country because they receive pieces of information one at a time based on the Q&A and hand-holding
o often resort to writing ad-hoc queries, scripts, etc. for the local support teams in order to obtain non-PII data from
the DP country to understand potential data issues.
This process of analysis, identification of root cause, and final resolution of the issues related to the application instances
in the DP countries often turns out to be time consuming, less cohesive and less efficient.
2) While some core support members (e.g., data center staff, system admin, dba, etc.) may be located within the DP country,
some, if not all, of the production support teams (e.g., L1/L2/L3) may be located outside the DP country (as a cost saving
measure), and they may need access to the application instance of the DP country for preliminary investigation of the
application issues before seeking the assistance of the global SMEs.
3) Functional or business team members from the corporate office may need to assist the end-users located inside the DP
country, investigate issues in the application as it relates to various business rules and associated data elements.
As a result, tangible and intangible costs add up due to operational constraints, additional burden on multiple local and global
teams so that there is no exposure of PII data outside the border of the DP country.
All these issues can be addressed seamlessly if there is a solution to dynamically and conditionally suppress PII and other
sensitive data elements based on well-defined criteria, while accessing data.
Fortunately there is one, which we’ll discuss in this article with the help of a standard business requirement, and an end-to-end
technical solution to meet business requirements and address operational issues.
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 3 of 37
2. Business Requirement
XYZ Financial Corp. has –
Its corporate office in a country ‘CNTRY_Non_DP’ that does not restrict sharing of data with other countries.
Its presence in a DP country ‘CNTRY_DP’ that restricts sharing of data of its clients with other countries by mandating that
the PII data of its clients cannot cross the geographical border of the DP country. So, the XYZ Financial Corp. has deployed
an end-to-end application instance in a data center within CNTRY_DP, in order for its local staff to operate on the data of
the clients of the CNTRY_DP country stored in the in-country application / database instance.
The following tables contain master and account data of a few clients of the country CNTRY_DP to describe the DP rules.
Table 1. Client Master Data
Client Identification Primary Contact of the Client
ID Type Domicile Country
First Name
Last Name
Middle Name
Date of Birth
Address Phone Number email
1001 Individual CNTRY_DP John Doe J. 2-Jan-1960 123 Main St, City1, State1 1111-2222-3333 [email protected]
2002 Individual CNTRY_DP Ann Wu 12-Aug-1970 678 River Ln, City2, State2 9988-776-6XYZ js12@xyz .net
Table 2. Client Account Data
Client ID
Account Details
ID Number Type Full Name Date of Birth Address Phone Number email Relation with Primary
Domicile Country
1001 1 445566777 CreditCard John Doe 2-Jan-1960 123 Main St, City1, State1 1111-2222-3333 [email protected] Self CNTRY_DP
1001 2 445561727 CreditCard Jane Doe 5-Mar-1962 123 Main St, City1, State1 1111-2222-3344 [email protected] Spouse CNTRY_DP
2002 3 33245 Savings Ann Wu 12-Aug-1970 678 River Ln, City2, State2 998-8776-6XYZ [email protected] Self CNTRY_DP
2002 4 22567 Checking Ann Wu 12-Aug-1970 678 River Ln, City2, State2 998-8776-6XYZ [email protected] Self CNTRY_DP
2002 5 S1234 Student Loan
David Wu 21-Sep-1997 888 College Blvd, X-City, Y-State
998-8745-6XYZ [email protected] Son CNTRY_ Non_DP
2002 6 6677889901 CreditCard Amy Wu 18-May-2000 678 River Ln, City2, State2 998-8123-4XYZ [email protected] Daughter CNTRY_DP
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 4 of 37
The rules governing these data elements state that –
1) All accounts of the client ID 1001 are created in CNTRY_DP, and hence the associated PII data cannot be accessed from
outside the CNTRY_DP.
2) The same rule applies to the client ID 2002, with the exception that the account of a family member ‘David Wu’ is created
in CNTRY_Non_DP as he has taken a student loan in CNTRY_Non_DP where he is attending college. The XYZ Financial
Corp. has used other accounts of the client ID 2002 as a security for granting the student loan.
a. Although the student loan account is tied to the client ID 2002, the account holder ‘David Wu’ has opened the
student loan account in the CNTRY_Non_DP and also resides in CNTRY_Non_DP, which makes him a client of the
CNTRY_Non_DP country.
b. Due to AML requirements of CNTRY_DP, the same student loan account record tied to the client ID 2002 should
also be present in the in-country application instance of CNTRY_DP, especially due to the fact that CNTRY_Non_DP
does not restrict sharing of its client information with other countries.
c. That means while the users from the CNTRY_Non_DP country cannot access PII data of other accounts of the client
ID 2002 from the CNTRY_DP in-country instance, they should still be able to access the account information related
to the student loan account along with the non PII data of other accounts of the client ID 2002.
So, the user interface of the CNTRY_DP application instance should reflect the following views:-
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 5 of 37
Figure 1. View of the CNTRY_DP users accessing data of the client ID 2002 from within the CNTRY_DP border
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 6 of 37
Figure 2. View of the CNTRY_Non_DP users accessing data of the client ID 2002 from outside the CNTRY_DP border. (The highlighted fields indicate redacted PII data, per the business requirement)
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 7 of 37
3. Solution Design
Let's take a look at the system components of a standard 3-tier application instance hosted in a DP country, and associated data
access points.
Figure 3. High Level Architecture of an Application Instance hosted in a DP Country
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 8 of 37
Figure 3 should be self-explanatory to those involved in system implementation in some capacity. A few notations used in this
diagram are –
i) The boxes with the text ‘John Doe’ represent plain text PII data as it moves thru different system components.
ii) RW FID – Database Functional user ID with Read-Write access to the database
iii) RO FID - Database Functional user ID with Read-Only access to the database
3.1. Design Considerations
Multiple access points for consumption of the same data
Masking the same sensitive data in different access points could lead to repetitive efforts and potential data
inconsistency
So, sensitive data should be masked (i.e., redacted) at the source while retrieving the same data in order to achieve
optimal efficiency and effectiveness
3.2. Design Principles for Data Redaction
Sensitive data should be redacted without changing the actual data stored in the production database.
Only presentation of the target data for redaction should be affected
No change in existing data model or schema FIDs should be required
Implement configurable and rule based design for data redaction as much as possible. Avoid writing custom code at
the application layers for data redaction unless absolutely needed. This addresses portability and manageability
aspects of the application design.
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 9 of 37
Separation of controls – implement the rule based policies owned by a different DB FID other than the DB FID owning
the data.
Data redaction configuration/rules should be enabled, disabled, modified at any time without affecting the BAU
operations on the core data. This one is probably less important in most operational scenario, but nice to have.
It would be great to be technology agnostic to meet these design principles. However, not all database vendors have seamlessly
addressed the challenge of data redaction effectively as yet. Oracle is among the database vendors to have addressed this
challenge at the core of its database engine, meeting these design principles.
So, despite the prospect of potential criticism for not being technology agnostics and vendor lock-in, I am using Oracle database
and relevant features for the technical solution as described in this article.
3.3. Data Redaction Solution Components using Oracle
Key Characteristics
Database session context based, i.e., dynamically applicable to each user session
Column level Data Redaction - using ‘Oracle Data Redaction’ (i.e., DBMS_REDACT package) policies for column(s)
of a table
Row level security for sensitive data - using ‘Oracle Virtual Private Database (VPD)’ (i.e., DBMS_RLS package)
policies for conditionally filtering out rows of a table
Redacted data elements at the table level are automatically reflected / propagated at the view (built upon those
tables) level
Effective immediately upon creation / modification of policies
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 10 of 37
Good News - Available in Oracle Database 11.2.0.4 and upwards, and comes with core Oracle Database
installation package.
Security Considerations
Users with DBA privileges, and certain database administrative operations (e.g., backup / recovery / replication,
etc.) are exempt from Data Redaction using these DBMS packages.
It is possible for Oracle database users with privileged access to break Data Redaction by inference. Oracle
documentation and some other publicly available articles have explained it well. However, it is not among the
best security practices to provide users and developers with privileged access to production data.
Some more disclaimers on Oracle Redaction limitations can be found in Oracle documentation, but I think those
considerations should be addressed in most well-designed database applications anyway.
Now that we know what tool and database we are going to use for our solution, let’s discuss how we’ll use it. As seen in
the architecture diagram in Figure 3, there are two modes of accessing data – 2-tier, and 3-tier (or, N-tier for that matter).
3.4. 2-Tier Access Mode
This is for accessing data over 2-tier client-server protocols, where a user logs in the Oracle database directly using a
database FID, and tools such as SQL*Plus, SQL Developer. In most cases, these tools use SQL*Net protocol, and some use
ODBC / JDBC protocols.
Solution Design Principles for 2-tier access mode
FID owning the data should not be used, as the best practice, to access production data directly over 2-tier client-
server protocols. Use FIDs that are not owner of the data, such as a RO FID.
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 11 of 37
As the RO FID is also used by the global and local support resources, PII data of the DP Country should be redacted
when the RO FID is used to access the data.
Data redaction policies are configured and dynamically triggered at the run time based on which FID is accessing the
data
Key implementation aspect:- Evaluation condition for Oracle redaction policy for the database engine –
SYS_CONTEXT('USERENV', 'SESSION_USER') != ‘<FID owning data>'
This is the simplest form of implementation of data redaction
3.5. 3-Tier (or, N-Tier) Access Mode
In 3-tier / n-tier systems, a user logs in an application with fine-grained entitlement-based individual user ID from a
front-end UI, e.g., a browser. Upon receipt of the user request from the browser, the application components in the
middle-tiers –
connect to the database directly using a generic database FID over 2-tier client-server protocols
access the data from the database
send the data to the users via application processing and presentation layers (implemented in [n-1] tiers) of the
n-tier architecture.
Solution for this access mode needs more considerations than the simplest form of implementation of data redaction,
including the data flow mechanism of n-tier architecture as explained below.
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 12 of 37
Figure 4.
Fine-grained management of database sessions is done by separating the notion of database sessions (user
handles) from connections (server handles).
Use of sessions (typically stateless) with database connection pools is implemented in the multi-threaded mid-
tiers of n-tier architecture.
Each thread can maintain a session to the database. The actual connections to the database are maintained by
the connection pool, and these connections (including the pool of dedicated database server processes) are
shared among all the threads in the middle tier(s).
Stateless sessions are serially reusable across mid-tier threads. That means, after a thread is done processing a
database request on behalf of a 3-tier user, the same database session can be reused for a completely different
request on behalf of a completely different 3-tier user.
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 13 of 37
These aspects ensure performance, security, scalability and endurance of the mid-tiers of n-tier architecture.
Solution Design Principles for 3-tier / N-tier access mode
Either a RW FID, same as the data owner, or a RO FID, is used by the application code to access production data
directly over 2-tier client-server protocols. The database connections established by these FIDs are typically
shared (i.e., connection pooling) among the user sessions.
As a result, all user sessions established at the Presentation layer of the application are bound to the database
sessions established by the same database FID.
However, based on certain criteria, the same data must be redacted for some users and should remain un-
redacted for other users. Applications can implement various strategies (including location awareness using
browser IP address) to determine such criteria for the users.
However, as the Data Redaction should take place before the data comes out of the database (i.e., at the
source), the database engine needs to be able to differentiate between the user sessions requiring data
redaction and the user sessions without data redaction. The mechanism of this differentiator is ‘session-
tagging’, implemented using the CLIENT_IDENTIFIER property of the associated database session.
Both the application and the database engine need to do their part to make ‘session-tagging’, work properly.
Key implementation aspect
1) Application tags a new session for data redaction upon user login to the application by setting the
CLIENT_IDENTIFIER property of the session with the ‘<Redaction identifier string>’.
Determination of a user session could include, but not limited to, the logic for location awareness in
conjunction with user’s profile info
Pseudo-logic for the code snippet in the post login validation code of the application for tagging a new
session for data redaction (using Java code - tested with ojdbc5)
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 14 of 37
// User Login & Entitlement Check successful
// Get the handle of the current DB session, typically created previously with a JDBC call such as
// DriverManager.getConnection("jdbc:oracle:thin:.. .:..")
conn = (Connection ) get_CurrentDBSession();
String[] metrics = new String[OracleConnection.END_TO_END_STATE_INDEX_MAX];
// the 3rd condition in the following if statement is a return value of location awareness logic
If ( (this_app_instance is a_DP_Country_Instance) AND (the_user_country_code is NOT a_DP_Country) AND
(the_user_is_logged_in_from_outside_the_country_border_of_this_app_instance) ) {
// Set CLIENT_IDENTIFIER with <Redaction identifier string>
metrics[OracleConnection.END_TO_END_CLIENTID_INDEX] = "REDACT”;
} else {
// Reset CLIENT_IDENTIFIER when using an existing session handle e.g., from the DB connection pool
metrics[OracleConnection.END_TO_END_CLIENTID_INDEX] = ‘’;
}
// Update the DB session to set / unset data redaction
((OracleConnection) conn).setEndToEndMetrics(metrics, (short)0);
2) Database engine evaluates the condition of the data redaction policy for the corresponding session as –
(SYS_CONTEXT(‘USERENV’, ‘SESSION_USER’) != ‘<FID owning data>’ OR
SYS_CONTEXT(‘USERENV’, ‘CLIENT_IDENTIFIER’) = ‘<Redaction identifier string>’)
With this design approach involving Oracle Data Redaction tools, the high level architecture of a standard 3-tier system
components (hosted in a DP country) in Figure 3 above should look like as in Figure 5 below. The boxes with the text
‘J****D**’ represent redacted PII data as it moves thru different system components.
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 15 of 37
Figure 5.
Now that we have a high level design in place, we need to develop a prototype to demonstrate that this design actually will
work. I am a big fan of ‘seeing is believing’ – well, with reasonable expectations. So, let’s get to build the prototype.
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 16 of 37
4. Development & Testing of a Prototype Application
For this prototype, we’ll do configuration and coding for both 2-tier access and 3-tier access. For 3-tier, we need to build
something to function as middle-tiers (web & application). As we are focusing on the data redaction aspect in this article,
we’ll bypass standard authentication, authorization, secure protocol, and all other heavy footprints that are otherwise
included in a standard enterprise application. For faster time to market (or, maybe me being simply lazy and trying to
avoid more work to develop a full scale Java-based application tier, configuration and deployment in a web & app server,
etc.), I have chosen to develop a light weight Python program, to simulate the middle-tier of a 3-tier system.
Let’s get started!
4.1. Database Setup
Here we setup Oracle database FIDs with necessary privileges, create tables with data per Tables 1 & 2 in the ‘Business
Requirement’ section above, and, setup Oracle Redaction & VPD policies. This is the heart of the solution.
1. Setup Oracle database user IDs with necessary privileges
At this point, I assume you have access to an Oracle database instance with DBA privilege. Per the design principles above, we’ll create 3 Oracle FIDs.
APPMAIN – to own the data, connect from the app as the RW-FID for data access. Per the design, data accessed by the APPMAIN is conditionally redacted.
APPRO – to act as the RO-FID. Per the design, data accessed by the APPRO is always redacted.
APPSEC – to act as the security administrator FID that will own the Data Redaction and VPD policies. This is for better security and control, it meets the principle of separation of job duties, and keeps your Info Security Officers and auditors happy.
Set Oracle environment variables on your server and login to the Oracle database with DBA privilege. $ sqlplus / as sysdba
-- Run the following statements at the ‘SQL>’ command prompt
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 17 of 37
-- (Optional) Create a small tablespace for your prototype data. Otherwise, you can use an existing
-- tablespace and replace ‘myappdata’ with the name of that tablespace in the following SQL statements
SQL> create tablespace myappdata datafile '<path_of_datafile>/myappdata01.dbf' size 10M;
SQL> create user appmain identified by appmain default tablespace myappdata quota unlimited on myappdata;
SQL> grant create session, create table, create view to appmain;
SQL> create user appro identified by appro default tablespace myappdata quota unlimited on myappdata;
SQL> grant create session, create synonym to appro;
SQL> create user appsec identified by appsec default tablespace myappdata quota unlimited on myappdata;
SQL> grant create session, create procedure to appsec;
SQL> grant execute on DBMS_REDACT to appsec;
SQL> grant execute on DBMS_RLS to appsec;
--
-- The following grant is required to view session-tagging info of all connected database sessions
SQL> grant select on v_$session to appsec;
2. Create database tables, and populate them with data per Tables 1 & 2 above
a) Connect as appmain and run the DDL and DML statements SQL> connect appmain/appmain
-- Run the following statements at the ‘SQL>’ command prompt
--------------------------------------------------------
-- DDL for Table APPMAIN.CLIENT_MASTER
--------------------------------------------------------
SQL> CREATE TABLE "APPMAIN"."CLIENT_MASTER" (
"CLIENT_ID" VARCHAR2(20) NOT NULL ENABLE,
"PRIM_FIRST_NAME" VARCHAR2(20),
"PRIM_LAST_NAME" VARCHAR2(20),
"PRIM_MIDDLE_NAME" VARCHAR2(20),
"PRIM_DOB" DATE,
"CLIENT_DOMICILE_COUNTRY" VARCHAR2(20),
"PRIM_ADDRESS" VARCHAR2(50),
"PRIM_PHONE_NO" VARCHAR2(20),
"PRIM_EMAIL" VARCHAR2(30),
"CLIENT_TYPE" VARCHAR2(20),
CONSTRAINT "CLIENT_MASTER_PK" PRIMARY KEY ("CLIENT_ID") USING INDEX ENABLE );
--------------------------------------------------------
-- DMLs for Table APPMAIN.CLIENT_MASTER. These inserts the same data from Table 1.
--------------------------------------------------------
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 18 of 37
SQL> Insert into APPMAIN.CLIENT_MASTER (CLIENT_ID,PRIM_FIRST_NAME,PRIM_LAST_NAME,PRIM_MIDDLE_NAME,PRIM_DOB,
CLIENT_DOMICILE_COUNTRY,PRIM_ADDRESS,PRIM_PHONE_NO,PRIM_EMAIL,CLIENT_TYPE) values ('1001','John','Doe',
'J.', to_date('02-JAN-60','DD-MON-RR'),'CNTRY_DP','123 Main St, City1, State1', '111122223333',
'[email protected]','Individual');
SQL> Insert into APPMAIN.CLIENT_MASTER (CLIENT_ID,PRIM_FIRST_NAME,PRIM_LAST_NAME,PRIM_MIDDLE_NAME,PRIM_DOB,
CLIENT_DOMICILE_COUNTRY,PRIM_ADDRESS,PRIM_PHONE_NO,PRIM_EMAIL,CLIENT_TYPE) values ('2002','Ann','Wu',null,
to_date('12-AUG-70','DD-MON-RR'),'CNTRY_DP','678 River Ln, City2, State2','99887766XYZ','[email protected]',
'Individual');
SQL> COMMIT;
--------------------------------------------------------
-- DDL for Table APPMAIN.CLIENT_ACCT
--------------------------------------------------------
SQL> CREATE TABLE "APPMAIN"."CLIENT_ACCT" (
"CLIENT_ID" VARCHAR2(20) NOT NULL ENABLE,
"ACCT_ID" VARCHAR2(20) NOT NULL ENABLE,
"ACCT_NUMBER" VARCHAR2(20) NOT NULL ENABLE,
"ACCT_TYPE" VARCHAR2(20) NOT NULL ENABLE,
"ACCT_FULL_NAME" VARCHAR2(20),
"ACCT_DOB" DATE,
"ACCT_ADDRESS" VARCHAR2(50),
"ACCT_PHONE_NO" VARCHAR2(20),
"ACCT_EMAIL" VARCHAR2(30),
"RELN_WITH_PRIM" VARCHAR2(20),
"ACCT_DOMICILE_COUNTRY" VARCHAR2(20),
CONSTRAINT "CLIENT_ACCT_PK" PRIMARY KEY ("CLIENT_ID", "ACCT_ID") USING INDEX ENABLE );
--------------------------------------------------------
-- DMLs for Table APPMAIN.CLIENT_ACCT. These inserts the same data from Table 2.
--------------------------------------------------------
SQL> Insert into APPMAIN.CLIENT_ACCT (CLIENT_ID,ACCT_ID,ACCT_NUMBER,ACCT_TYPE,ACCT_FULL_NAME,ACCT_DOB,
ACCT_ADDRESS,ACCT_PHONE_NO, ACCT_EMAIL,RELN_WITH_PRIM,ACCT_DOMICILE_COUNTRY) values ('1001','1',
'445566777','CreditCard','John Doe',to_date('02-JAN-60','DD-MON-RR'),'123 Main St, City1, State1',
'111122223333', '[email protected]','Self', 'CNTRY_DP');
SQL> Insert into APPMAIN.CLIENT_ACCT (CLIENT_ID,ACCT_ID,ACCT_NUMBER,ACCT_TYPE,ACCT_FULL_NAME,ACCT_DOB,
ACCT_ADDRESS,ACCT_PHONE_NO,ACCT_EMAIL,RELN_WITH_PRIM,ACCT_DOMICILE_COUNTRY) values ('1001','2',
'445561727','CreditCard','Jane Doe',to_date('05-MAR-62','DD-MON-RR'),'123 Main St, City1, State1',
'111122223344','[email protected]','Spouse','CNTRY_DP');
SQL> Insert into APPMAIN.CLIENT_ACCT (CLIENT_ID,ACCT_ID,ACCT_NUMBER,ACCT_TYPE,ACCT_FULL_NAME,ACCT_DOB,
ACCT_ADDRESS,ACCT_PHONE_NO,ACCT_EMAIL,RELN_WITH_PRIM,ACCT_DOMICILE_COUNTRY) values ('2002','3',
'33245','Savings','Ann Wu',to_date('12-AUG-70','DD-MON-RR'),'678 River Ln, City2, State2',
'99887766XYZ','[email protected]','Self','CNTRY_DP');
SQL> Insert into APPMAIN.CLIENT_ACCT (CLIENT_ID,ACCT_ID,ACCT_NUMBER,ACCT_TYPE,ACCT_FULL_NAME,ACCT_DOB,
ACCT_ADDRESS,ACCT_PHONE_NO,ACCT_EMAIL,RELN_WITH_PRIM,ACCT_DOMICILE_COUNTRY) values ('2002','4',
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 19 of 37
'22567','Checking','Ann Wu',to_date('12-AUG-70','DD-MON-RR'),'678 River Ln, City2, State2',
'99887766XYZ','[email protected]','Self','CNTRY_DP');
SQL> Insert into APPMAIN.CLIENT_ACCT (CLIENT_ID,ACCT_ID,ACCT_NUMBER,ACCT_TYPE,ACCT_FULL_NAME,ACCT_DOB,
ACCT_ADDRESS,ACCT_PHONE_NO,ACCT_EMAIL,RELN_WITH_PRIM,ACCT_DOMICILE_COUNTRY) values ('2002','5',
'S1234','Student Loan','David Wu',to_date('21-SEP-97','DD-MON-RR'),'888 College Blvd, X-City, Y-State',
'99887456XYZ','[email protected]','Son','CNTRY_Non_DP');
SQL> Insert into APPMAIN.CLIENT_ACCT (CLIENT_ID,ACCT_ID,ACCT_NUMBER,ACCT_TYPE,ACCT_FULL_NAME,ACCT_DOB,
ACCT_ADDRESS,ACCT_PHONE_NO,ACCT_EMAIL,RELN_WITH_PRIM,ACCT_DOMICILE_COUNTRY) values ('2002','6',
'6677889901','CreditCard','Amy Wu',to_date('18-MAY-00','DD-MON-RR'),'678 River Ln, City2, State2',
'99881234XYZ','[email protected]','Daughter','CNTRY_DP');
SQL> COMMIT;
--------------------------------------------------------
-- DDL for Table APPMAIN.USER_TBL
-- This table is to simulate mapping between users and their locations.
--------------------------------------------------------
SQL> CREATE TABLE "APPMAIN"."USER_TBL" (
"USER_ID" VARCHAR2(10) NOT NULL ENABLE,
"USER_LOCATION" VARCHAR2(20) NOT NULL ENABLE,
CONSTRAINT "USER_TBL_PK" PRIMARY KEY ("USER_ID") USING INDEX ENABLE );
--------------------------------------------------------
-- DMLs for Table APPMAIN.USER_TBL. 2 users for CNTRY_DP and 2 users for CNTRY_Non_DP.
--------------------------------------------------------
SQL> Insert into APPMAIN.USER_TBL (USER_ID,USER_LOCATION) values ('user1','CNTRY_Non_DP');
SQL> Insert into APPMAIN.USER_TBL (USER_ID,USER_LOCATION) values ('user2','CNTRY_DP');
SQL> Insert into APPMAIN.USER_TBL (USER_ID,USER_LOCATION) values ('user3','CNTRY_DP');
SQL> Insert into APPMAIN.USER_TBL (USER_ID,USER_LOCATION) values ('user4','CNTRY_Non_DP');
SQL> COMMIT;
b) Grant RO access and create synonyms -- Run the following commands at the ‘SQL>’ command prompt
SQL> connect appmain/appmain
SQL> grant select on appmain.client_master to appro;
SQL> grant select on appmain.client_acct to appro;
SQL> grant select on appmain.user_tbl to appro;
SQL>
SQL> connect appro/appro
SQL> create synonym client_master for appmain.client_master;
SQL> create synonym client_acct for appmain.client_acct;
SQL> create synonym user_tbl for appmain.user_tbl;
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 20 of 37
3. Setup Oracle Redaction & VPD policies
After creation of the Data Redaction policy, it is automatically enabled and ready to redact data with immediate effect. Connect as appsec and run the following statements at the ‘SQL>’ command prompt to setup Oracle Redaction and VPD policies - SQL> connect appsec/appsec
------------------------------------------
-- For Column Level Security - using Oracle Redact
-- This is to redact client master data - at the column level (i.e., top part) in the UI
------------------------------------------
SQL> BEGIN
DBMS_REDACT.ADD_POLICY (
object_schema => 'APPMAIN',
object_name => 'CLIENT_MASTER',
policy_name => 'CLIENT_REDACT',
expression => 'SYS_CONTEXT(''USERENV'', ''SESSION_USER'') != ''APPMAIN'' OR
SYS_CONTEXT(''USERENV'', ''CLIENT_IDENTIFIER'') = ''REDACT'' ',
column_name => 'PRIM_DOB',
function_type => DBMS_REDACT.PARTIAL,
function_parameters => 'm12d31y2016'); -- setting dates to a specific value instead of masking chars
DBMS_REDACT.ALTER_POLICY (
object_schema => 'APPMAIN',
object_name => 'CLIENT_MASTER',
policy_name => 'CLIENT_REDACT',
action => DBMS_REDACT.ADD_COLUMN,
column_name => 'PRIM_FIRST_NAME',
function_type => DBMS_REDACT.REGEXP,
function_parameters => NULL,
regexp_pattern => '(.)',
regexp_replace_string => '*' );
DBMS_REDACT.ALTER_POLICY (
object_schema => 'APPMAIN',
object_name => 'CLIENT_MASTER',
policy_name => 'CLIENT_REDACT',
action => DBMS_REDACT.ADD_COLUMN,
column_name => 'PRIM_LAST_NAME',
function_type => DBMS_REDACT.REGEXP,
function_parameters => NULL,
regexp_pattern => '(.)',
regexp_replace_string => '*' );
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 21 of 37
DBMS_REDACT.ALTER_POLICY (
object_schema => 'APPMAIN',
object_name => 'CLIENT_MASTER',
policy_name => 'CLIENT_REDACT',
action => DBMS_REDACT.ADD_COLUMN,
column_name => 'PRIM_MIDDLE_NAME',
function_type => DBMS_REDACT.REGEXP,
function_parameters => NULL,
regexp_pattern => '(.)',
regexp_replace_string => '*');
DBMS_REDACT.ALTER_POLICY (
object_schema => 'APPMAIN',
object_name => 'CLIENT_MASTER',
policy_name => 'CLIENT_REDACT',
action => DBMS_REDACT.ADD_COLUMN,
column_name => 'PRIM_PHONE_NO',
function_type => DBMS_REDACT.REGEXP,
function_parameters => NULL,
regexp_pattern => '(.)',
regexp_replace_string => '9');
DBMS_REDACT.ALTER_POLICY (
object_schema => 'APPMAIN',
object_name => 'CLIENT_MASTER',
policy_name => 'CLIENT_REDACT',
action => DBMS_REDACT.ADD_COLUMN,
column_name => 'PRIM_EMAIL',
function_type => DBMS_REDACT.REGEXP,
function_parameters => NULL,
regexp_pattern => DBMS_REDACT.RE_PATTERN_EMAIL_ADDRESS,
regexp_replace_string => DBMS_REDACT.RE_REDACT_EMAIL_ENTIRE);
DBMS_REDACT.ALTER_POLICY (
object_schema => 'APPMAIN',
object_name => 'CLIENT_MASTER',
policy_name => 'CLIENT_REDACT',
action => DBMS_REDACT.ADD_COLUMN,
column_name => 'PRIM_ADDRESS',
function_type => DBMS_REDACT.REGEXP,
function_parameters => NULL,
regexp_pattern => '(.)',
regexp_replace_string => '*');
END;
/
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 22 of 37
------------------------------------------
-- For Row Level Security - using Oracle VPD
-- This is to redact the client account data – at the row level in the UI
------------------------------------------
SQL> CREATE OR REPLACE FUNCTION POLICY_FUNC_CLIENT_ACCT
(schema IN VARCHAR2, tab IN VARCHAR2) RETURN VARCHAR2 AS
predicate VARCHAR2(4000) DEFAULT NULL;
BEGIN
IF (SYS_CONTEXT('USERENV', 'SESSION_USER') != 'APPMAIN' OR
SYS_CONTEXT('USERENV', 'CLIENT_IDENTIFIER') = 'REDACT') THEN
predicate := ' ACCT_DOMICILE_COUNTRY != ''CNTRY_DP'' ';
ELSE
NULL;
END IF;
RETURN predicate;
END;
/
SQL> BEGIN
DBMS_RLS.ADD_POLICY (
object_schema => 'APPMAIN',
object_name => 'CLIENT_ACCT',
policy_name => 'VPD_CLIENT_ACCT',
function_schema => 'APPSEC',
policy_function => 'POLICY_FUNC_CLIENT_ACCT',
statement_types => 'SELECT',
policy_type => DBMS_RLS.CONTEXT_SENSITIVE,
sec_relevant_cols_opt => DBMS_RLS.ALL_ROWS,
sec_relevant_cols => 'ACCT_NUMBER,ACCT_FULL_NAME,ACCT_DOB,ACCT_ADDRESS,ACCT_PHONE_NO,ACCT_EMAIL');
END;
/
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 23 of 37
4.2. Verification of Database Setup
Assuming the above mentioned steps for setting up database for our prototype application are successful, let’s check out if
things are working properly per the design. We can use any SQL tool for this verification step. I have used the SQL Developer
tool so that all output columns of the tables can be accommodated, even if partially, in the screen.
1) Login as appmain, query client master and client account tables. Per design, all data items should be visible as the appmain
FID owns this data.
Figure 6. Querying appmain.client_master as the appmain FID
Figure 7. Querying appmain.client_acct as the appmain FID
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 24 of 37
2) Login as appro and query client master and client account tables. Per design, PII data items of CNTRY_DP should be
redacted when accessed by the RO FID, i.e., appro, except the Student Loan account record, as it is owned by
CNTRY_Non_DP.
Figure 8. Querying appmain.client_master as the appro FID
Figure 9. Querying appmain.client_account as the appro FID
It is to be noted that Oracle VPD has not implemented use of selective (i.e., partial/full/regex) masking of data. The default
masked content is ‘NULL’, therefore ‘(null)’ in the PII data columns, whose actual stored values can be seen in Figure 7.
This concludes the proof of concept of 2-tier data access as per our design criteria. Next, we’ll build the middle tiers (web and
application) of our prototype application.
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 25 of 37
4.3. Middle-Tier (Web and Application) Setup
For our Python based middle-tiers (web and application), the approach is to use Python’s CGI scripting framework along
with Python HTTPServer modules. Figure 10 shows the contents of the entire middle-tier setup under a folder on a Unix
server.
Figure 10. Contents of the middle-tier components of the prototype
Folder and Files Description
cgi-bin This folder contains the Python scripts based on CGI framework. The scripts in this folder simulates the mechanisms of the web and application tiers as shown in Figure 4 above.
cgi-bin/app3tier.py This script is the main application code that accepts input from a browser based UI, retrieves data from the database, and sends formatted response back to the browser UI for rendering.
cgi-bin/multi.py This script establishes a listening endpoint (default port = 55123) on the server, accepts simultaneous connections from the browsers, and handles those connections by multithreading them.
app3tier.html This is a simple html file (created with Notepad – keeping in line with my moto of faster-time-to-market) that works as the point of entry into the prototype application and to render the UI in a browser. You would invoke this from your browser as – “http://<your_server_name>:55123/app3tier.html”
my.env This is to set the environment variables like ORACLE_HOME, ORACLE_SID, PATH, LD_LIBRARY_PATH, etc. so that the python scripts find the path to Python modules and Oracle drivers. It’s a good practice to keep all these items together in a single file.
startSvr.sh This script starts the HTTP server and the server side runtime environment of the prototype application.
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 26 of 37
Code:- app3tier.html <html>
<title>Data Redaction ProtoType</title>
<body>
<form action="/cgi-bin/app3tier.py" method="post" target="out_iframe">
<table>
<tr style="background-color:cyan;width=100%;text-align=center"><td colspan="3">Simulation of a 3-tier
application hosted in a Data Privacy Country (CNTRY_DP)</td></tr>
<tr>
<td>Login with User Id: <input type="text" name="UserId"></td>
<td>(Hint: Enter one of - user1, user2, user3, user4 for this exercise)</td>
<td rowspan="2" style="padding-left:100px"> <input type="submit" value="View Client Info" /> </td>
</tr>
<tr>
<td>Lookup Client ID : <input type="text" name="CID"></td>
<td>(Hint: Enter one of - 1001, 2002 for this exercise)</td>
</tr>
</table>
</form>
<iframe name="out_iframe" src="/cgi-bin/app3tier.py" width="100%" height="80%"></iframe>
</body>
</html>
Code:- my.env export ORACLE_HOME=<Your_Oracle_Home_Path_Here. I tested with Oracle DB 11.2.0.4>
export ORACLE_SID=<Your_Oracle_SID_Here>
export LD_LIBRARY_PATH=$ORACLE_HOME/lib
export PATH=$ORACLE_HOME/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:.
# Add other paths as needed in your environment. Python executable is in /usr/bin in my RHEL server environment
Code:- startSvr.sh . ./my.env
python cgi-bin/multi.py
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 27 of 37
Code:- cgi-bin/multi.py #!/bin/env python
import sys, SocketServer, BaseHTTPServer, CGIHTTPServer
class MyLittleThreadingServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
pass
# default listening port is 55123, if no port number is passed as command line argument
if sys.argv[1:]:
port = int(sys.argv[1])
else:
port = 55123
print "Oh no, not again :-(..."
myserver = MyLittleThreadingServer(('', port), CGIHTTPServer.CGIHTTPRequestHandler)
try:
while 1:
sys.stdout.flush()
myserver.handle_request()
except KeyboardInterrupt:
# Ctrl+C to terminate
print "\nFinally Done! Thank God!"
Code:- cgi-bin/app3tier.py #!/usr/bin/python
import os, sys, cgi, cgitb, cx_Oracle
# class definition
class app3tier(object):
# main function
def main(self, argv):
form = cgi.FieldStorage()
# Get user input from the two text input fields of app3tier.html
self.UserId = form.getvalue('UserId')
self.CID = form.getvalue('CID')
self.IsRedact = None
self.UserLocation = None
self.cur = None
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 28 of 37
self.con = None
self.IsOk = True
print "Content-type:text/html\r\n\r\n"
print "<html><head><title>Data Redaction Prototype</title>"
print "<style> th { background-color: lavender; text-align: left } </style></head><body>"
if (self.UserId is not None):
try:
# Connect to the Oracle database using the RW-FID appmain. In real enterprise application,
# this will likely be grabing an existing connection from the DB connection pool.
self.con = cx_Oracle.connect("appmain", "appmain", "<Name_of_Oracle_DB_Instance>")
self.cur = self.con.cursor()
# Upon successful connection to the database, determine if this session should be redacted
self.getUserLocation()
# If no error occured while determining the location of the user, and evaluating data
# redaction criteria, query the master record
if self.IsOk:
self.getMasterRecord()
# If no error occured obtaining the master record, query the account records
if self.IsOk:
self.getAcctRecords()
except cx_Oracle.DatabaseError, exc:
error, = exc
print "Error:- ", error.message
print "</body></html>"
# Flush output buffer so that the browser receives all contents sent by the print statements
sys.stdout.flush()
# Uncomment the following line (i.e. raw_input()) if interested in viewing tagged DB sessions using a SQL tool.
# The idea is to put a hold on the connections established from this script from being closed in the following
# lines of this main function. However, as there is no mechanism from these threads to accept keyboard input,
# there will be errors thrown at the server end, which is ok I guess, because uncommenting this line is just
# for testing purpose. Figure 14 shows the result of my testing by uncommenting the line with raw_input().
# raw_input("Paused here")
if self.cur != None:
self.cur.close()
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 29 of 37
if self.con != None:
self.con.close()
# This function determines the location of the user, evaluates if data redaction should apply to this
# session, and sends the evaluation result along with the user input back to the browser.
def getUserLocation(self):
print "<table border=1><tr>"
print "<td><b>User Input:- Login Id= %s, Client ID= %s</b></td>" % (self.UserId, self.CID)
try:
self.cur.execute("select user_location from user_tbl where user_id = '" + self.UserId + "'")
row1 = self.cur.fetchone ()
if row1 == None:
self.UserLocation = 'Invalid UserId! Try again'
self.IsRedact = False
self.IsOk = False
else:
self.UserLocation = row1[0]
# Per design, as all non CNTRY_DP users should receive redacted data over 3-tier access,
# their corresponding database sessions should be tagged accordingly so that the Oracle
# database engine can apply the Redaction and VPD policies appropriately.
if (self.UserLocation != "CNTRY_DP"):
self.IsRedact = True
self.con.client_identifier = 'REDACT'
else:
self.IsRedact = False
self.con.client_identifier = ''
except cx_Oracle.DatabaseError, exc:
error, = exc
print "Error:- ", error.message
self.IsOk = False
print "<td><b>Login Validation:- User Location= %s, Data Redaction= %s </b></td>"
% (self.UserLocation, ("ON" if self.IsRedact else "Off"))
print "</tr></table><p />"
return;
# This function simply queries the database for the master record, and sends the data, as returned by
# the database, to the browser. The to_char function is used to trim the time part of the DOB field
# from appearing in the UI; just a little cosmetic thing. Other than that, there is no need to format
# the redacted data here as Oracle DB engine already masks the data as defined in the Data Redaction
# policies (i.e., using DBMS_REDACT functions) for column level data redaction.
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 30 of 37
def getMasterRecord(self):
try:
stmt1 = ("select client_id, client_domicile_country, prim_first_name, prim_middle_name, "
"prim_last_name, client_type, to_char(prim_dob, 'YYYY-MM-DD') , prim_phone_no, "
"prim_address, prim_email from samapp_id.client_master where client_id = '" + self.CID + "'")
self.cur.execute(stmt1)
print "<table border=1>"
print "<tr><th colspan=""4"">Client Master Record ===== [ ", \
("Column Level" if self.IsRedact else "NO"), " Data Redaction ]</th></tr>"
for row in self.cur:
print "<tr><th>Client ID</th><td>", row[0],"</td><th>Domicile Country</th><td>", \
row[1], "</td></tr>"
print "<tr><th>First Name (Primary)</th><td", \
(' style="background: yellow">' if ( row[2] is not None and self.IsRedact ) else '>'), \
row[2],"</td><th>Middle Name (Primary)</th><td", \
(' style="background: yellow">' if ( row[3] is not None and self.IsRedact ) else '>'), \
row[3],"</td></tr>"
print "<tr><th>Last Name (Primary)</th><td", \
(' style="background: yellow">' if ( row[4] is not None and self.IsRedact ) else '>'), \
row[4],"</td><th>Client Type</th><td>", row[5],"</td></tr>"
print "<tr><th>DOB (Primary)</th><td", \
(' style="background: yellow">' if ( row[6] is not None and self.IsRedact ) else '>'), \
row[6],"</td><th>Phone (Primary)</th><td", \
(' style="background: yellow">' if ( row[7] is not None and self.IsRedact ) else '>'), \
row[7],"</td></tr>"
print "<tr><th>Address (Primary)</th><td", \
(' style="background: yellow">' if ( row[8] is not None and self.IsRedact ) else '>'), \
row[8],"</td><th>Email (Primary)</th><td", \
(' style="background: yellow">' if ( row[9] is not None and self.IsRedact ) else '>'), \
row[9],"</td></tr>"
except cx_Oracle.DatabaseError, exc:
error, = exc
print "Error:- ", error.message
self.IsOk = False
print "</table><p />"
return;
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 31 of 37
# This function queries the database for account records along with some formatting on the data at the
# database level, and sends the contents from the database to the browser. This additional formatting is
# needed here because we are dealing with row level data redaction for the account records, and Oracle VPD
# (i.e., using DBMS_RLS functions) is used for row level data redaction. As the DBMS_RLS package is not as
# mature as the DBMS_REDACT package in terms of data masking, it returns the default value of '(null)' for
# masked data. Hence, the additional treatment of the null values in the SQL while retrieving account data.
def getAcctRecords(self):
try:
stmt1 = ("select acct_id, acct_type, nvl(acct_number, '*****'), "
"nvl(acct_full_name, '***********'), decode(acct_dob, null, '****-**-**', "
"to_char(acct_dob, 'YYYY-MM-DD')), nvl(acct_address, '*********'), "
"nvl(acct_phone_no,'*********'), nvl(acct_email, '****@***.***'), reln_with_prim, "
"acct_domicile_country from samapp_id.client_acct where client_id = '" + self.CID + "' ")
self.cur.execute(stmt1)
print "<table border=1>"
print "<tr><th colspan=""10"">Account Information for this client ===== [ ", \
("Row Level" if self.IsRedact else "NO"), " Data Redaction ]</th></tr>"
print "<tr><th width=""5%"">Account ID</th><th>Account Type</th>" \
"<th width=""7%"">Account Number</th>"
print "<th>Full Name</th><th width=""9%"">DOB</th><th>Address</th><th>Phone #</th>"
print "<th>Email</th><th width=""5%"">Relationship with Primary</th>" \
"<th width=""7%"">Account Domicile Country</tr>"
for row in self.cur:
print "<tr>"
for j in range (0,10):
print "<td", (' style="background: yellow">' \
if ( self.IsRedact and row[j].startswith('***') ) else '>'), row[j], "</td>"
print "</tr>"
except cx_Oracle.DatabaseError, exc:
error, = exc
print "Error:- ", error.message
self.IsOk = False
print "</table>"
return;
# Point of entry
app3tier().main(sys.argv[1:])
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 32 of 37
4.4. Testing 3-tier Prototype
1) Starting & stopping the middle-tier server.
a. Go to the folder containing the middle-tier files, as shown in Figure 10, on your Unix server.
b. Run ‘./startSvr.sh’ at the command prompt to start the middle-tier server.
c. Press Ctrl+C in the Unix server terminal to stop the middle-tier server.
Figure 11. Start, execution log, and termination of the middle-tier server
2) Access the Application UI for testing.
a. Once the middle-tier server is started, open a browser session in your PC/workstation.
b. enter the following URL - http://<hostname_running_middle-tier_server>:55123/app3tier.html
c. enter values in the User Id and Client ID fields and click on ‘View Client Info’ button
d. for the User Ids (user2 & user3) belonging to CNTRY_DP, data is NOT redacted. The UI looks like Figure 12.
e. for the User Ids (user1 & user4) NOT belonging to CNTRY_DP, data is redacted. The UI looks like Figure 13.
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 33 of 37
Figure 12: Data NOT redacted for the users belonging to CNTRY_DP
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 34 of 37
Figure 13: Data redacted for the users NOT belonging to CNTRY_DP
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 35 of 37
3) Verify session tagging at the database level for multiple concurrent sessions using 3-tier access.
a. Login as appmain, appro, and appsec FIDs to the database simultaneously using a SQL tool (e.g., SQL Developer,
SQL*Plus, etc.).
b. Open the ‘cgi-bin/app3tier.py’ file in an editor, uncomment the line that has the ‘raw_input("Paused here")’
function, and save the file. This will keep the python threads created by the HTTPServer running, and therefore the
corresponding database connections from the middle-tier application will stay alive so that we can view them with
a SQL tool.
c. (Optional) Although it is not necessary to stop the middle-tier server process in order for this change to take effect,
but if you want, you may stop and restart the middle-tier server process before proceeding to the next step.
d. Open a few browser sessions, enter the app UI URL, and use different user Ids in each of them. The browser UI will
render the contents properly but the terminal window of the middle-tier server process (similar to Figure 11) will
have a few error messages, which is expected as a result of the step (b) above.
e. Go to the SQL tool window of the database session established by the appsec FID, and run the following SQL
statement.
select sys_context(‘USERENV’, ‘SESSION_USER’) userid, sid, username,
client_identifier, osuser, machine, status, program
from v$session where username like 'APP%' ;
You’ll see all established database sessions originated from 2-tier and 3-tier processes with some of the 3-tier
related database sessions tagged with the redaction identifier string ‘REDACT’ (in the CLIENT_IDENTIFIER column).
The output should be similar to Figure 14.
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 36 of 37
Figure 14:- Verification of session tagging from 3-tier access
For the test results shown in Figures 11, 12, 13 & 14, I used SQL Developer tool and IE browser from my windows login id
‘sam1’ on my PC named ‘myWin10PC’. I used a RHEL server named ‘RHEL-DevSvr’, on which the middle-tier scripts (i.e.,
.sh, .py, etc.) ran as the ‘pyusr’ user id.
Addressing Data Privacy Challenges In Global Applications | Sambit Banerjee
Page 37 of 37
5. Conclusion
So, the outcome of these tests meets the business requirements and the technical solution design as laid out in this article.
By using a combination of Oracle Redaction and VPD features, we have addressed a few common challenges for
implementation of cross-border Data Privacy application.
This solution can be extended further to solve a number of other business problems involving sensitive data, even at
intra-country level. Using this solution approach, it is possible to identify the Oracle database sessions associated with
fine-grained application entitlement based user ids of a 3 / n tier application.
For example, the redaction identifier string can be built by the post login application code as ‘REDACT_userN_locationY’,
and then different Oracle Redaction and VPD policies can be defined based on the pattern of the substrings in the
redaction identifier string ‘REDACT_userN_locationY’. This helps establishing an end-to-end traceability of a user session
within 3 / n-tier application.
If you are also in the same boat of ‘seeing is believing’, and would like to get your hands dirty, please feel free to use the
code, configuration, data included in this article, add your own data and policies to test various use cases of your choice.
Finally, any feedback on this article is welcome!