Skip to content

05 — SQL for Security Professionals

SQL is one of the most useful skills for cybersecurity professionals who work with structured data.

Modern security programs rely heavily on databases containing:

USERS
ASSETS
VULNERABILITIES
LOG EVENTS
ALERTS
INCIDENTS
ACCESS RECORDS
APPLICATION DATA
AUDIT DATA
CONFIGURATION DATA

SQL helps you ask precise questions of that data.

For example:

SHOW ME ALL FAILED LOGINS
SHOW ME ALL CRITICAL VULNERABILITIES
SHOW ME USERS WITHOUT MFA
SHOW ME ASSETS WITH MULTIPLE HIGH-RISK FINDINGS
SHOW ME ADMINISTRATIVE ACTIVITY
SHOW ME EVENTS FROM A SPECIFIC IP

That makes SQL extremely valuable for:

SOC
THREAT HUNTING
INCIDENT RESPONSE
GRC
VULNERABILITY MANAGEMENT
APPLICATION SECURITY
AUDIT
SECURITY ENGINEERING
CLOUD SECURITY

Think of SQL as:

SECURITY QUESTION
QUERY
DATABASE
FILTER / JOIN / AGGREGATE
RESULT
SECURITY DECISION

Example:

Which users generated
more than five failed logins?
SQL QUERY
AUTHENTICATION EVENTS
GROUP BY USER
COUNT
SUSPICIOUS USERS

Follow this sequence:

DATABASE FUNDAMENTALS
TABLES
ROWS
COLUMNS
SELECT
WHERE
ORDER BY
LIMIT
DISTINCT
COUNT
GROUP BY
HAVING
JOIN
AGGREGATION
SUBQUERIES
DATE / TIME
SECURITY DATA ANALYSIS
DATABASE SECURITY

A database stores structured information.

Example:

SECURITY DATABASE
|
+-- USERS
|
+-- ASSETS
|
+-- EVENTS
|
+-- VULNERABILITIES
|
+-- INCIDENTS

A table stores related records.

Example:

users

might contain:

user_id username department mfa_enabled
1 analyst01 SOC true
2 admin01 IT true
3 user01 Finance false

A:

ROW

represents one record.

A:

COLUMN

represents one attribute.

Example:

ROW
=
admin01's user record

Columns:

username
department
mfa_enabled

A primary key uniquely identifies a row.

Example:

user_id

Values:

1
2
3

should uniquely identify users in the table.

Foreign keys connect tables.

Example:

users

contains:

user_id

while:

login_events

may contain:

user_id

Conceptually:

USERS
USER_ID
LOGIN EVENTS

This relationship allows data correlation.

Imagine a training database containing:

users
assets
login_events
vulnerabilities
incidents
users
user_id username role department mfa_enabled
1 analyst01 analyst SOC true
2 admin01 admin IT true
3 user01 user Finance false
4 user02 user HR false
assets
asset_id hostname ip_address criticality
1 DC01 10.10.10.10 critical
2 WEB01 10.10.10.20 high
3 WS01 10.10.10.30 medium
login_events
event_id user_id source_ip status event_time
1 2 10.10.10.50 failed 2026-08-29 09:00
2 2 10.10.10.50 failed 2026-08-29 09:01
3 1 10.10.10.40 success 2026-08-29 09:05

The most important SQL statement is:

SELECT

Example:

SELECT *
FROM users;

This returns every column and every row.

Prefer selecting only what you need.

SELECT username, department
FROM users;

This is cleaner than:

SELECT *

for many security workflows.

Because:

LESS DATA
LESS NOISE
LESS EXPOSURE
CLEARER ANALYSIS

Security professionals should follow:

MINIMUM NECESSARY DATA

where practical.

Use:

WHERE

to filter results.

Example:

SELECT username
FROM users
WHERE role = 'admin';

Find users without MFA:

SELECT username, department
FROM users
WHERE mfa_enabled = false;

Common operators:

=
!=
<>
>
<
>=
<=

Example:

SELECT *
FROM vulnerabilities
WHERE severity = 'critical';

Use:

AND

