Top Banner
Apex and Virtual Private Database Jeffrey Kemp InSync Perth, Nov 2013
44

Apex and Virtual Private Database

Jun 20, 2015

Download

Technology

Jeffrey Kemp

Oracle Application Express and Oracle Row-Level Security (RLS) (aka Virtual Private Database) work very well together. Using RLS you can have one database serve different groups of users while virtually guaranteeing that no-one will be able to view or update data they aren't supposed to. That was the sales pitch. This presentation will be a case study on one small Apex application with complex security requirements. The author started with a complex solution using views which performed poorly and didn't satisfy all the user's requirements. When he switched to a solution using RLS, the application became significantly simpler and faster, and all user requirements were met.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Apex and Virtual Private Database

Apex and Virtual Private Database

Jeffrey Kemp

InSync Perth, Nov 2013

Page 2: Apex and Virtual Private Database

Why use VPD?

• Security

• Simplicity

• Flexibility

• No backdoors

Page 3: Apex and Virtual Private Database
Page 4: Apex and Virtual Private Database

Acronym Overload

• Virtual Private Database

• Row Level Security

• Fine-Grained Access Control

Page 5: Apex and Virtual Private Database

His

tory

8i VPD introduced; supports tables and views

9i global application contexts support for synonyms policy groups

10g column-level privacy column masking static policies shared policies

11g integrated into Enterprise Manager

12c improved security for expdp fine-grained context-sensitive policies

Page 6: Apex and Virtual Private Database
Page 7: Apex and Virtual Private Database

Requirements

• Enterprise Edition

• execute on DBMS_RLS

Page 8: Apex and Virtual Private Database

Disclaimer

not an expert

expertise

Page 9: Apex and Virtual Private Database

Case Study: eBud

• Budgeting solution for a large government department

• Groups of users: “Super Admins”, “Finance”, “Managers”

• Super Admin: "access all areas"

• Finance: "access to most areas"

• Managers: "limited access"

Page 10: Apex and Virtual Private Database

eBud Data Model BUDGETS budget_id budget_owner budget_publicity

BUDGET_ENTRIES chart amount

COST_CENTRES cost_centre branch_code

USERS username role_list

Row-level security required

Page 11: Apex and Virtual Private Database

Solution #1 Query:

SELECT budget_id, name FROM budgets_vw WHERE budget_id = :b1;

View:

CREATE VIEW budgets_vw AS

SELECT * FROM budgets WHERE budget_owner = v('APP_USER');

Page 12: Apex and Virtual Private Database

Solution #2

V.P.D.

Image source: http://www.executiveinvestigationandsecurity.com/security/

Page 13: Apex and Virtual Private Database

Row Level Security The query you asked for:

SELECT budget_id, name FROM budgets WHERE budget_id = :b1;

What we executed:

SELECT budget_id, name FROM budgets WHERE budget_id = :b1

AND budget_owner = SYS_CONTEXT('EBUD_CTX','APP_USER');

(not exactly, but this gives the general idea)

Page 14: Apex and Virtual Private Database

Package spec PACKAGE vpd_pkg IS

PROCEDURE new_session;

FUNCTION budgets_policy

( object_schema IN VARCHAR2

, object_name IN VARCHAR2

) RETURN VARCHAR2;

END vpd_pkg;

Page 15: Apex and Virtual Private Database

Initialise an Apex Session

PROCEDURE new_session IS

BEGIN

set_context('APP_USER', v('APP_USER'));

set_context('SUPERADMIN', is_superadmin);

set_context('FINANCE', is_finance_user);

END new_session;

Page 16: Apex and Virtual Private Database

Set Context PROCEDURE set_context ( i_attr IN VARCHAR2 , i_value IN VARCHAR2 ) IS BEGIN DBMS_SESSION.set_context ( namespace => 'EBUD_CTX' , attribute => i_attr , value => i_value , client_id => v('APP_USER') || ':' || v('SESSION') ); END set_context;

Page 17: Apex and Virtual Private Database

Create an Application Context

CREATE CONTEXT EBUD_CTX USING VPD_PKG ACCESSED GLOBALLY;

Page 18: Apex and Virtual Private Database

Apex Setup 1. Authentication Scheme

2. (no step 2!)

Page 19: Apex and Virtual Private Database
Page 20: Apex and Virtual Private Database

Policy Function body #1 FUNCTION budgets_policy

( object_schema IN VARCHAR2

, object_name IN VARCHAR2

) RETURN VARCHAR2 IS

BEGIN

RETURN q'[

budget_owner = SYS_CONTEXT('EBUD_CTX','APP_USER')

]';

END budgets_policy;

Page 21: Apex and Virtual Private Database

(old quote syntax) FUNCTION budgets_policy

