@memberjunction/global 6.2.0-edge.4 → 6.2.0-edge.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ClassFactory.d.ts +16 -3
- package/dist/ClassFactory.d.ts.map +1 -1
- package/dist/ClassFactory.js +112 -48
- package/dist/ClassFactory.js.map +1 -1
- package/dist/DeepDiff.d.ts +2 -0
- package/dist/DeepDiff.d.ts.map +1 -1
- package/dist/DeepDiff.js +40 -38
- package/dist/DeepDiff.js.map +1 -1
- package/dist/KeyedSerialTaskQueue.d.ts +18 -1
- package/dist/KeyedSerialTaskQueue.d.ts.map +1 -1
- package/dist/KeyedSerialTaskQueue.js +24 -3
- package/dist/KeyedSerialTaskQueue.js.map +1 -1
- package/dist/ObjectCache.d.ts +1 -0
- package/dist/ObjectCache.d.ts.map +1 -1
- package/dist/ObjectCache.js +14 -22
- package/dist/ObjectCache.js.map +1 -1
- package/dist/SQLExpressionValidator.d.ts +70 -41
- package/dist/SQLExpressionValidator.d.ts.map +1 -1
- package/dist/SQLExpressionValidator.js +183 -134
- package/dist/SQLExpressionValidator.js.map +1 -1
- package/dist/SQLScreeningScanner.d.ts +117 -0
- package/dist/SQLScreeningScanner.d.ts.map +1 -0
- package/dist/SQLScreeningScanner.js +475 -0
- package/dist/SQLScreeningScanner.js.map +1 -0
- package/dist/__tests__/FieldSecurityEgressCompliance.test.d.ts +2 -0
- package/dist/__tests__/FieldSecurityEgressCompliance.test.d.ts.map +1 -0
- package/dist/__tests__/FieldSecurityEgressCompliance.test.js +228 -0
- package/dist/__tests__/FieldSecurityEgressCompliance.test.js.map +1 -0
- package/dist/__tests__/KeyedSerialTaskQueue.test.js +92 -0
- package/dist/__tests__/KeyedSerialTaskQueue.test.js.map +1 -1
- package/dist/__tests__/ProofOfPossession.test.d.ts +2 -0
- package/dist/__tests__/ProofOfPossession.test.d.ts.map +1 -0
- package/dist/__tests__/ProofOfPossession.test.js +123 -0
- package/dist/__tests__/ProofOfPossession.test.js.map +1 -0
- package/dist/__tests__/SQLExpressionValidator.dialect.test.d.ts +2 -0
- package/dist/__tests__/SQLExpressionValidator.dialect.test.d.ts.map +1 -0
- package/dist/__tests__/SQLExpressionValidator.dialect.test.js +183 -0
- package/dist/__tests__/SQLExpressionValidator.dialect.test.js.map +1 -0
- package/dist/__tests__/SQLExpressionValidator.security.test.js +176 -2
- package/dist/__tests__/SQLExpressionValidator.security.test.js.map +1 -1
- package/dist/__tests__/SQLScreeningScanner.test.d.ts +2 -0
- package/dist/__tests__/SQLScreeningScanner.test.d.ts.map +1 -0
- package/dist/__tests__/SQLScreeningScanner.test.js +172 -0
- package/dist/__tests__/SQLScreeningScanner.test.js.map +1 -0
- package/dist/__tests__/SQLScreeningScanner.tokens.test.d.ts +2 -0
- package/dist/__tests__/SQLScreeningScanner.tokens.test.d.ts.map +1 -0
- package/dist/__tests__/SQLScreeningScanner.tokens.test.js +82 -0
- package/dist/__tests__/SQLScreeningScanner.tokens.test.js.map +1 -0
- package/dist/__tests__/UUIDCompliance.test.js +4 -4
- package/dist/__tests__/UUIDCompliance.test.js.map +1 -1
- package/dist/__tests__/UserScopedCacheKey.test.d.ts +2 -0
- package/dist/__tests__/UserScopedCacheKey.test.d.ts.map +1 -0
- package/dist/__tests__/UserScopedCacheKey.test.js +25 -0
- package/dist/__tests__/UserScopedCacheKey.test.js.map +1 -0
- package/dist/__tests__/util.valuesEqual.test.d.ts +2 -0
- package/dist/__tests__/util.valuesEqual.test.d.ts.map +1 -0
- package/dist/__tests__/util.valuesEqual.test.js +37 -0
- package/dist/__tests__/util.valuesEqual.test.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/util/ProofOfPossession.d.ts +68 -0
- package/dist/util/ProofOfPossession.d.ts.map +1 -0
- package/dist/util/ProofOfPossession.js +163 -0
- package/dist/util/ProofOfPossession.js.map +1 -0
- package/dist/util/UserScopedCacheKey.d.ts +42 -0
- package/dist/util/UserScopedCacheKey.d.ts.map +1 -0
- package/dist/util/UserScopedCacheKey.js +49 -0
- package/dist/util/UserScopedCacheKey.js.map +1 -0
- package/dist/util.d.ts +25 -0
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +38 -0
- package/dist/util.js.map +1 -1
- package/package.json +1 -1
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* @module @memberjunction/global/SQLExpressionValidator
|
|
11
11
|
*/
|
|
12
12
|
import { BaseSingleton } from './BaseSingleton.js';
|
|
13
|
+
import { ScanSQLForScreening, SQL_SCREENING_DIALECTS, } from './SQLScreeningScanner.js';
|
|
13
14
|
/**
|
|
14
15
|
* Dangerous SQL keywords that are never allowed in user-provided expressions
|
|
15
16
|
*/
|
|
@@ -67,7 +68,8 @@ export const FULL_QUERY_ALLOWED_KEYWORDS = [
|
|
|
67
68
|
* a schema-enumeration and credential-exfiltration primitive
|
|
68
69
|
* (e.g. `SELECT name, password_hash FROM sys.sql_logins`,
|
|
69
70
|
* `SELECT * FROM INFORMATION_SCHEMA.COLUMNS`, `SELECT * FROM pg_catalog.pg_authid`).
|
|
70
|
-
*
|
|
71
|
+
* The check reads {@link SQLScreeningScan.CodeWithIdentifiers}: string literals are removed, so a
|
|
72
|
+
* literal value like `'sys.x'` is safe, and quoted names are unwrapped, so `[sys].[x]` is caught.
|
|
71
73
|
*/
|
|
72
74
|
export const BLOCKED_SYSTEM_OBJECT_PATTERNS = [
|
|
73
75
|
/\bSYS\s*\.\s*\w/i, // SQL Server system catalog schema: sys.sql_logins, sys.objects, sys.fn_*, ...
|
|
@@ -77,65 +79,111 @@ export const BLOCKED_SYSTEM_OBJECT_PATTERNS = [
|
|
|
77
79
|
/\bPG_(AUTHID|SHADOW|USER|ROLES)\b/i, // PostgreSQL credential / role catalogs
|
|
78
80
|
];
|
|
79
81
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* single quote, `''` is an embedded quote, and a backslash is an ORDINARY character that
|
|
83
|
-
* does NOT escape the closing quote. Double-quoted runs are matched with the same doubling
|
|
84
|
-
* rule so a delimited identifier can't hide a payload either.
|
|
85
|
-
*
|
|
86
|
-
* @see StripSQLStringLiterals — use that, not this constant, so every caller gets the
|
|
87
|
-
* documented semantics and the two validators in MJ can never drift apart again.
|
|
82
|
+
* The keywords a full query may open with. Without the `u` flag, the `i` flag matches ASCII letters
|
|
83
|
+
* only, so no other letter is case-mapped to S, E, L, C, T, W, I or H.
|
|
88
84
|
*/
|
|
89
|
-
const
|
|
85
|
+
const FULL_QUERY_OPENING_KEYWORD = /^(?:SELECT|WITH)$/i;
|
|
90
86
|
/**
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
* 🚨 SECURITY — this is the single implementation of literal-stripping for MJ's SQL screens, and
|
|
96
|
-
* it MUST stay byte-for-byte consistent with how the database parses literals. If the stripper
|
|
97
|
-
* removes a span the database does NOT treat as a literal, everything hidden inside that span
|
|
98
|
-
* bypasses the denylist while the database still executes it.
|
|
99
|
-
*
|
|
100
|
-
* An earlier version of this logic (duplicated in two places, which is how it survived) honored
|
|
101
|
-
* **backslash escaping** — `/(['"])(?:(?=(\\?))\2[\s\S])*?\1/g`. SQL Server and PostgreSQL do not
|
|
102
|
-
* treat `\` as an escape character, so `x = 'a\') ; DROP TABLE Users; --'` was swallowed whole as
|
|
103
|
-
* one "literal" and stripped to `x = `, which passed every denylist — while the database closed
|
|
104
|
-
* the literal at the real quote and executed the stacked statement.
|
|
87
|
+
* Replaces each SQL string literal with one space so that a keyword denylist can be applied to the
|
|
88
|
+
* rest without tripping over keywords inside quoted data (e.g. `Comments LIKE '%--%'`). Quoted
|
|
89
|
+
* identifiers and comments are left as written.
|
|
105
90
|
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
91
|
+
* 🚨 SECURITY — literals are found by {@link ScanSQLForScreening}, which reads the text the way the
|
|
92
|
+
* database does: a quote inside a T-SQL `[…]` identifier, a comment or a PostgreSQL `$$…$$` string
|
|
93
|
+
* opens no literal, and a backslash escapes a quote only inside a PostgreSQL `E'…'` string. A
|
|
94
|
+
* stripper that removes a span the database does NOT treat as a literal hides everything inside it
|
|
95
|
+
* from the denylist while the database still runs it. Screens should call
|
|
96
|
+
* {@link ScanSQLForScreening} directly, which also reports comments and text it cannot classify.
|
|
108
97
|
*
|
|
109
98
|
* @param sql The clause, expression, or query to strip literals from
|
|
110
|
-
* @
|
|
111
|
-
*
|
|
112
|
-
*
|
|
99
|
+
* @param dialect The dialect that will run the SQL. Without one, the text must read the same way
|
|
100
|
+
* under every dialect the scanner knows.
|
|
101
|
+
* @returns The input with each string literal replaced by a space. The input is returned unchanged
|
|
102
|
+
* when it cannot be classified (for example an unterminated literal) or when the dialects
|
|
103
|
+
* disagree on where its literals are, so a denylist still sees all of it.
|
|
113
104
|
*/
|
|
114
|
-
export function StripSQLStringLiterals(sql) {
|
|
115
|
-
|
|
105
|
+
export function StripSQLStringLiterals(sql, dialect) {
|
|
106
|
+
const scans = (dialect ? [dialect] : SQL_SCREENING_DIALECTS).map(d => ScanSQLForScreening(sql, d));
|
|
107
|
+
if (scans.some(scan => !scan.Classified))
|
|
108
|
+
return sql;
|
|
109
|
+
const readings = scans.map(scan => replaceStringSpans(sql, scan.Spans));
|
|
110
|
+
return readings.every(reading => reading === readings[0]) ? readings[0] : sql;
|
|
111
|
+
}
|
|
112
|
+
/** Writes `sql` with each string span replaced by one space. */
|
|
113
|
+
function replaceStringSpans(sql, spans) {
|
|
114
|
+
let result = '';
|
|
115
|
+
let from = 0;
|
|
116
|
+
for (const span of spans) {
|
|
117
|
+
if (span.Kind !== 'string')
|
|
118
|
+
continue;
|
|
119
|
+
result += sql.slice(from, span.Start) + ' ';
|
|
120
|
+
from = span.End;
|
|
121
|
+
}
|
|
122
|
+
return result + sql.slice(from);
|
|
116
123
|
}
|
|
117
124
|
/**
|
|
118
|
-
* Safe SQL functions allowed in expressions, organized by category
|
|
125
|
+
* Safe SQL functions allowed in expressions, organized by category.
|
|
126
|
+
*
|
|
127
|
+
* WHY THIS IS A UNION RATHER THAN A PER-DIALECT TABLE
|
|
128
|
+
* ---------------------------------------------------
|
|
129
|
+
* This is a deny-by-default SAFETY list, not a dialect grammar. Its job is to
|
|
130
|
+
* stop a user-supplied expression from smuggling in something that is not a
|
|
131
|
+
* read-only scalar/aggregate call — it is not, and must not become, a
|
|
132
|
+
* per-platform parser. So it carries the union of every supported dialect's
|
|
133
|
+
* read-only vocabulary, and `checkFunctionNames` consults the flattened union.
|
|
134
|
+
*
|
|
135
|
+
* Keying the buckets off `ResolvePlatformKey` is the alternative, and it costs
|
|
136
|
+
* more than it buys: a PostgreSQL name that reaches a SQL Server tenant is
|
|
137
|
+
* rejected by the SQL Server parser on its own — `DATE_TRUNC(...)` simply never
|
|
138
|
+
* parses there. The union therefore cannot widen the blast radius past what the
|
|
139
|
+
* target server will already accept, whereas a dialect switch here would add a
|
|
140
|
+
* second independent place for the dialect to be resolved, and so a second place
|
|
141
|
+
* for it to be wrong.
|
|
142
|
+
*
|
|
143
|
+
* Before this list held the PostgreSQL names, a perfectly ordinary PG filter
|
|
144
|
+
* such as `DATE_TRUNC('month', CreatedAt)` was rejected outright with
|
|
145
|
+
* "Function 'DATE_TRUNC' is not allowed" on every PostgreSQL tenant.
|
|
146
|
+
*
|
|
147
|
+
* Every name here is read-only by construction. Anything that writes, escalates,
|
|
148
|
+
* or reaches outside the statement stays on {@link DANGEROUS_SQL_KEYWORDS}, which
|
|
149
|
+
* is checked FIRST (step 2 of `validate`) — a name added here can never unblock
|
|
150
|
+
* one that is denied there.
|
|
119
151
|
*/
|
|
120
152
|
export const ALLOWED_SQL_FUNCTIONS = {
|
|
121
|
-
// Aggregate functions
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
153
|
+
// Aggregate functions. PG: ARRAY_AGG / JSONB_AGG / JSON_AGG / BOOL_AND / BOOL_OR /
|
|
154
|
+
// EVERY / PERCENTILE_* / MODE.
|
|
155
|
+
aggregates: ['COUNT', 'COUNT_BIG', 'SUM', 'AVG', 'MIN', 'MAX', 'STDEV', 'STDEVP', 'VAR', 'VARP', 'STRING_AGG', 'CHECKSUM_AGG',
|
|
156
|
+
'ARRAY_AGG', 'JSONB_AGG', 'JSON_AGG', 'BOOL_AND', 'BOOL_OR', 'EVERY', 'PERCENTILE_CONT', 'PERCENTILE_DISC', 'MODE'],
|
|
157
|
+
// Math functions. PG: CEIL (vs CEILING), RANDOM (vs RAND), TRUNC, MOD, DIV,
|
|
158
|
+
// GREATEST, LEAST, WIDTH_BUCKET.
|
|
159
|
+
math: ['ABS', 'CEILING', 'FLOOR', 'ROUND', 'POWER', 'SQRT', 'LOG', 'LOG10', 'EXP', 'SIGN', 'RAND',
|
|
160
|
+
'CEIL', 'RANDOM', 'TRUNC', 'MOD', 'DIV', 'GREATEST', 'LEAST', 'WIDTH_BUCKET'],
|
|
161
|
+
// String functions (read-only). PG: POSITION / STRPOS (vs CHARINDEX), SPLIT_PART,
|
|
162
|
+
// INITCAP, LPAD, RPAD, REPEAT, REVERSE, TRANSLATE, REGEXP_*, TO_CHAR, MD5, ASCII, CHR.
|
|
163
|
+
string: ['LEN', 'LENGTH', 'UPPER', 'LOWER', 'LTRIM', 'RTRIM', 'TRIM', 'LEFT', 'RIGHT', 'SUBSTRING', 'CHARINDEX', 'REPLACE', 'CONCAT', 'STUFF',
|
|
164
|
+
'POSITION', 'STRPOS', 'SPLIT_PART', 'INITCAP', 'LPAD', 'RPAD', 'REPEAT', 'REVERSE', 'TRANSLATE',
|
|
165
|
+
'REGEXP_REPLACE', 'REGEXP_MATCHES', 'REGEXP_SUBSTR', 'TO_CHAR', 'MD5', 'ASCII', 'CHR'],
|
|
166
|
+
// Date functions. PG: NOW / CURRENT_* / LOCALTIMESTAMP (vs GETDATE), DATE_TRUNC,
|
|
167
|
+
// DATE_PART / EXTRACT (vs DATEPART), AGE, TO_DATE, TO_TIMESTAMP, MAKE_*, JUSTIFY_DAYS.
|
|
168
|
+
date: ['DATEPART', 'DATEDIFF', 'DATEADD', 'YEAR', 'MONTH', 'DAY', 'HOUR', 'MINUTE', 'SECOND', 'GETDATE', 'GETUTCDATE', 'SYSDATETIME', 'EOMONTH',
|
|
169
|
+
'NOW', 'CURRENT_DATE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP', 'LOCALTIMESTAMP', 'DATE_TRUNC', 'DATE_PART', 'EXTRACT', 'AGE',
|
|
170
|
+
'TO_DATE', 'TO_TIMESTAMP', 'MAKE_DATE', 'MAKE_TIMESTAMP', 'JUSTIFY_DAYS'],
|
|
171
|
+
// Type conversion (safe subset). PG: TO_CHAR / TO_DATE / TO_NUMBER / TO_TIMESTAMP
|
|
172
|
+
// (vs CAST/CONVERT/FORMAT).
|
|
173
|
+
conversion: ['CAST', 'CONVERT', 'TRY_CAST', 'TRY_CONVERT', 'FORMAT', 'TO_CHAR', 'TO_DATE', 'TO_NUMBER', 'TO_TIMESTAMP'],
|
|
174
|
+
// Null handling. PG has no ISNULL/IIF; GREATEST/LEAST are its null-tolerant pickers.
|
|
175
|
+
nullHandling: ['ISNULL', 'COALESCE', 'NULLIF', 'IIF', 'GREATEST', 'LEAST'],
|
|
133
176
|
// Case expressions
|
|
134
177
|
conditional: ['CASE', 'WHEN', 'THEN', 'ELSE', 'END'],
|
|
135
|
-
// Logical operators (as keywords)
|
|
136
|
-
|
|
137
|
-
//
|
|
138
|
-
|
|
178
|
+
// Logical operators (as keywords). PG: ILIKE, SIMILAR TO. ANY/ALL/SOME/EXISTS are
|
|
179
|
+
// listed so that the full-query context, which unblocks them from
|
|
180
|
+
// DANGEROUS_SQL_KEYWORDS via FULL_QUERY_ALLOWED_KEYWORDS, does not then trip over
|
|
181
|
+
// them here as unknown function-shaped tokens.
|
|
182
|
+
logical: ['AND', 'OR', 'NOT', 'IS', 'NULL', 'LIKE', 'BETWEEN', 'IN', 'ILIKE', 'SIMILAR', 'ANY', 'ALL', 'SOME', 'EXISTS'],
|
|
183
|
+
// Sort/order and windowing. PG: NULLS FIRST/LAST, aggregate FILTER (WHERE …),
|
|
184
|
+
// WITHIN GROUP, GROUPING.
|
|
185
|
+
ordering: ['ASC', 'ASCENDING', 'DESC', 'DESCENDING', 'OVER', 'PARTITION', 'BY', 'ORDER', 'ROWS', 'RANGE', 'UNBOUNDED', 'PRECEDING', 'FOLLOWING', 'CURRENT', 'ROW',
|
|
186
|
+
'NULLS', 'FIRST', 'LAST', 'FILTER', 'WITHIN', 'GROUPING']
|
|
139
187
|
};
|
|
140
188
|
/**
|
|
141
189
|
* Central SQL expression validator for preventing SQL injection.
|
|
@@ -186,75 +234,65 @@ export class SQLExpressionValidator extends BaseSingleton {
|
|
|
186
234
|
if (!trimmed) {
|
|
187
235
|
return { valid: false, error: 'Expression cannot be empty' };
|
|
188
236
|
}
|
|
189
|
-
//
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
237
|
+
// Read the text the way the database will. When the dialect is unknown, every reading must pass.
|
|
238
|
+
const dialects = options.Dialect ? [options.Dialect] : SQL_SCREENING_DIALECTS;
|
|
239
|
+
for (const dialect of dialects) {
|
|
240
|
+
const result = this.validateReading(ScanSQLForScreening(trimmed, dialect), options);
|
|
241
|
+
if (!result.valid)
|
|
242
|
+
return result;
|
|
243
|
+
}
|
|
244
|
+
return { valid: true };
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Runs every check against one dialect's reading of the expression.
|
|
248
|
+
*
|
|
249
|
+
* 🚨 SECURITY: the checks read the scanner's projections, never the raw text. Do not add a regex
|
|
250
|
+
* that finds literals, identifiers or comments here; see {@link ScanSQLForScreening}.
|
|
251
|
+
*/
|
|
252
|
+
validateReading(scan, options) {
|
|
253
|
+
if (!scan.Classified) {
|
|
254
|
+
return {
|
|
255
|
+
valid: false,
|
|
256
|
+
error: `SQL could not be read safely as ${scan.Dialect}: ${scan.Error}`,
|
|
257
|
+
trigger: 'unclassified'
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
const dangerCheck = this.checkDangerousPatterns(scan, options);
|
|
193
261
|
if (!dangerCheck.valid)
|
|
194
262
|
return dangerCheck;
|
|
195
|
-
//
|
|
196
|
-
//
|
|
263
|
+
// The function allowlist is designed for expression fragments, not full SQL statements.
|
|
264
|
+
// Quoted names are unwrapped, so a quoted function call is checked too.
|
|
197
265
|
if (options.context !== 'full_query') {
|
|
198
|
-
const functionCheck = this.checkFunctionNames(
|
|
266
|
+
const functionCheck = this.checkFunctionNames(scan.CodeWithIdentifiers, options);
|
|
199
267
|
if (!functionCheck.valid)
|
|
200
268
|
return functionCheck;
|
|
201
269
|
}
|
|
202
|
-
|
|
203
|
-
const contextCheck = this.checkContextRules(withoutStrings, options);
|
|
270
|
+
const contextCheck = this.checkContextRules(scan, options);
|
|
204
271
|
if (!contextCheck.valid)
|
|
205
272
|
return contextCheck;
|
|
206
|
-
//
|
|
273
|
+
// Optional field reference validation (lenient - just logs warnings)
|
|
207
274
|
if (options.entityFields?.length) {
|
|
208
|
-
this.checkFieldReferences(
|
|
275
|
+
this.checkFieldReferences(scan.Code, options.entityFields);
|
|
209
276
|
}
|
|
210
277
|
return { valid: true };
|
|
211
278
|
}
|
|
212
|
-
/**
|
|
213
|
-
* Remove string literals to avoid false positives in keyword detection.
|
|
214
|
-
*
|
|
215
|
-
* 🚨 SECURITY: delegates to {@link StripSQLStringLiterals} — read the warning there before
|
|
216
|
-
* changing anything about how literals are matched. This must never grow its own regex again.
|
|
217
|
-
*/
|
|
218
|
-
removeStringLiterals(expression) {
|
|
219
|
-
return StripSQLStringLiterals(expression);
|
|
220
|
-
}
|
|
221
279
|
/**
|
|
222
280
|
* Check for dangerous SQL patterns that indicate injection attempts
|
|
223
281
|
*/
|
|
224
|
-
checkDangerousPatterns(
|
|
282
|
+
checkDangerousPatterns(scan, options) {
|
|
225
283
|
const isFullQuery = options.context === 'full_query';
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
// Add SELECT to blocked unless context allows it (prevents subqueries in expressions)
|
|
237
|
-
if (!isFullQuery && !options.allowSubqueries && !blocked.includes('SELECT')) {
|
|
238
|
-
blocked.push('SELECT');
|
|
239
|
-
}
|
|
240
|
-
// For full_query, strip comments before keyword checking (agent SQL has header comment blocks).
|
|
241
|
-
// For expressions, comments are still rejected outright as injection vectors.
|
|
242
|
-
let textToCheck;
|
|
243
|
-
if (isFullQuery) {
|
|
244
|
-
textToCheck = this.stripSQLComments(expression).toUpperCase();
|
|
245
|
-
}
|
|
246
|
-
else {
|
|
247
|
-
const upper = expression.toUpperCase();
|
|
248
|
-
if (upper.includes('--') || upper.includes('/*') || upper.includes('*/')) {
|
|
249
|
-
return {
|
|
250
|
-
valid: false,
|
|
251
|
-
error: 'Comments are not allowed in SQL expressions',
|
|
252
|
-
trigger: 'comment'
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
textToCheck = upper;
|
|
284
|
+
const textToCheck = scan.Code.toUpperCase();
|
|
285
|
+
// Full queries may carry comments (agent SQL has header comment blocks); the scan has already
|
|
286
|
+
// blanked them. In expressions, comments are rejected outright as injection vectors, and so is
|
|
287
|
+
// a stray `*/`, which is code.
|
|
288
|
+
if (!isFullQuery && (scan.CommentCount > 0 || textToCheck.includes('*/'))) {
|
|
289
|
+
return {
|
|
290
|
+
valid: false,
|
|
291
|
+
error: 'Comments are not allowed in SQL expressions',
|
|
292
|
+
trigger: 'comment'
|
|
293
|
+
};
|
|
256
294
|
}
|
|
257
|
-
for (const keyword of
|
|
295
|
+
for (const keyword of this.blockedKeywords(options)) {
|
|
258
296
|
// Use word boundaries to avoid false positives (e.g., "DESCRIPTION" containing "EXEC")
|
|
259
297
|
const pattern = new RegExp(`\\b${this.escapeRegex(keyword)}\\b`, 'i');
|
|
260
298
|
if (pattern.test(textToCheck)) {
|
|
@@ -269,9 +307,10 @@ export class SQLExpressionValidator extends BaseSingleton {
|
|
|
269
307
|
// Block references to database system catalogs / metadata objects in ALL contexts
|
|
270
308
|
// (including full_query). These live outside MemberJunction's entity-permission model, so
|
|
271
309
|
// permitting them turns a validated SELECT into a schema-enumeration / credential-exfiltration
|
|
272
|
-
// primitive.
|
|
310
|
+
// primitive. Literals are blanked and quoted names unwrapped, so `[sys].[x]` is caught too.
|
|
311
|
+
const namesToCheck = scan.CodeWithIdentifiers.toUpperCase();
|
|
273
312
|
for (const sysPattern of BLOCKED_SYSTEM_OBJECT_PATTERNS) {
|
|
274
|
-
if (sysPattern.test(
|
|
313
|
+
if (sysPattern.test(namesToCheck)) {
|
|
275
314
|
return {
|
|
276
315
|
valid: false,
|
|
277
316
|
error: 'Access to database system catalogs / metadata objects is not allowed',
|
|
@@ -279,13 +318,10 @@ export class SQLExpressionValidator extends BaseSingleton {
|
|
|
279
318
|
};
|
|
280
319
|
}
|
|
281
320
|
}
|
|
282
|
-
// Check statement terminator (prevents multi-statement injection).
|
|
283
|
-
//
|
|
284
|
-
//
|
|
285
|
-
|
|
286
|
-
const textForSemicolonCheck = isFullQuery
|
|
287
|
-
? this.stripSQLComments(expression).replace(/;\s*$/, '') // strip comments then trailing semicolon
|
|
288
|
-
: expression;
|
|
321
|
+
// Check statement terminator (prevents multi-statement injection). Comments are already
|
|
322
|
+
// blanked, so a full query may end with one semicolon even when a comment follows it
|
|
323
|
+
// (`ORDER BY x DESC; -- highest first`). A semicolon anywhere else indicates injection.
|
|
324
|
+
const textForSemicolonCheck = isFullQuery ? textToCheck.replace(/;\s*$/, '') : textToCheck;
|
|
289
325
|
if (textForSemicolonCheck.includes(';')) {
|
|
290
326
|
return {
|
|
291
327
|
valid: false,
|
|
@@ -295,6 +331,27 @@ export class SQLExpressionValidator extends BaseSingleton {
|
|
|
295
331
|
}
|
|
296
332
|
return { valid: true };
|
|
297
333
|
}
|
|
334
|
+
/**
|
|
335
|
+
* The keywords {@link checkDangerousPatterns} rejects in this context.
|
|
336
|
+
*/
|
|
337
|
+
blockedKeywords(options) {
|
|
338
|
+
const isFullQuery = options.context === 'full_query';
|
|
339
|
+
// Build blocked list - explicitly typed as string[] for mutability
|
|
340
|
+
let blocked = [...DANGEROUS_SQL_KEYWORDS];
|
|
341
|
+
if (options.additionalBlocked) {
|
|
342
|
+
blocked.push(...options.additionalBlocked);
|
|
343
|
+
}
|
|
344
|
+
// For full_query context, remove keywords that are legitimate in SELECT statements
|
|
345
|
+
if (isFullQuery) {
|
|
346
|
+
const allowedSet = new Set(FULL_QUERY_ALLOWED_KEYWORDS.map(k => k.toUpperCase()));
|
|
347
|
+
blocked = blocked.filter(kw => !allowedSet.has(kw.toUpperCase()));
|
|
348
|
+
}
|
|
349
|
+
// Add SELECT to blocked unless context allows it (prevents subqueries in expressions)
|
|
350
|
+
if (!isFullQuery && !options.allowSubqueries && !blocked.includes('SELECT')) {
|
|
351
|
+
blocked.push('SELECT');
|
|
352
|
+
}
|
|
353
|
+
return blocked;
|
|
354
|
+
}
|
|
298
355
|
/**
|
|
299
356
|
* Check that function names are in the allowlist
|
|
300
357
|
*/
|
|
@@ -324,12 +381,12 @@ export class SQLExpressionValidator extends BaseSingleton {
|
|
|
324
381
|
/**
|
|
325
382
|
* Context-specific validation rules
|
|
326
383
|
*/
|
|
327
|
-
checkContextRules(
|
|
384
|
+
checkContextRules(scan, options) {
|
|
328
385
|
// For aggregate context, require at least one aggregate function (unless explicitly disabled)
|
|
329
386
|
if (options.context === 'aggregate' && options.requireAggregate !== false) {
|
|
330
387
|
const hasAggregate = ALLOWED_SQL_FUNCTIONS.aggregates.some(fn => {
|
|
331
388
|
const pattern = new RegExp(`\\b${fn}\\s*\\(`, 'i');
|
|
332
|
-
return pattern.test(
|
|
389
|
+
return pattern.test(scan.Code);
|
|
333
390
|
});
|
|
334
391
|
if (!hasAggregate) {
|
|
335
392
|
return {
|
|
@@ -339,17 +396,15 @@ export class SQLExpressionValidator extends BaseSingleton {
|
|
|
339
396
|
};
|
|
340
397
|
}
|
|
341
398
|
}
|
|
342
|
-
// For full_query context, the
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
};
|
|
352
|
-
}
|
|
399
|
+
// For full_query context, the first token (after comments) must be the unquoted keyword SELECT or
|
|
400
|
+
// WITH, compared in ASCII. SQL Server runs a batch that opens with any other name, quoted or not,
|
|
401
|
+
// as a procedure call.
|
|
402
|
+
if (options.context === 'full_query' && !FULL_QUERY_OPENING_KEYWORD.test(scan.LeadingWord ?? '')) {
|
|
403
|
+
return {
|
|
404
|
+
valid: false,
|
|
405
|
+
error: 'Ad-hoc query must start with SELECT or WITH',
|
|
406
|
+
suggestion: 'Only SELECT statements and CTEs (WITH ... AS) are allowed'
|
|
407
|
+
};
|
|
353
408
|
}
|
|
354
409
|
return { valid: true };
|
|
355
410
|
}
|
|
@@ -379,16 +434,6 @@ export class SQLExpressionValidator extends BaseSingleton {
|
|
|
379
434
|
// For now, we allow it to pass
|
|
380
435
|
}
|
|
381
436
|
}
|
|
382
|
-
/**
|
|
383
|
-
* Strip SQL comments (single-line -- and multi-line block comments) from a query.
|
|
384
|
-
* Used by full_query context to allow agent-generated header comments
|
|
385
|
-
* without triggering the comment injection check.
|
|
386
|
-
*/
|
|
387
|
-
stripSQLComments(sql) {
|
|
388
|
-
return sql
|
|
389
|
-
.replace(/--[^\n]*/g, '') // Single-line comments
|
|
390
|
-
.replace(/\/\*[\s\S]*?\*\//g, ''); // Block comments
|
|
391
|
-
}
|
|
392
437
|
/**
|
|
393
438
|
* Escape special regex characters in a string
|
|
394
439
|
*/
|
|
@@ -414,13 +459,17 @@ export class SQLExpressionValidator extends BaseSingleton {
|
|
|
414
459
|
* Validate a full SQL query (SELECT or WITH/CTE statement).
|
|
415
460
|
* Blocks mutations, dangerous operations, and multi-statement injection.
|
|
416
461
|
* Allows SELECT, subqueries, set operations, and SQL comments.
|
|
462
|
+
*
|
|
463
|
+
* @param sql The query to validate
|
|
464
|
+
* @param dialect The dialect that will run the query. Without one, the query must pass under
|
|
465
|
+
* every dialect {@link ScanSQLForScreening} knows.
|
|
417
466
|
*/
|
|
418
|
-
ValidateFullQuery(sql) {
|
|
467
|
+
ValidateFullQuery(sql, dialect) {
|
|
419
468
|
// Normalize literal escape sequences before validation — agent-generated
|
|
420
469
|
// SQL may arrive with literal \n instead of real newlines, which breaks
|
|
421
470
|
// comment stripping and the "must start with SELECT" check.
|
|
422
471
|
const normalized = this.normalizeSQLWhitespace(sql);
|
|
423
|
-
return this.validate(normalized, { context: 'full_query' });
|
|
472
|
+
return this.validate(normalized, { context: 'full_query', Dialect: dialect });
|
|
424
473
|
}
|
|
425
474
|
/** @deprecated Use {@link ValidateFullQuery}. */
|
|
426
475
|
validateFullQuery(sql) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SQLExpressionValidator.js","sourceRoot":"","sources":["../src/SQLExpressionValidator.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SQLExpressionValidator.js","sourceRoot":"","sources":["../src/SQLExpressionValidator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Dialect-aware SQL scanner for MemberJunction's SQL denylist screens.
|
|
3
|
+
*
|
|
4
|
+
* A denylist screen is only as good as its idea of which text is code. This scanner reads SQL the
|
|
5
|
+
* way SQL Server or PostgreSQL splits it into tokens and marks every string literal, quoted
|
|
6
|
+
* identifier and comment, so a screen checks exactly the text the database runs as code. When it
|
|
7
|
+
* cannot read the text the way the database would, it reports that, so the screen rejects the text
|
|
8
|
+
* instead of guessing.
|
|
9
|
+
*
|
|
10
|
+
* Used by `SQLExpressionValidator` and `DatabaseProviderBase.ValidateUserProvidedSQLClause`.
|
|
11
|
+
*
|
|
12
|
+
* @module @memberjunction/global/SQLScreeningScanner
|
|
13
|
+
*/
|
|
14
|
+
/** SQL dialects whose lexical rules {@link ScanSQLForScreening} knows. */
|
|
15
|
+
export type SQLScreeningDialect = 'sqlserver' | 'postgresql';
|
|
16
|
+
/**
|
|
17
|
+
* Every dialect {@link ScanSQLForScreening} knows. A screen that does not know which database will
|
|
18
|
+
* run the SQL must accept it under each one.
|
|
19
|
+
*/
|
|
20
|
+
export declare const SQL_SCREENING_DIALECTS: readonly SQLScreeningDialect[];
|
|
21
|
+
/** Kinds of text that the database never runs as code. */
|
|
22
|
+
export type SQLScreeningSpanKind = 'string' | 'identifier' | 'comment';
|
|
23
|
+
/** One string literal, quoted identifier or comment found by {@link ScanSQLForScreening}. */
|
|
24
|
+
export interface SQLScreeningSpan {
|
|
25
|
+
Kind: SQLScreeningSpanKind;
|
|
26
|
+
/** Offset of the first character, including a prefix such as `N` or `E`. */
|
|
27
|
+
Start: number;
|
|
28
|
+
/** Offset just past the last character. */
|
|
29
|
+
End: number;
|
|
30
|
+
}
|
|
31
|
+
/** Kinds of token {@link ScanSQLForScreening} reports. Comments are not tokens. */
|
|
32
|
+
export type SQLScreeningTokenKind = 'word' | 'identifier' | 'number' | 'string' | 'symbol';
|
|
33
|
+
/**
|
|
34
|
+
* One token the database reads as code, or one literal. Whitespace and comments are not tokens.
|
|
35
|
+
*/
|
|
36
|
+
export interface SQLScreeningToken {
|
|
37
|
+
Kind: SQLScreeningTokenKind;
|
|
38
|
+
/**
|
|
39
|
+
* The text as the database reads it: a quoted identifier's bare name with its doubled quote
|
|
40
|
+
* characters undone (`[a]]b]` reads `a]b`); every other kind exactly as written.
|
|
41
|
+
*/
|
|
42
|
+
Text: string;
|
|
43
|
+
/** Offset of the first character, including a quote or prefix. */
|
|
44
|
+
Start: number;
|
|
45
|
+
/** Offset just past the last character. */
|
|
46
|
+
End: number;
|
|
47
|
+
}
|
|
48
|
+
/** Result of {@link ScanSQLForScreening}. */
|
|
49
|
+
export interface SQLScreeningScan {
|
|
50
|
+
/** The dialect whose rules were applied. */
|
|
51
|
+
Dialect: SQLScreeningDialect;
|
|
52
|
+
/** True when every character was read the way the database reads it. When false, reject the text. */
|
|
53
|
+
Classified: boolean;
|
|
54
|
+
/** Why the text could not be classified; null when {@link Classified} is true. */
|
|
55
|
+
Error: string | null;
|
|
56
|
+
/** The string literals, quoted identifiers and comments found, in order. */
|
|
57
|
+
Spans: SQLScreeningSpan[];
|
|
58
|
+
/** Number of comments found. */
|
|
59
|
+
CommentCount: number;
|
|
60
|
+
/**
|
|
61
|
+
* The input with each string literal, quoted identifier and comment replaced by one space, and a
|
|
62
|
+
* space between a number and a word written against it. Only code remains, split where the
|
|
63
|
+
* database splits it, so `N'x'UNION` reads as ` UNION` and `1UNION` as `1 UNION`. Keyword,
|
|
64
|
+
* statement-separator and comment-marker checks read this. When {@link Classified} is false,
|
|
65
|
+
* the text from the point where the scan stopped is left as written.
|
|
66
|
+
*/
|
|
67
|
+
Code: string;
|
|
68
|
+
/**
|
|
69
|
+
* {@link Code}, except each quoted identifier is written as its bare name between spaces, so
|
|
70
|
+
* `[sys].[objects]` reads as ` sys . objects `. Checks for object and function names read this,
|
|
71
|
+
* so quoting a name does not hide it.
|
|
72
|
+
*/
|
|
73
|
+
CodeWithIdentifiers: string;
|
|
74
|
+
/**
|
|
75
|
+
* The first token that is not whitespace or a comment, when that token is an unquoted word and
|
|
76
|
+
* the character after it is ASCII, so every server ends the word in the same place. Null when a
|
|
77
|
+
* literal, quoted identifier, number or symbol comes first, or there is no token. Checks for the
|
|
78
|
+
* statement's opening keyword read this.
|
|
79
|
+
*/
|
|
80
|
+
LeadingWord: string | null;
|
|
81
|
+
/**
|
|
82
|
+
* Every token in order: unquoted words, quoted identifiers, numbers, string literals and
|
|
83
|
+
* single-character symbols. When {@link Classified} is false, the list stops where the scan
|
|
84
|
+
* stopped.
|
|
85
|
+
*/
|
|
86
|
+
Tokens: SQLScreeningToken[];
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Reads `sql` the way `dialect` splits it into tokens. Returns the string literals, quoted
|
|
90
|
+
* identifiers and comments it contains, and the code that remains.
|
|
91
|
+
*
|
|
92
|
+
* Both dialects: `'…'` and `N'…'` strings, in which `''` is an escaped quote and a backslash is an
|
|
93
|
+
* ordinary character; `"…"` identifiers with `""` escapes; `--` comments to the end of the line; and
|
|
94
|
+
* nested block comments. SQL Server adds `[…]` identifiers with `]]` escapes. PostgreSQL adds `E'…'`
|
|
95
|
+
* strings, in which a backslash escapes the next character, dollar-quoted strings (`$$…$$`,
|
|
96
|
+
* `$tag$…$tag$`), and `U&"…"` identifiers, read as one identifier whose `\XXXX` and `\+XXXXXX`
|
|
97
|
+
* escapes (or those of the character a following `UESCAPE '<c>'` names) are decoded, so the name is
|
|
98
|
+
* the one PostgreSQL resolves; a `[` is code there.
|
|
99
|
+
*
|
|
100
|
+
* 🚨 Do not add backslash escapes to plain `'…'` strings. Neither server honors them (PostgreSQL is
|
|
101
|
+
* assumed to run with `standard_conforming_strings = on`, its default since 9.1), and a scanner that
|
|
102
|
+
* does reads `x = 'a\') ; DROP TABLE t; --'` as one literal while the database runs the DROP.
|
|
103
|
+
*
|
|
104
|
+
* The scan stops and reports an error, instead of guessing, when:
|
|
105
|
+
* - a string, quoted identifier, dollar-quoted string or block comment is not closed;
|
|
106
|
+
* - the text contains a NUL character;
|
|
107
|
+
* - a `--` comment contains a line break other than `\n` or `\r\n`;
|
|
108
|
+
* - a PostgreSQL `E'…'` string is followed by another quoted segment, which PostgreSQL can join to
|
|
109
|
+
* it and read with backslash escapes;
|
|
110
|
+
* - a PostgreSQL `U&"…"` identifier has an escape or a `UESCAPE` clause PostgreSQL would reject;
|
|
111
|
+
* - on SQL Server, a number is followed by `e` and a word character (`1EXEC` splits two ways).
|
|
112
|
+
*
|
|
113
|
+
* @param sql The clause, expression or query to read
|
|
114
|
+
* @param dialect The dialect whose lexical rules apply
|
|
115
|
+
*/
|
|
116
|
+
export declare function ScanSQLForScreening(sql: string, dialect: SQLScreeningDialect): SQLScreeningScan;
|
|
117
|
+
//# sourceMappingURL=SQLScreeningScanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SQLScreeningScanner.d.ts","sourceRoot":"","sources":["../src/SQLScreeningScanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,0EAA0E;AAC1E,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG,YAAY,CAAC;AAE7D;;;GAGG;AACH,eAAO,MAAM,sBAAsB,EAAE,SAAS,mBAAmB,EAAgC,CAAC;AAElG,0DAA0D;AAC1D,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,YAAY,GAAG,SAAS,CAAC;AAEvE,6FAA6F;AAC7F,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,oBAAoB,CAAC;IAC3B,4EAA4E;IAC5E,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;CACf;AAED,mFAAmF;AACnF,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE3F;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAC9B,IAAI,EAAE,qBAAqB,CAAC;IAC5B;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;CACf;AAED,6CAA6C;AAC7C,MAAM,WAAW,gBAAgB;IAC7B,4CAA4C;IAC5C,OAAO,EAAE,mBAAmB,CAAC;IAC7B,qGAAqG;IACrG,UAAU,EAAE,OAAO,CAAC;IACpB,kFAAkF;IAClF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,4EAA4E;IAC5E,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,gCAAgC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;;;;OAKG;IACH,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;;OAIG;IACH,MAAM,EAAE,iBAAiB,EAAE,CAAC;CAC/B;AAqED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,gBAAgB,CAE/F"}
|