when both conditions must be true.

Example:

SELECT *
FROM users
WHERE role = 'admin'
AND mfa_enabled = false;

Use:

OR

when either condition can be true.

Example:

SELECT *
FROM vulnerabilities
WHERE severity = 'high'
OR severity = 'critical';

A cleaner approach:

SELECT *
FROM vulnerabilities
WHERE severity IN ('high', 'critical');

Example:

SELECT *
FROM users
WHERE NOT role = 'admin';

Use pattern matching.

Example:

SELECT *
FROM assets
WHERE hostname LIKE 'WEB%';

This might return:

WEB01
WEB02

Common:

%
=
Any sequence of characters
_
=
Single character

Example:

WHERE username LIKE 'admin%'

Sort results:

SELECT *
FROM vulnerabilities
ORDER BY severity;

Descending:

SELECT *
FROM vulnerabilities
ORDER BY severity DESC;

In database systems that support it:

SELECT *
FROM login_events
LIMIT 10;

Useful when initially exploring large tables.

Remove duplicates:

SELECT DISTINCT source_ip
FROM login_events;

Security use case:

SHOW ALL UNIQUE
SOURCE IP ADDRESSES

Count records:

SELECT COUNT(*)
FROM login_events;
SELECT COUNT(*)
FROM login_events
WHERE status = 'failed';

Group events:

SELECT source_ip, COUNT(*) AS event_count
FROM login_events
GROUP BY source_ip;

This answers:

HOW MANY EVENTS
CAME FROM EACH IP?
SELECT user_id, COUNT(*) AS failed_count
FROM login_events
WHERE status = 'failed'
GROUP BY user_id;
SELECT user_id, COUNT(*) AS failed_count
FROM login_events
WHERE status = 'failed'
GROUP BY user_id
ORDER BY failed_count DESC;

WHERE filters rows before grouping.

HAVING filters grouped results.

Example:

SELECT user_id, COUNT(*) AS failed_count
FROM login_events
WHERE status = 'failed'
GROUP BY user_id
HAVING COUNT(*) >= 5;

This answers:

WHICH USERS HAVE
AT LEAST FIVE FAILURES?

Common functions:

COUNT
SUM
AVG
MIN
MAX

Example:

SELECT MIN(event_time), MAX(event_time)
FROM login_events;

This can help identify:

FIRST EVENT
LAST EVENT

in a dataset.

If vulnerability data includes scores:

SELECT AVG(cvss_score)
FROM vulnerabilities;

If data includes counts or quantified impact:

SELECT SUM(event_count)
FROM daily_security_metrics;

Use:

AS

Example:

SELECT COUNT(*) AS failed_logins
FROM login_events
WHERE status = 'failed';

Aliases make reports easier to read.

Example:

SELECT u.username
FROM users AS u;

Short form:

SELECT u.username
FROM users u;

Useful when joins become complex.

Joins combine related data from multiple tables.

Conceptually:

LOGIN EVENT
USER_ID
USER RECORD

Example:

SELECT
u.username,
l.source_ip,
l.status,
l.event_time
FROM login_events l
INNER JOIN users u
ON l.user_id = u.user_id;

Now instead of:

user_id = 2

you see:

admin01

Security investigations often require combining:

EVENT
USER
ASSET
VULNERABILITY
ROLE
LOCATION

into one context.

SELECT
u.username,
l.source_ip,
l.event_time
FROM login_events l
JOIN users u
ON l.user_id = u.user_id
WHERE l.status = 'failed';
SELECT
u.username,
COUNT(*) AS failed_count
FROM login_events l
JOIN users u
ON l.user_id = u.user_id
WHERE l.status = 'failed'
GROUP BY u.username
ORDER BY failed_count DESC;

A left join keeps all rows from the left table.

Example:

SELECT
u.username,
l.event_id
FROM users u
LEFT JOIN login_events l
ON u.user_id = l.user_id;

This can help identify:

USERS WITH NO EVENTS
SELECT u.username
FROM users u
LEFT JOIN login_events l
ON u.user_id = l.user_id
WHERE l.event_id IS NULL;

Possible security use:

