diff --git a/scenarios/02-shared-app-account/README.md b/scenarios/02-shared-app-account/README.md index 40d75db..ae5d4e3 100755 --- a/scenarios/02-shared-app-account/README.md +++ b/scenarios/02-shared-app-account/README.md @@ -6,7 +6,7 @@ Show the risk of a technical application account used by many users and how the ## What This Lab Shows -Before Oracle Deep Data Security, a technical account or connection pool can query orders from every seller and region. After data grants are applied, the result depends on the persona propagated by the application. +Before Oracle Deep Data Security, a technical account or connection pool can query orders from every seller and region. After data grants are applied, the database authorizes access based on the end-user persona, not only on the shared technical account. ## Personas @@ -16,39 +16,37 @@ Before Oracle Deep Data Security, a technical account or connection pool can que ## Where To Run The Commands -Run commands from the repository root: +Run SQL scripts from the repository root. On Linux/macOS/WSL: + +```bash +cd ~/DEEP-DATA-SECURITY/oracle-deep-data-security-lab +export TNS_ADMIN=~/DEEP-DATA-SECURITY/wallet-ddslab +``` + +Connect as the lab administrator: + +```bash +sql admin@ddslab_tunnel +``` + +SQLcl note: when running a script with `@file.sql`, press Enter once and wait for the output. Do not type `/` afterward, because `/` reruns the last command in the SQLcl buffer. + +On Windows PowerShell: ```powershell cd C:\Users\rodrigo\Documents\Codex\oracle-deep-data-security-lab -``` - -Connect to the database with SQLcl or SQL*Plus: - -```bash -sql "" -``` - -Example: - -```text -ADMIN/@ddslab_high +sql admin@ddslab_tunnel ``` ## Step By Step - Before, Vulnerable Environment -1. Connect to the database: - - ```bash - sql "" - ``` - -2. Reset the scenario: +1. Reset the scenario as `ADMIN`: ```sql @scenarios/02-shared-app-account/sql/99_reset.sql ``` -3. Create the table, data, users, and technical account: +2. Create the orders table, seed data, business personas, and the shared app account: ```sql @scenarios/02-shared-app-account/sql/00_schema.sql @@ -56,34 +54,82 @@ ADMIN/@ddslab_high @scenarios/02-shared-app-account/sql/02_identities.sql ``` -4. Simulate an application querying orders with broad SQL: +3. Show the full raw data as `ADMIN`: + + ```sql + SELECT order_id, customer_name, region, seller, amount, margin + FROM dds_orders + ORDER BY order_id; + ``` + +4. Connect as the shared technical application account: + + ```bash + sql 'dds_app/AppPool#2026Lab!@ddslab_tunnel' + ``` + +5. Run the broad application query: ```sql @scenarios/02-shared-app-account/sql/04_test_queries.sql ``` -Expected result before protection: orders from multiple regions and fields such as `MARGIN` may appear to users who should not see them. +Expected result before protection: `DDS_APP` can see orders from all regions and the sensitive `MARGIN` column. This represents a common connection-pool problem where the database only sees the application account. ## Step By Step - After, With Deep Data Security -1. Apply the data grants: +1. Reconnect as `ADMIN` and apply the data grants: ```sql @scenarios/02-shared-app-account/sql/03_data_grants.sql ``` -2. Run the query again: +2. Connect as `alice`, a sales representative: - ```sql - @scenarios/02-shared-app-account/sql/04_test_queries.sql + ```bash + sql 'alice/Welcome1_DDS!@ddslab_tunnel' ``` -3. Repeat the test by simulating `alice` and `bruno` as end users. +3. Run Alice's normal business query, without the sensitive `MARGIN` column: + + ```sql + ALTER SESSION SET CURRENT_SCHEMA = ADMIN; + + SELECT order_id, customer_name, region, seller, amount + FROM dds_orders + ORDER BY order_id; + ``` + + This query represents the normal sales workflow. Alice needs customer, region, seller, and order amount to follow her pipeline, but she does not need commercial margin. + +4. Try to access the sensitive margin column as Alice: + + ```sql + SELECT order_id, customer_name, region, seller, amount, margin + FROM dds_orders + ORDER BY order_id; + ``` + + This query represents an application bug, abused endpoint, prompt injection, or ad hoc SQL asking for a sensitive field outside Alice's business role. + +5. Connect as `bruno`, the LATAM manager, and run the manager query: + + ```bash + sql 'bruno/Welcome1_DDS!@ddslab_tunnel' + ``` + + ```sql + ALTER SESSION SET CURRENT_SCHEMA = ADMIN; + + SELECT order_id, customer_name, region, seller, amount, margin + FROM dds_orders + ORDER BY order_id; + ``` Expected result after protection: -- `alice` sees only her orders and does not see `MARGIN`. -- `bruno` sees LATAM orders with manager visibility. +- `alice` sees only her orders and does not get access to `MARGIN`. +- `bruno` sees LATAM orders with manager visibility, including `MARGIN`. - The technical account is no longer the only authorization boundary. ## Optional Automated Execution @@ -103,4 +149,3 @@ Linux/macOS: ## Demo Details See the complete walkthrough, evidence, and official references in [RUNBOOK.md](RUNBOOK.md). - diff --git a/scenarios/02-shared-app-account/RUNBOOK.md b/scenarios/02-shared-app-account/RUNBOOK.md index ad70c92..bfbeeb4 100755 --- a/scenarios/02-shared-app-account/RUNBOOK.md +++ b/scenarios/02-shared-app-account/RUNBOOK.md @@ -18,13 +18,27 @@ Show that a shared technical application account should not be the real data aut ## Before - Vulnerable Environment -1. Reset the scenario: +1. From the repository root, connect as `ADMIN`: + + ```bash + cd ~/DEEP-DATA-SECURITY/oracle-deep-data-security-lab + export TNS_ADMIN=~/DEEP-DATA-SECURITY/wallet-ddslab + sql admin@ddslab_tunnel + ``` + + Presenter note: `ADMIN` prepares the lab objects. The risk will be shown later using the shared application account. + + SQLcl note: after running a script with `@file.sql`, do not type `/`. The slash reruns the last command in the SQLcl buffer and can make a successful command look like an error. + +2. Reset the scenario: ```sql @scenarios/02-shared-app-account/sql/99_reset.sql ``` -2. Create the table, data, and technical account: + Presenter note: this makes the demo repeatable and removes previous Data Grants or roles. + +3. Create the table, data, and identities: ```sql @scenarios/02-shared-app-account/sql/00_schema.sql @@ -32,12 +46,38 @@ Show that a shared technical application account should not be the real data aut @scenarios/02-shared-app-account/sql/02_identities.sql ``` -3. Simulate an application or API using the `DDS_APP` account to query all orders: + Presenter note: `DDS_APP` represents the application connection pool; `alice` and `bruno` represent real business users. + +4. Show all rows and columns as `ADMIN`: + + ```sql + SELECT order_id, customer_name, region, seller, amount, margin + FROM dds_orders + ORDER BY order_id; + ``` + + Presenter note: `MARGIN` is commercially sensitive and should not be visible to every seller. + +5. Exit and connect as the shared technical application account: + + ```sql + exit + ``` + + ```bash + sql 'dds_app/AppPool#2026Lab!@ddslab_tunnel' + ``` + + Presenter note: this simulates a web app, API, BI tool, or AI service where many users arrive through the same database account. + +6. Simulate an application or API using `DDS_APP` to query all orders: ```sql @scenarios/02-shared-app-account/sql/04_test_queries.sql ``` + Presenter note: before DDS, the database sees `DDS_APP` and the broad SQL returns too much data. + ## Expected Result Before - The shared account can see orders from every seller and region. @@ -46,18 +86,74 @@ Show that a shared technical application account should not be the real data aut ## After - Applying Deep Data Security -1. Apply data grants by business role: +1. Exit and reconnect as `ADMIN`: + + ```sql + exit + ``` + + ```bash + sql admin@ddslab_tunnel + ``` + +2. Apply data grants by business role: ```sql @scenarios/02-shared-app-account/sql/03_data_grants.sql ``` -2. Run the same query in the context of `alice` and `bruno`: + Presenter note: `seller_role` is limited to the seller's own rows and excludes `MARGIN`; `latam_manager_role` can see LATAM orders with full manager fields. + +3. Test Alice, the sales representative, with a normal business query: ```sql - @scenarios/02-shared-app-account/sql/04_test_queries.sql + exit ``` + ```bash + sql 'alice/Welcome1_DDS!@ddslab_tunnel' + ``` + + ```sql + ALTER SESSION SET CURRENT_SCHEMA = ADMIN; + + SELECT order_id, customer_name, region, seller, amount + FROM dds_orders + ORDER BY order_id; + ``` + + Presenter note: this is Alice's legitimate workflow. She needs customer, region, seller, and amount to manage her pipeline, but she does not need commercial margin. + +4. Try to force Alice to see `MARGIN`: + + ```sql + SELECT order_id, customer_name, region, seller, amount, margin + FROM dds_orders + ORDER BY order_id; + ``` + + Presenter note: this simulates an application bug, abused API endpoint, prompt injection, or AI-generated SQL asking for a sensitive column outside Alice's business role. + +5. Test Bruno, the LATAM manager: + + ```sql + exit + ``` + + ```bash + sql 'bruno/Welcome1_DDS!@ddslab_tunnel' + ``` + + ```sql + ALTER SESSION SET CURRENT_SCHEMA = ADMIN; + + SELECT order_id, customer_name, region, seller, amount, margin + FROM dds_orders + ORDER BY order_id; + ``` + + Presenter note: Bruno has manager visibility, so he can see LATAM orders and the margin needed for his role. + ## Expected Result After - `alice` sees only her orders and does not see `margin`. @@ -76,4 +172,3 @@ Show that a shared technical application account should not be the real data aut - Fine-Grained Data Authorization: https://docs.oracle.com/en/database/oracle/oracle-database/26/ddscg/fine-grained-data-authorization.html - Create Data Grants: https://docs.oracle.com/en/database/oracle/oracle-database/26/ddscg/create-data-grants.html - End-User Security Contexts: https://docs.oracle.com/en/database/oracle/oracle-database/26/refrn/DBA_END_USER_SECURITY_CONTEXTS.html - diff --git a/scenarios/02-shared-app-account/evidence/expected-results.md b/scenarios/02-shared-app-account/evidence/expected-results.md index b9982b5..54bf387 100755 --- a/scenarios/02-shared-app-account/evidence/expected-results.md +++ b/scenarios/02-shared-app-account/evidence/expected-results.md @@ -1,6 +1,16 @@ # Expected Results -- `alice` sees her orders and no `margin`. -- `bruno` sees LATAM orders with all columns. -- The shared technical account alone is not the authorization boundary for data access. +## Before Oracle Deep Data Security +- `DDS_APP` simulates a shared application account or connection pool. +- `DDS_APP` can query all orders from all regions. +- `DDS_APP` can see the sensitive `margin` column. +- The database cannot safely distinguish Alice's access from Bruno's access if the application account is the only security boundary. + +## After Oracle Deep Data Security + +- `alice` sees only her own orders. +- `alice` can query operational columns such as `order_id`, `customer_name`, `region`, `seller`, and `amount`. +- `alice` cannot access `margin`. +- `bruno` sees LATAM orders with manager visibility, including `margin`. +- The database enforces access based on the business persona, not only on the shared technical account. diff --git a/scenarios/02-shared-app-account/sql/00_schema.sql b/scenarios/02-shared-app-account/sql/00_schema.sql index 87ae476..f43aedc 100755 --- a/scenarios/02-shared-app-account/sql/00_schema.sql +++ b/scenarios/02-shared-app-account/sql/00_schema.sql @@ -1,11 +1,20 @@ WHENEVER SQLERROR EXIT SQL.SQLCODE -CREATE TABLE dds_orders ( - order_id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - customer_name VARCHAR2(100) NOT NULL, - region VARCHAR2(30) NOT NULL, - seller VARCHAR2(60) NOT NULL, - amount NUMBER(12,2) NOT NULL, - margin NUMBER(12,2) NOT NULL -); - +BEGIN + EXECUTE IMMEDIATE q'[ + CREATE TABLE dds_orders ( + order_id NUMBER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + customer_name VARCHAR2(100) NOT NULL, + region VARCHAR2(30) NOT NULL, + seller VARCHAR2(60) NOT NULL, + amount NUMBER(12,2) NOT NULL, + margin NUMBER(12,2) NOT NULL + ) + ]'; +EXCEPTION + WHEN OTHERS THEN + IF SQLCODE != -955 THEN + RAISE; + END IF; +END; +/ diff --git a/scenarios/02-shared-app-account/sql/02_identities.sql b/scenarios/02-shared-app-account/sql/02_identities.sql index 2e92151..3f62004 100755 --- a/scenarios/02-shared-app-account/sql/02_identities.sql +++ b/scenarios/02-shared-app-account/sql/02_identities.sql @@ -14,5 +14,11 @@ GRANT shared_app_session_role TO latam_manager_role; GRANT DATA ROLE seller_role TO alice; GRANT DATA ROLE latam_manager_role TO bruno; -CREATE USER dds_app IDENTIFIED BY "Welcome1_DDS_App!" ACCOUNT UNLOCK; +CREATE USER dds_app IDENTIFIED BY "AppPool#2026Lab!" ACCOUNT UNLOCK; GRANT CREATE SESSION TO dds_app; + +-- Vulnerable baseline: this broad legacy role simulates a shared application +-- account or connection pool that can query the full table before DDS is enforced. +CREATE ROLE shared_app_legacy_access_role; +GRANT SELECT ON dds_orders TO shared_app_legacy_access_role; +GRANT shared_app_legacy_access_role TO dds_app; diff --git a/scenarios/02-shared-app-account/sql/03_data_grants.sql b/scenarios/02-shared-app-account/sql/03_data_grants.sql index c02d269..0b17ec3 100755 --- a/scenarios/02-shared-app-account/sql/03_data_grants.sql +++ b/scenarios/02-shared-app-account/sql/03_data_grants.sql @@ -3,7 +3,7 @@ WHENEVER SQLERROR EXIT SQL.SQLCODE CREATE OR REPLACE DATA GRANT seller_own_orders AS SELECT (order_id, customer_name, region, seller, amount) ON dds_orders - WHERE seller = ORA_END_USER_CONTEXT.username + WHERE UPPER(seller) = ORA_END_USER_CONTEXT.username TO seller_role; CREATE OR REPLACE DATA GRANT latam_manager_orders diff --git a/scenarios/02-shared-app-account/sql/99_reset.sql b/scenarios/02-shared-app-account/sql/99_reset.sql index cb2ca6a..ae2c858 100755 --- a/scenarios/02-shared-app-account/sql/99_reset.sql +++ b/scenarios/02-shared-app-account/sql/99_reset.sql @@ -14,6 +14,8 @@ BEGIN EXECUTE IMMEDIATE 'DROP DATA ROLE latam_manager_role'; EXCEPTION WHEN OTHE / BEGIN EXECUTE IMMEDIATE 'DROP ROLE shared_app_session_role'; EXCEPTION WHEN OTHERS THEN NULL; END; / +BEGIN EXECUTE IMMEDIATE 'DROP ROLE shared_app_legacy_access_role'; EXCEPTION WHEN OTHERS THEN NULL; END; +/ BEGIN EXECUTE IMMEDIATE 'DROP END USER alice'; EXCEPTION WHEN OTHERS THEN NULL; END; / BEGIN EXECUTE IMMEDIATE 'DROP END USER bruno'; EXCEPTION WHEN OTHERS THEN NULL; END;