( object_schema IN VARCHAR2

, object_name IN VARCHAR2

) RETURN VARCHAR2 IS

BEGIN

RETURN '

budget_owner = SYS_CONTEXT(''EBUD_CTX'',''APP_USER'')

';

END budgets_policy;

Page 22: Apex and Virtual Private Database

Create a Policy begin

DBMS_RLS.add_policy

( object_name => 'BUDGETS'

, policy_name => 'budgets_policy'

, policy_function => 'VPD_PKG.budgets_policy'

);

end;

/

Page 23: Apex and Virtual Private Database

Create a Policy begin

DBMS_RLS.add_policy

( object_name => 'BUDGETS'

, policy_name => 'budgets_policy'

, policy_function => 'VPD_PKG.budgets_policy'

, statement_types => 'SELECT'

);

end;

/

Page 24: Apex and Virtual Private Database

DBMS_RLS.add_policy • object_schema (NULL for current user) • object_name (table or view) • policy_name • function_schema (NULL for current user) • policy_function • statement_types

(default is SELECT, INSERT, UPDATE, DELETE) • policy_type • (other optional parameters)

Page 25: Apex and Virtual Private Database

How it works Query:

SELECT budget_id, name FROM budgets WHERE budget_id = :b1;

Parser calls function:

budget_owner = SYS_CONTEXT('EBUD_CTX','APP_USER')

Executed:

SELECT budget_id, name FROM ( SELECT * FROM budgets budgets WHERE budget_owner = SYS_CONTEXT('EBUD_CTX','APP_USER') ) WHERE budget_id = :b1;

Page 26: Apex and Virtual Private Database

Policy Function body #2 FUNCTION budgets_policy

(object_schema IN VARCHAR2

,object_name IN VARCHAR2

) RETURN VARCHAR2 IS

BEGIN

RETURN q'[

budget_owner = SYS_CONTEXT('EBUD_CTX','APP_USER')

OR budget_publicity = 'PUBLIC'

]';

END budgets_policy;

Page 27: Apex and Virtual Private Database

Policy Function body #3 FUNCTION budgets_policy

(object_schema IN VARCHAR2

,object_name IN VARCHAR2

) RETURN VARCHAR2 IS

BEGIN

RETURN q'[

budget_owner = SYS_CONTEXT('EBUD_CTX','APP_USER')

OR budget_publicity = 'PUBLIC'

OR (budget_publicity = 'FINANCE'

AND SYS_CONTEXT('EBUD_CTX','FINANCE') = 'Y')

OR SYS_CONTEXT('EBUD_CTX','SUPERADMIN') = 'Y'

]';

END budgets_policy;

Page 28: Apex and Virtual Private Database

Policy Function body #4 FUNCTION budgets_policy (object_schema IN VARCHAR2 ,object_name IN VARCHAR2 ) RETURN VARCHAR2 IS o_predicate VARCHAR2(4000); BEGIN IF SYS_CONTEXT('EBUD_CTX','SUPERADMIN') = 'Y' THEN o_predicate := ''; ELSE o_predicate := q'[ budget_publicity = 'PUBLIC' OR (budget_publicity = 'FINANCE' AND SYS_CONTEXT('EBUD_CTX','FINANCE') = 'Y') OR budget_owner = SYS_CONTEXT('EBUD_CTX','APP_USER') ]'; END IF; RETURN o_predicate; END budgets_policy;

Page 29: Apex and Virtual Private Database

Polic

y Fu

nct

ion

bo

dy

#5

FUNCTION budgets_policy (object_schema IN VARCHAR2 ,object_name IN VARCHAR2 ) RETURN VARCHAR2 IS o_predicate VARCHAR2(4000); BEGIN IF SYS_CONTEXT('EBUD_CTX','SUPERADMIN') = 'Y' THEN o_predicate := ''; ELSIF SYS_CONTEXT('EBUD_CTX','FINANCE') = 'Y' THEN o_predicate := q'[ budget_publicity IN ('PUBLIC','FINANCE') OR budget_owner = SYS_CONTEXT('EBUD_CTX','APP_USER') ]'; ELSE o_predicate := q'[ budget_publicity = 'PUBLIC' OR budget_owner = SYS_CONTEXT('EBUD_CTX','APP_USER') ]'; END IF; RETURN o_predicate; END budgets_policy;

lots of different queries in shared pool

Page 30: Apex and Virtual Private Database

Hierarch

y Division

Directorate

Branch

Cost Centre

Cost Centre

Branch

Cost Centre

Directorate

Branch

Cost Centre

Cost Centre

"Co

st C

entr

e G

rou

ps"

Page 31: Apex and Virtual Private Database

eBud Data Model BUDGETS budget_id budget_owner budget_publicity