Dormant Account Review

NULL means:

NO VALUE

Do not compare with:

= NULL

Use:

IS NULL

or:

IS NOT NULL

Example:

SELECT *
FROM assets
WHERE owner IS NULL;

Security use case:

IDENTIFY ASSETS
WITHOUT OWNERS

Incomplete security data creates blind spots.

Examples:

Asset Without Owner
User Without Department
Finding Without Severity
Event Without Source

SQL can identify these governance issues.

SELECT hostname, ip_address
FROM assets
WHERE owner IS NULL;

A subquery places one query inside another.

Example:

SELECT username
FROM users
WHERE user_id IN (
SELECT user_id
FROM login_events
WHERE status = 'failed'
);

Subqueries can be useful for:

FILTERING
COMPARISON
LOOKUPS
DERIVED CONDITIONS

But joins may sometimes be clearer.

Many databases support:

WITH

Example:

WITH failed_users AS (
SELECT
user_id,
COUNT(*) AS failed_count
FROM login_events
WHERE status = 'failed'
GROUP BY user_id
)
SELECT *
FROM failed_users
WHERE failed_count >= 5;

CTEs can make complex analysis easier to read.

Security data is time-sensitive.

Common questions include:

WHAT HAPPENED TODAY?
WHAT HAPPENED IN THE LAST HOUR?
WHEN DID THE EVENT START?
WHEN DID IT STOP?

Date syntax varies between database products.

Conceptually:

SELECT *
FROM login_events
WHERE event_time >= <START_TIME>
AND event_time < <END_TIME>;

Use the date/time functions appropriate to your training database.

SELECT *
FROM login_events
ORDER BY event_time ASC;

This helps build an investigation timeline.

FIRST EVENT
RELATED EVENTS
PRIVILEGE ACTIVITY
RESOURCE ACCESS
LAST EVENT

Start:

SELECT *
FROM login_events
WHERE status = 'failed'
ORDER BY event_time;

Then group:

SELECT
source_ip,
COUNT(*) AS failed_count
FROM login_events
WHERE status = 'failed'
GROUP BY source_ip
ORDER BY failed_count DESC;
SELECT *
FROM login_events
WHERE source_ip = '10.10.10.50'
ORDER BY event_time;
SELECT
u.username,
l.status,
l.event_time
FROM login_events l
JOIN users u
ON l.user_id = u.user_id
WHERE l.source_ip = '10.10.10.50'
ORDER BY l.event_time;

Now ask:

ONE IP?
MANY USERS?
MANY FAILURES?
ANY SUCCESS?

53 — Detect Password-Spray-Like Patterns Conceptually

Section titled “53 — Detect Password-Spray-Like Patterns Conceptually”

A security analyst may look for:

ONE SOURCE
MANY USERS
LOW NUMBER OF ATTEMPTS PER USER

SQL can help aggregate the data.

Example analytical concept:

SELECT
source_ip,
COUNT(DISTINCT user_id) AS unique_users,
COUNT(*) AS attempts
FROM login_events
WHERE status = 'failed'
GROUP BY source_ip
ORDER BY unique_users DESC;

Interpret results carefully rather than automatically labeling them malicious.

SELECT
user_id,
COUNT(*) AS failed_count
FROM login_events
WHERE status = 'failed'
GROUP BY user_id
HAVING COUNT(*) >= 5;

An analyst may investigate sequences where failed authentication is followed by success.

The exact query depends on database features and schema.

The investigation question is:

DID A SUCCESSFUL LOGIN
FOLLOW AN UNUSUAL SERIES
OF FAILURES?

Example table:

vulnerabilities
vuln_id asset_id title severity cvss_score status
1 2 Outdated package high 8.1 open
2 1 Weak configuration critical 9.4 open
3 3 Missing patch medium 6.2 closed
SELECT *
FROM vulnerabilities
WHERE severity = 'critical';
SELECT *
FROM vulnerabilities
WHERE status = 'open'
AND severity IN ('high', 'critical');
SELECT
a.hostname,
a.criticality,
v.title,
v.severity
FROM vulnerabilities v
JOIN assets a
ON v.asset_id = a.asset_id;

