Merge pull request #14724 from Budibase/fix-enterprise-vulns
Fix enterprise vulns
This commit is contained in:
commit
2e499c2dff
|
@ -184,6 +184,10 @@ spec:
|
||||||
- name: NODE_DEBUG
|
- name: NODE_DEBUG
|
||||||
value: {{ .Values.services.apps.nodeDebug | quote }}
|
value: {{ .Values.services.apps.nodeDebug | quote }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
{{ if .Values.services.apps.xssSafeMode }}
|
||||||
|
- name: XSS_SAFE_MODE
|
||||||
|
value: {{ .Values.services.apps.xssSafeMode | quote }}
|
||||||
|
{{ end }}
|
||||||
{{ if .Values.globals.datadogApmEnabled }}
|
{{ if .Values.globals.datadogApmEnabled }}
|
||||||
- name: DD_LOGS_INJECTION
|
- name: DD_LOGS_INJECTION
|
||||||
value: {{ .Values.globals.datadogApmEnabled | quote }}
|
value: {{ .Values.globals.datadogApmEnabled | quote }}
|
||||||
|
|
|
@ -83,6 +83,7 @@ const environment = {
|
||||||
PLUGINS_DIR: process.env.PLUGINS_DIR || DEFAULTS.PLUGINS_DIR,
|
PLUGINS_DIR: process.env.PLUGINS_DIR || DEFAULTS.PLUGINS_DIR,
|
||||||
MAX_IMPORT_SIZE_MB: process.env.MAX_IMPORT_SIZE_MB,
|
MAX_IMPORT_SIZE_MB: process.env.MAX_IMPORT_SIZE_MB,
|
||||||
SESSION_EXPIRY_SECONDS: process.env.SESSION_EXPIRY_SECONDS,
|
SESSION_EXPIRY_SECONDS: process.env.SESSION_EXPIRY_SECONDS,
|
||||||
|
XSS_SAFE_MODE: process.env.XSS_SAFE_MODE,
|
||||||
// SQL
|
// SQL
|
||||||
SQL_MAX_ROWS: process.env.SQL_MAX_ROWS,
|
SQL_MAX_ROWS: process.env.SQL_MAX_ROWS,
|
||||||
SQL_LOGGING_ENABLE: process.env.SQL_LOGGING_ENABLE,
|
SQL_LOGGING_ENABLE: process.env.SQL_LOGGING_ENABLE,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
import { generateTableID } from "../../../../db/utils"
|
import { generateTableID } from "../../../../db/utils"
|
||||||
import { validate } from "../utils"
|
import { validate } from "../utils"
|
||||||
import { generator } from "@budibase/backend-core/tests"
|
import { generator } from "@budibase/backend-core/tests"
|
||||||
|
import { withEnv } from "../../../../environment"
|
||||||
|
|
||||||
describe("validate", () => {
|
describe("validate", () => {
|
||||||
const hour = () => generator.hour().toString().padStart(2, "0")
|
const hour = () => generator.hour().toString().padStart(2, "0")
|
||||||
|
@ -332,4 +333,46 @@ describe("validate", () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("XSS Safe mode", () => {
|
||||||
|
const getTable = (): Table => ({
|
||||||
|
type: "table",
|
||||||
|
_id: generateTableID(),
|
||||||
|
name: "table",
|
||||||
|
sourceId: INTERNAL_TABLE_SOURCE_ID,
|
||||||
|
sourceType: TableSourceType.INTERNAL,
|
||||||
|
schema: {
|
||||||
|
text: {
|
||||||
|
name: "sometext",
|
||||||
|
type: FieldType.STRING,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
it.each([
|
||||||
|
"SELECT * FROM users WHERE username = 'admin' --",
|
||||||
|
"SELECT * FROM users WHERE id = 1; DROP TABLE users;",
|
||||||
|
"1' OR '1' = '1",
|
||||||
|
"' OR 'a' = 'a",
|
||||||
|
"<script>alert('XSS');</script>",
|
||||||
|
'"><img src=x onerror=alert(1)>',
|
||||||
|
"</script><script>alert('test')</script>",
|
||||||
|
"<div onmouseover=\"alert('XSS')\">Hover over me!</div>",
|
||||||
|
"'; EXEC sp_msforeachtable 'DROP TABLE ?'; --",
|
||||||
|
"{alert('Injected')}",
|
||||||
|
"UNION SELECT * FROM users",
|
||||||
|
"INSERT INTO users (username, password) VALUES ('admin', 'password')",
|
||||||
|
"/* This is a comment */ SELECT * FROM users",
|
||||||
|
'<iframe src="http://malicious-site.com"></iframe>',
|
||||||
|
])("test potentially unsafe input: %s", async input => {
|
||||||
|
withEnv({ XSS_SAFE_MODE: "1" }, async () => {
|
||||||
|
const table = getTable()
|
||||||
|
const row = { text: input }
|
||||||
|
const output = await validate({ source: table, row })
|
||||||
|
expect(output.valid).toBe(false)
|
||||||
|
expect(output.errors).toStrictEqual({
|
||||||
|
text: ["Input not sanitised - potentially vulnerable to XSS"],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -22,6 +22,7 @@ import { extractViewInfoFromID, isRelationshipColumn } from "../../../db/utils"
|
||||||
import { isSQL } from "../../../integrations/utils"
|
import { isSQL } from "../../../integrations/utils"
|
||||||
import { docIds, sql } from "@budibase/backend-core"
|
import { docIds, sql } from "@budibase/backend-core"
|
||||||
import { getTableFromSource } from "../../../api/controllers/row/utils"
|
import { getTableFromSource } from "../../../api/controllers/row/utils"
|
||||||
|
import env from "../../../environment"
|
||||||
|
|
||||||
const SQL_CLIENT_SOURCE_MAP: Record<SourceName, SqlClient | undefined> = {
|
const SQL_CLIENT_SOURCE_MAP: Record<SourceName, SqlClient | undefined> = {
|
||||||
[SourceName.POSTGRES]: SqlClient.POSTGRES,
|
[SourceName.POSTGRES]: SqlClient.POSTGRES,
|
||||||
|
@ -43,6 +44,9 @@ const SQL_CLIENT_SOURCE_MAP: Record<SourceName, SqlClient | undefined> = {
|
||||||
[SourceName.BUDIBASE]: undefined,
|
[SourceName.BUDIBASE]: undefined,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const XSS_INPUT_REGEX =
|
||||||
|
/[<>;"'(){}]|--|\/\*|\*\/|union|select|insert|drop|delete|update|exec|script/i
|
||||||
|
|
||||||
export function getSQLClient(datasource: Datasource): SqlClient {
|
export function getSQLClient(datasource: Datasource): SqlClient {
|
||||||
if (!isSQL(datasource)) {
|
if (!isSQL(datasource)) {
|
||||||
throw new Error("Cannot get SQL Client for non-SQL datasource")
|
throw new Error("Cannot get SQL Client for non-SQL datasource")
|
||||||
|
@ -222,6 +226,15 @@ export async function validate({
|
||||||
} else {
|
} else {
|
||||||
res = validateJs.single(row[fieldName], constraints)
|
res = validateJs.single(row[fieldName], constraints)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (env.XSS_SAFE_MODE && typeof row[fieldName] === "string") {
|
||||||
|
if (XSS_INPUT_REGEX.test(row[fieldName])) {
|
||||||
|
errors[fieldName] = [
|
||||||
|
"Input not sanitised - potentially vulnerable to XSS",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (res) errors[fieldName] = res
|
if (res) errors[fieldName] = res
|
||||||
}
|
}
|
||||||
return { valid: Object.keys(errors).length === 0, errors }
|
return { valid: Object.keys(errors).length === 0, errors }
|
||||||
|
|
Loading…
Reference in New Issue