COST_CENTRES cost_centre branch_code

USER_COST_CENTRES USERS username role_list

USER_COST_CENTRE_GROUPS group_code

COST_CENTRE_GROUPS parent_group_code

hierarchy

Page 32: Apex and Virtual Private Database

Cost Centre Policy

Function

FUNCTION cost_centre_policy (object_schema IN VARCHAR2, object_name IN VARCHAR2) RETURN VARCHAR2 IS

BEGIN

IF SYS_CONTEXT('EBUD_CTX','FINANCE') = 'Y' THEN

RETURN '';

ELSE

RETURN q'[

EXISTS (

SELECT null

FROM user_cost_centres ucc

WHERE ucc.username = SYS_CONTEXT('EBUD_CTX','APP_USER')

AND ucc.cost_centre = cost_centres.cost_centre

)

OR EXISTS (

SELECT null

FROM all_budget_branches_vw b

JOIN user_cost_centre_groups uccg

ON uccg.group_code IN

(b.branch_code, b.directorate_code, b.division_code)

WHERE uccg.username = SYS_CONTEXT('EBUD_CTX','APP_USER')

AND b.budget_id = cost_centres.budget_id

AND b.branch_code = cost_centres.branch_code

)

]';

END IF;

END cost_centre_policy;

we can refer to the table via its alias

Page 33: Apex and Virtual Private Database

Warning

Predicate MUST NOT query the table to which it is meant to be applied - not even via a view

Image source: http://en.wikipedia.org/wiki/Drawing_Hands

Page 34: Apex and Virtual Private Database

But…

The predicate may query another table that itself has an RLS policy.

Page 35: Apex and Virtual Private Database

Budget Entry Policy Function FUNCTION budget_entry_policy (object_schema IN VARCHAR2, object_name IN VARCHAR2) RETURN VARCHAR2 IS

BEGIN

IF SYS_CONTEXT('EBUD_CTX','FINANCE') = 'Y' THEN

RETURN '';

ELSE

RETURN q'[

EXISTS (

SELECT null

FROM cost_centres cc

WHERE cc.cost_centre = budget_entries.cost_centre

AND cc.budget_id = budget_entries.budget_id

)

]';

END IF;

END budget_entry_policy;

Page 36: Apex and Virtual Private Database

Policy Type parameter (10g+)

Re-Executed for each for all

statement DYNAMIC (default)

object STATIC SHARED_STATIC

context CONTEXT_SENSITIVE SHARED_CONTEXT_SENSITIVE

If in doubt, always start with the default - DYNAMIC

consider SHARED_... if your policy function is shared amongs multiple tables

The policy type parameter is just for performance optimisation.

Page 37: Apex and Virtual Private Database

Improved in 12c

Fine-grained Context Sensitive policies

– new parameters for DBMS_RLS.add_policy: namespace and attribute

– new procedure DBMS_RLS.add_policy_context

– improved performance

Page 38: Apex and Virtual Private Database

Bypassing VPD

• Not enforced for DIRECT path export

• Grant EXEMPT ACCESS POLICY

• Return NULL for object owner: IF object_schema = USER THEN RETURN ''; END IF;

Page 39: Apex and Virtual Private Database

Errors

• ORA-28112: failed to execute policy function – the policy function raised an exception

• "Invalid SQL statement" – may be a syntax error in the generated SQL

• ORA-28115: policy with check option violation – policy has been applied to Insert, Update or Delete operations

• ORA-28133: full table access is restricted by fine-grained security – policy has been applied to Index operation

Page 40: Apex and Virtual Private Database

Tuning

• Set client_identifier to APP_USER:SESSION then call the policy function

• or, query v$vpd_policy to get the predicate(s) applied to the query

• or, get the final exact SQL statement from the trace file ALTER SESSION SET EVENTS '10730 trace name context forever, level 12';

Page 41: Apex and Virtual Private Database

Recommendations

• Use q'{ syntax for predicates }'

• Understand how Apex Sessions work

• Use context for variables

– avoid injecting literals

– avoid calls to v() etc.

• Keep predicates simple

Page 42: Apex and Virtual Private Database

More Information

Read the Oracle Docs for:

– using policy groups

– automated policy creation in DDL triggers

– integration with Oracle Label Security

– data dictionary views

– Oracle Data Redaction

Page 43: Apex and Virtual Private Database

Oracle Docs

Oracle Database Security Guide:

Using Oracle Virtual Private Database to Control Data Access http://bit.ly/16Iq5EQ

Oracle Database PL/SQL Packages and Types Reference:

DBMS_RLS http://bit.ly/1abI46V

Page 44: Apex and Virtual Private Database

Thank you jeffkemponoracle.com

Image source: http://www.toothpastefordinner.com/index.php?date=082609