60 — Critical Findings on Critical Assets

Section titled “60 — Critical Findings on Critical Assets”
SELECT
a.hostname,
v.title,
v.severity
FROM vulnerabilities v
JOIN assets a
ON v.asset_id = a.asset_id
WHERE a.criticality = 'critical'
AND v.severity IN ('high', 'critical');

This is more meaningful than severity alone.

SELECT
a.hostname,
COUNT(*) AS finding_count
FROM vulnerabilities v
JOIN assets a
ON v.asset_id = a.asset_id
GROUP BY a.hostname
ORDER BY finding_count DESC;
SELECT
a.hostname,
COUNT(*) AS critical_count
FROM vulnerabilities v
JOIN assets a
ON v.asset_id = a.asset_id
WHERE v.severity = 'critical'
GROUP BY a.hostname
ORDER BY critical_count DESC;

A stronger prioritization model might consider:

ASSET CRITICALITY
+
FINDING SEVERITY
+
EXPOSURE
+
BUSINESS CONTEXT

SQL helps prepare the data.

The final risk decision still requires security judgment.

Find administrators:

SELECT username
FROM users
WHERE role = 'admin';
SELECT username
FROM users
WHERE role = 'admin'
AND mfa_enabled = false;

This could become a high-priority identity governance finding.

SELECT
username,
role,
department
FROM users
WHERE mfa_enabled = false;
SELECT
mfa_enabled,
COUNT(*) AS user_count
FROM users
GROUP BY mfa_enabled;

SQL can help create metrics such as:

MFA COVERAGE
OPEN CRITICAL FINDINGS
FAILED LOGIN COUNTS
UNOWNED ASSETS
DORMANT USERS
INCIDENT COUNTS

The exact syntax may vary.

Conceptually:

USERS WITH MFA
÷
TOTAL USERS
×
100

This can support security dashboards.

Example:

incidents
incident_id severity status owner created_at
1 high open SOC1 2026-08-28
2 medium closed SOC2 2026-08-27
SELECT *
FROM incidents
WHERE status = 'open';
SELECT
severity,
COUNT(*) AS incident_count
FROM incidents
GROUP BY severity;
SELECT *
FROM incidents
WHERE owner IS NULL;

This is both:

OPERATIONS ISSUE
GOVERNANCE ISSUE

SQL is extremely useful for:

ACCESS REVIEWS
CONTROL TESTING
COMPLIANCE EVIDENCE
USER REVIEWS
ASSET REVIEWS
VULNERABILITY REPORTING

Suppose:

user_roles

contains:

username
role
system
approved

Query unapproved access:

SELECT *
FROM user_roles
WHERE approved = false;
SELECT *
FROM user_roles
WHERE role IN (
'admin',
'superuser',
'security_admin'
);
SELECT
system,
COUNT(*) AS privileged_users
FROM user_roles
WHERE role = 'admin'
GROUP BY system;

Security inventories may contain duplicates.

Identify duplicates:

SELECT
hostname,
COUNT(*) AS duplicate_count
FROM assets
GROUP BY hostname
HAVING COUNT(*) > 1;
SELECT
ip_address,
COUNT(*) AS duplicate_count
FROM assets
GROUP BY ip_address
HAVING COUNT(*) > 1;

Data may contain:

HIGH
High
high

Use database functions appropriate to your environment to normalize.

Example:

SELECT LOWER(severity)
FROM vulnerabilities;

Clean whitespace:

SELECT TRIM(username)
FROM users;

Data quality matters for accurate correlation.

CASE provides conditional logic.

Example:

SELECT
username,
CASE
WHEN role = 'admin'
THEN 'Privileged'
ELSE 'Standard'
END AS access_type
FROM users;

Example:

SELECT
title,
cvss_score,
CASE
WHEN cvss_score >= 9.0
THEN 'Critical'
WHEN cvss_score >= 7.0
THEN 'High'
WHEN cvss_score >= 4.0
THEN 'Medium'
ELSE 'Low'
END AS risk_band
FROM vulnerabilities;

