SQL injection attacks are typically the application developer's responsibility to prevent — but developers are not always the ones accountable when a breach happens. Database administrators have limited control over how applications query the database, yet they bear responsibility for protecting the data. SQL/Protect addresses this gap.
SQL/Protect is a plug-in for PolarDB for Oracle that analyzes incoming query requests and detects SQL injection patterns. When it identifies a suspicious query, it either alerts you or blocks the query, depending on how you configure it.
SQL injection attack types
SQL/Protect detects four types of SQL injection attacks:
| Attack type | How it works | Why it's dangerous |
|---|---|---|
| Unauthorized relations | Attacker accesses tables the application was never meant to touch | Hard to prevent manually; SQL/Protect learns which tables each user legitimately accesses and flags deviations |
| Utility commands | Attacker runs DDL statements, such as creating a user-defined function to read restricted data | These commands rarely appear in normal application workloads, making them straightforward to detect |
| SQL tautology | Attacker injects a WHERE clause that is always true, such as WHERE password = 'x' OR 'x'='x' | This is how attackers typically probe for security weaknesses — the first step before deeper exploitation |
| Unbounded DML statements | Attacker runs UPDATE or DELETE without a WHERE clause | A single statement can modify or delete every row in a table, enabling denial-of-service (DoS) attacks |
Modes
The polar_sql_protect.level parameter controls how SQL/Protect responds to suspicious queries. Three modes are available:
| Mode | Behavior | When to use |
|---|---|---|
| learn | Tracks and records which tables each user accesses. Does not alert or block. | Initial setup — run this mode first to build a baseline of legitimate behavior |
| passive | Sends an alert for unauthorized SQL statements but still allows them to run | Testing and monitoring — use this when you want visibility without risking blocked queries |
| active | Blocks all unauthorized SQL statements and records them | Production protection — enables SQL firewalls to intercept attacks during penetration tests and real incidents |
The default mode is passive.
Protected roles
A protected role is a database user or group that SQL/Protect monitors. Each protected role can have different protection settings — for example, one role might have relation protection enabled while another allows utility commands.
Constraints:
A role with superuser privileges cannot be added as a protected role.
If a protected non-superuser role is later granted superuser privileges, SQL/Protect generates an alert for every command that role runs. In active mode, all commands are blocked.
When SQL/Protect is running, a protected role that has the superuser privilege is changed to a common role or restored to an unprotected role.
Each database supports up to 64 protected roles by default (configurable with
max_protected_roles) and up to 1,024 protected tables (configurable withmax_protected_relations).
Set up SQL/Protect
This section covers enabling SQL/Protect, adding a protected role, and switching between modes.
Prerequisites
Before you begin, ensure that you have:
A PolarDB for Oracle cluster
Database administrator access
Enable SQL/Protect and create a protected role
Enable SQL/Protect by setting the following parameters:
SET polar_sql_protect.enabled = on; -- Default: off SET polar_sql_protect.level = passive; -- Default: passive. Valid values: learn, passive, activeCreate a test database and user:
CREATE DATABASE targetdb; CREATE ROLE test; GRANT ALL ON DATABASE targetdb TO test; ALTER ROLE test LOGIN;Connect to
targetdb, install the extension, and add the protected role:CREATE EXTENSION sqlprotect; SELECT sqlprotect.protect_role('test');Verify that the role is protected:
SELECT * FROM sqlprotect.list_protected_users; SELECT * FROM sqlprotect.polar_sql_protect;
Use learn mode to build a baseline
Switch to learn mode before your application starts running queries. SQL/Protect records every table the protected role accesses, building a list of authorized relations.
SET polar_sql_protect.level = learn;Connect to targetdb as the test user and run your application's typical queries:
CREATE TABLE company(name VARCHAR(100), employee_num INT);
SELECT * FROM company;
INSERT INTO company VALUES('new', 1);
SELECT * FROM company;After running the queries, check what SQL/Protect learned:
SELECT * FROM sqlprotect.polar_sql_protect_rel;
SELECT * FROM sqlprotect.list_protected_rels;Switch to passive mode
After the baseline is built, switch to passive mode to start detecting suspicious queries without blocking them.
SET polar_sql_protect.level = passive;Connect as the test user and run test SQL statements:
SELECT * FROM company WHERE 1 = 1; -- SQL tautology
DELETE FROM company; -- Unbounded DMLSQL/Protect sends an alert for each unauthorized statement but allows execution.
Use passive mode to tune your baseline before enabling enforcement.
Switch to active mode
When you are confident in the baseline, switch to active mode. SQL/Protect blocks unauthorized SQL statements instead of only alerting.
SET polar_sql_protect.level = active;Connect as the test user and run the same test statements:
SELECT * FROM company WHERE 1 = 1;
DELETE FROM company;SQL/Protect returns a message that indicates unauthorized SQL statements and prevents execution.
Manage protected roles
Protected roles are stored in the sqlprotect.polar_sql_protect table. As a database administrator, you control which users and groups are protected.
Add a protected role:
SELECT sqlprotect.protect_role('userA');View protected roles and their learned tables:
SELECT * FROM sqlprotect.list_protected_users;
SELECT * FROM sqlprotect.polar_sql_protect;Remove a protected role:
SELECT sqlprotect.unprotect_role('userA');Fine-tune protection per role
The sqlprotect.polar_sql_protect table has four boolean columns that control which attack types SQL/Protect enforces for each role:
targetdb=# \d sqlprotect.polar_sql_protect;
Table "sqlprotect.polar_sql_protect"
Column | Type | Collation | Nullable | Default
--------------------+---------+-----------+----------+---------
dbid | oid | | not null |
roleid | oid | | not null |
protect_relations | boolean | | |
allow_utility_cmds | boolean | | |
allow_tautology | boolean | | |
allow_empty_dml | boolean | | |
Indexes:
"polar_sql_protect_pkey" PRIMARY KEY, btree (roleid)For example, if you execute the following statement to set the allow_utility_cmds parameter to TRUE for a protected role named 16480, SQL/Protect blocks the utility commands run by the protected role 16480:
UPDATE sqlprotect.polar_sql_protect
SET allow_utility_cmds = TRUE
WHERE roleid = 16480;Monitor SQL injection statistics
SQL/Protect records statistics for every suspicious query a protected role runs. These statistics help you identify attack patterns early — before an attacker escalates from probing to exploitation.
View statistics for all protected roles:
SELECT * FROM sqlprotect.polar_sql_protect_stats;The polar_sql_protect_stats view breaks down counts by attack type (unauthorized relations, utility commands, tautology, unbounded DML), so you can see which vectors are being attempted and against which roles. Reviewing this data regularly lets you respond proactively — for example, by switching to active mode when you see a spike in tautology attempts.
Clear statistics for a specific user:
SELECT sqlprotect.drop_stats('username');Disable SQL/Protect
To disable SQL/Protect:
polar_sql_protect.enabled = off
polar_sql_protect.level = passive