This is a simplified technical classification and should not replace full risk analysis.

A view is a stored query representation.

Conceptually:

RAW TABLES
VIEW
AUTHORIZED SECURITY DATA

Views can help restrict what analysts see.

A security team might expose:

security_events_view

containing only:

Timestamp
Username
Source IP
Event Type

instead of the full underlying application data.

Security analysts should have:

ONLY THE DATABASE ACCESS
REQUIRED FOR THEIR ROLE

For many analytical workflows:

READ ONLY

may be sufficient.

87 — Avoid Using Administrative Accounts

Section titled “87 — Avoid Using Administrative Accounts”

Do not perform routine queries with:

DBA / ROOT / SUPERUSER

unless the task specifically requires that privilege.

A secure database environment may use roles such as:

READ_ONLY_ANALYST
APP_READ_WRITE
DB_ADMIN
AUDITOR

Rather than granting everyone broad privileges.

Consider:

AUTHENTICATION
AUTHORIZATION
ENCRYPTION
AUDITING
BACKUPS
PATCHING
NETWORK RESTRICTION
LEAST PRIVILEGE

Sensitive database traffic should be appropriately protected.

Consider:

TLS
CERTIFICATE VALIDATION
NETWORK SEGMENTATION
PRIVATE NETWORKS
STRONG AUTHENTICATION

A database should generally not be exposed more broadly than necessary.

Architecture:

USER
X
DATABASE
APPLICATION
DATABASE

with administration limited to approved management paths.

SQL injection occurs when untrusted application input is incorrectly incorporated into SQL structure.

Unsafe conceptual model:

USER INPUT
+
SQL QUERY STRING
DATABASE INTERPRETS BOTH
AS QUERY LOGIC

Prefer:

APPLICATION
PARAMETERIZED QUERY
SQL STRUCTURE
+
DATA PARAMETERS
DATABASE

The application should keep:

DATA

separate from:

SQL CODE

Avoid application patterns conceptually like:

"SELECT ... WHERE username = '" + userInput + "'"

when handling untrusted input.

Use the database library’s parameterization features instead.

Python example:

cursor.execute(
"SELECT user_id FROM users WHERE username = ?",
(username,)
)

Exact placeholders vary by database driver.

The key principle is:

DON'T BUILD SQL
BY CONCATENATING
UNTRUSTED INPUT

Stored procedures can centralize database operations.

They can support security when:

Permissions Are Restricted
Inputs Are Safely Handled
Dynamic Query Construction Is Controlled

They are not automatically secure merely because they are stored procedures.

Applications should not expose database credentials in:

Frontend JavaScript
Public Repositories
Logs
Error Messages
World-Readable Configuration

Use:

SECRET MANAGEMENT
MANAGED IDENTITIES
RESTRICTED CONFIGURATION

where appropriate.

Database monitoring may include:

Authentication
Failed Authentication
Administrative Changes
Schema Changes
Privilege Changes
Sensitive Queries
Data Modification

A structured investigation might follow:

DEFINE QUESTION
IDENTIFY TABLES
IDENTIFY KEYS
FILTER TIME RANGE
FILTER EVENT TYPE
JOIN CONTEXT
AGGREGATE
INTERPRET

Question:

Which users had the most
failed logins?

Query:

SELECT
u.username,
COUNT(*) AS failed_count
FROM login_events l
JOIN users u
ON l.user_id = u.user_id
WHERE l.status = 'failed'
GROUP BY u.username
ORDER BY failed_count DESC;

Question:

Which source IPs targeted
the most users?

Query:

SELECT
source_ip,
COUNT(DISTINCT user_id) AS unique_users
FROM login_events
WHERE status = 'failed'
GROUP BY source_ip
ORDER BY unique_users DESC;

Question:

Which high-value systems have
open critical vulnerabilities?
SELECT
a.hostname,
a.criticality,
v.title
FROM assets a
JOIN vulnerabilities v
ON a.asset_id = v.asset_id
WHERE a.criticality IN ('high', 'critical')
AND v.severity = 'critical'
AND v.status = 'open';

Question:

Which privileged users do not
have MFA enabled?
SELECT username, role
FROM users
WHERE role = 'admin'
AND mfa_enabled = false;

Question:

Which assets do not have
documented owners?
SELECT hostname, ip_address
FROM assets
WHERE owner IS NULL;

Focus on:

SELECT
WHERE
GROUP BY
COUNT
JOIN
TIME FILTERING
EVENT CORRELATION

Focus on:

Large Event Data
Aggregation
Baselines
Outliers
Time Windows
User / IP Correlation

Focus on:

TIMELINES
USER ACTIVITY
ASSET ACTIVITY
AUTHENTICATION
PROCESS / EVENT DATA
CORRELATION

depending on available telemetry.

Focus on:

ASSETS
FINDINGS
SEVERITY
STATUS
OWNERS
DUE DATES
RISK PRIORITIZATION

Focus on:

ACCESS REVIEWS
CONTROL EVIDENCE
ASSET OWNERSHIP
POLICY EXCEPTIONS
AUDIT RESULTS
COMPLIANCE STATUS

Focus on understanding:

DATA MODELS
APPLICATION QUERIES
DATABASE PERMISSIONS
PARAMETERIZATION
ACCESS CONTROL
DATA MINIMIZATION

Cloud security data may be exported or centralized into structured stores containing:

IDENTITIES
RESOURCES
AUDIT EVENTS
POLICY DATA
FINDINGS

SQL can help correlate these datasets.

112 — Project 01: Failed Login Dashboard Dataset

Section titled “112 — Project 01: Failed Login Dashboard Dataset”

Build queries for:

Total Failed Logins
Failures by User
Failures by Source IP
Unique Users per Source
Top 10 Sources

113 — Project 02: Vulnerability Prioritization

Section titled “113 — Project 02: Vulnerability Prioritization”

Create:

OPEN FINDINGS
HIGH / CRITICAL
JOIN ASSET
ADD CRITICALITY
PRIORITIZE

Generate:

Total Users
Users with MFA
Users without MFA
Admins without MFA
MFA Adoption by Department

Identify:

Missing Owner
Missing Criticality
Duplicate Hostname
Duplicate IP
Unknown Environment

Generate:

Open Incidents
Incidents by Severity
Incidents by Owner
Unassigned Incidents
Incidents by Status

117 — Project 06: Privileged Access Review

Section titled “117 — Project 06: Privileged Access Review”

Analyze:

ADMIN USERS
SYSTEM ACCESS
APPROVAL STATUS
DORMANT PRIVILEGED ACCESS
EXCESSIVE ADMIN COUNTS

using synthetic training data.

118 — Project 07: Security Event Timeline

Section titled “118 — Project 07: Security Event Timeline”

Given an incident identifier or user:

FILTER RELEVANT EVENTS
ORDER BY TIME
JOIN USER / ASSET CONTEXT
BUILD TIMELINE

119 — Project 08: Security Metrics Dataset

Section titled “119 — Project 08: Security Metrics Dataset”

Build queries for:

MFA Coverage
Critical Vulnerability Count
Unowned Assets
Failed Authentication
Open Incidents
Privileged Account Count

Large security datasets may contain:

MILLIONS
BILLIONS

of events.

Poorly designed queries can become slow.

Understand concepts such as:

INDEXES
FILTER EARLY
SELECT REQUIRED COLUMNS
LIMIT DEVELOPMENT QUERIES

An index helps databases find records efficiently.

Conceptually:

WITHOUT INDEX
SEARCH MANY ROWS

versus:

WITH APPROPRIATE INDEX
LOOK UP MATCHING RECORDS
MORE EFFICIENTLY

At enterprise scale, raw security data may be queried through systems that use SQL or SQL-like languages.

The mental model remains:

DATASET
FILTER
AGGREGATE
CORRELATE
INVESTIGATE

Different platforms use different SQL dialects.

Examples include:

PostgreSQL
MySQL
SQL Server
SQLite
Oracle

Syntax is mostly similar for fundamentals but differs in areas such as:

DATE FUNCTIONS
LIMITING RESULTS
JSON FUNCTIONS
IDENTIFIERS
ADMINISTRATION

Learn the underlying concepts:

SELECT
FILTER
GROUP
JOIN
AGGREGATE
CORRELATE

Then adapt syntax to the platform.

For cybersecurity analytics, begin with:

READ-ONLY DATASETS

before working with:

INSERT
UPDATE
DELETE

This reduces accidental data modification.

Conceptually:

INSERT INTO incidents (
severity,
status,
owner
)
VALUES (
'medium',
'open',
'SOC1'
);

Use only on your own training database when learning.

Conceptually:

UPDATE incidents
SET status = 'closed'
WHERE incident_id = 1;

Always understand the WHERE condition before modifying data.

This:

UPDATE incidents
SET status = 'closed';

updates every row.

Therefore:

CHECK WHERE
BEFORE UPDATE

Example:

DELETE FROM incidents
WHERE incident_id = 99;

Again, practice only with disposable training data.

This:

DELETE FROM incidents;

may remove all records.

Cybersecurity professionals should understand these commands, but routine analysis should usually remain read-only.

Transactions help group changes safely.

Conceptually:

BEGIN
MAKE CHANGES
VERIFY
├── CORRECT → COMMIT
└── WRONG → ROLLBACK

Exact syntax varies by database.

Database security requires reliable:

BACKUPS
RESTORE TESTING
ACCESS CONTROL
ENCRYPTION
RETENTION

Backups themselves are sensitive assets.

Protect backups because they may contain:

FULL USER DATA
PASSWORD HASHES
BUSINESS RECORDS
APPLICATION SECRETS
HISTORICAL DATA

Applications should not expose raw errors revealing:

QUERY STRUCTURE
TABLE NAMES
DATABASE VERSION
FILESYSTEM PATHS
INTERNAL DETAILS

A secure model:

USER
APPLICATION
AUTHENTICATE
AUTHORIZE
VALIDATE INPUT
PARAMETERIZED QUERY
DATABASE ACCOUNT
WITH LEAST PRIVILEGE
DATABASE

136 — Database Layer Is Not the Only Security Layer

Section titled “136 — Database Layer Is Not the Only Security Layer”

Do not rely solely on:

DATABASE PERMISSIONS

The application must also enforce:

USER AUTHORIZATION
OBJECT OWNERSHIP
TENANT BOUNDARIES
BUSINESS RULES

Use:

QUESTION
SCHEMA
TABLE
KEY
FILTER
JOIN
GROUP
SORT
INTERPRET

Bad approach:

SELECT EVERYTHING
AND LOOK AROUND

Better:

QUESTION:
Which admin accounts
lack MFA?

Then write the smallest query needed.

SQL gives you:

RESULTS

not automatically:

CONCLUSIONS

For example:

100 FAILED LOGINS

does not automatically prove:

ATTACK

You still need context:

Source
Time
Affected Users
Success Events
Known Maintenance
Existing Alerts
Week Focus
1 SELECT, WHERE, ORDER BY, DISTINCT
2 COUNT, GROUP BY, HAVING, Aggregation
3 JOIN, Subqueries, Time-Based Analysis
4 Security Investigation and Reporting Projects

You understand:

Database
Table
Row
Column
Primary Key
Foreign Key

You can use:

SELECT
WHERE
ORDER BY
DISTINCT

You can use:

COUNT
GROUP BY
HAVING
MIN
MAX
AVG

You can use:

JOIN
LEFT JOIN
SUBQUERY
CTE

You can analyze:

Authentication
Assets
Vulnerabilities
Incidents
Access

You can build repeatable queries for:

SOC
GRC
Vulnerability Management
Identity Reviews
Security Metrics
  • Database concept understood
  • Table understood
  • Row understood
  • Column understood
  • Primary key understood
  • Foreign key understood
  • SELECT
  • Specific columns
  • WHERE
  • AND
  • OR
  • IN
  • LIKE
  • ORDER BY
  • DISTINCT
  • LIMIT concept
  • COUNT
  • SUM
  • AVG
  • MIN
  • MAX
  • GROUP BY
  • HAVING
  • Aliases
  • INNER JOIN
  • LEFT JOIN
  • Join keys understood
  • Users correlated with events
  • Assets correlated with vulnerabilities
  • NULL
  • IS NULL
  • CASE
  • LOWER
  • TRIM
  • Data-quality checks
  • Failed logins
  • Events by source
  • Events by user
  • MFA coverage
  • Vulnerability prioritization
  • Asset hygiene
  • Incident metrics
  • Privileged access review
  • Least privilege
  • Read-only access
  • Secure connections
  • Network restrictions
  • Audit logging
  • Backup protection
  • Secret protection
  • Parameterized queries
  • SQL injection concept understood
  • String concatenation risk understood
  • Parameterization understood
  • Database account least privilege understood
  • Error disclosure understood
  • Failed login dataset
  • Vulnerability prioritization
  • MFA coverage
  • Asset hygiene
  • Incident metrics
  • Privileged access review
  • Event timeline
  • Security metrics

40 SQL for Security Professionals Review Questions

Section titled “40 SQL for Security Professionals Review Questions”
  1. What is SQL?
  2. Why is SQL useful for cybersecurity professionals?
  3. What is a database?
  4. What is a table?
  5. What is a row?
  6. What is a column?
  7. What is a primary key?
  8. What is a foreign key?
  9. What does SELECT do?
  10. Why might you avoid SELECT *?
  11. What does WHERE do?
  12. What does IN do?
  13. What does LIKE do?
  14. What does ORDER BY do?
  15. What does DISTINCT do?
  16. What does COUNT do?
  17. What does GROUP BY do?
  18. What is the difference between WHERE and HAVING?
  19. What does an aggregate function do?
  20. What is an SQL alias?
  21. What is a JOIN?
  22. What is an INNER JOIN?
  23. What is a LEFT JOIN?
  24. Why are joins important in security investigations?
  25. What does NULL mean?
  26. How do you test for NULL?
  27. What is a subquery?
  28. What is a CTE?
  29. Why is time filtering important for security data?
  30. How can SQL help identify unusual login patterns?
  31. How can SQL help prioritize vulnerabilities?
  32. How can SQL help with MFA reviews?
  33. What is database least privilege?
  34. Why should analysts often have read-only access?
  35. What is SQL injection conceptually?
  36. Why is string concatenation with untrusted input dangerous?
  37. What is a parameterized query?
  38. Why should database errors not be exposed to users?
  39. Why should database backups be protected?
  40. Why does SQL output still require human security interpretation?

Remember:

SECURITY QUESTION
IDENTIFY DATA
SELECT
FILTER
JOIN
GROUP
AGGREGATE
SORT
INTERPRET
SECURITY DECISION

Do not think:

I NEED TO MEMORIZE
EVERY SQL COMMAND

Think:

WHAT SECURITY QUESTION
AM I TRYING TO ANSWER?

For example:

Who had the most
failed logins?
LOGIN EVENTS
WHERE FAILED
GROUP BY USER
COUNT
ORDER BY

or:

Which critical servers have
critical open vulnerabilities?
ASSETS
+
VULNERABILITIES
JOIN
FILTER
PRIORITIZED RESULT

or:

Which administrators
do not have MFA?
USERS
ROLE = ADMIN
MFA = FALSE
IDENTITY SECURITY FINDING

That is SQL for security professionals:

STRUCTURED DATA
+
SECURITY QUESTIONS
+
CORRELATION
=
SECURITY INSIGHT

➡️ 06 — Security Automation

The final programming module brings everything together.

You will combine:

PYTHON
+
BASH
+
POWERSHELL
+
JAVASCRIPT
+
SQL
+
APIs
+
JSON
SECURITY AUTOMATION

You will learn how to build workflows around:

DATA COLLECTION
NORMALIZATION
ENRICHMENT
ANALYSIS
RISK SCORING
DECISION
APPROVED RESPONSE
REPORTING

The goal will be to move from individual scripting skills toward repeatable cybersecurity automation for SOC operations, cloud security, vulnerability management, incident response, compliance, and security engineering.