From 24f23b460ca686bb27003d269dc5375b9901b811 Mon Sep 17 00:00:00 2001 From: junjun Date: Wed, 17 Sep 2025 14:45:49 +0800 Subject: [PATCH] fix: Fix possible SQL injection vulnerabilities --- backend/apps/db/db.py | 20 ++++---- backend/apps/db/db_sql.py | 100 +++++++++++++++++++------------------- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/backend/apps/db/db.py b/backend/apps/db/db.py index 5018c994..9c1b2cfa 100644 --- a/backend/apps/db/db.py +++ b/backend/apps/db/db.py @@ -264,10 +264,10 @@ def get_schema(ds: CoreDatasource): def get_tables(ds: CoreDatasource): conf = DatasourceConf(**json.loads(aes_decrypt(ds.configuration))) if ds.type != "excel" else get_engine_config() db = DB.get_db(ds.type) - sql = get_table_sql(ds, conf, get_version(ds)) + sql, sql_param = get_table_sql(ds, conf, get_version(ds)) if db.connect_type == ConnectType.sqlalchemy: with get_session(ds) as session: - with session.execute(text(sql)) as result: + with session.execute(text(sql), {"param": sql_param}) as result: res = result.fetchall() res_list = [TableSchema(*item) for item in res] return res_list @@ -275,7 +275,7 @@ def get_tables(ds: CoreDatasource): if ds.type == 'dm': with dmPython.connect(user=conf.username, password=conf.password, server=conf.host, port=conf.port) as conn, conn.cursor() as cursor: - cursor.execute(sql, timeout=conf.timeout) + cursor.execute(sql, {"param": sql_param}, timeout=conf.timeout) res = cursor.fetchall() res_list = [TableSchema(*item) for item in res] return res_list @@ -283,7 +283,7 @@ def get_tables(ds: CoreDatasource): with pymysql.connect(user=conf.username, passwd=conf.password, host=conf.host, port=conf.port, db=conf.database, connect_timeout=conf.timeout, read_timeout=conf.timeout) as conn, conn.cursor() as cursor: - cursor.execute(sql) + cursor.execute(sql, {"param": sql_param}) res = cursor.fetchall() res_list = [TableSchema(*item) for item in res] return res_list @@ -291,7 +291,7 @@ def get_tables(ds: CoreDatasource): with redshift_connector.connect(host=conf.host, port=conf.port, database=conf.database, user=conf.username, password=conf.password, timeout=conf.timeout) as conn, conn.cursor() as cursor: - cursor.execute(sql) + cursor.execute(sql, {"param": sql_param}) res = cursor.fetchall() res_list = [TableSchema(*item) for item in res] return res_list @@ -304,10 +304,10 @@ def get_tables(ds: CoreDatasource): def get_fields(ds: CoreDatasource, table_name: str = None): conf = DatasourceConf(**json.loads(aes_decrypt(ds.configuration))) if ds.type != "excel" else get_engine_config() db = DB.get_db(ds.type) - sql = get_field_sql(ds, conf, table_name) + sql, p1, p2 = get_field_sql(ds, conf, table_name) if db.connect_type == ConnectType.sqlalchemy: with get_session(ds) as session: - with session.execute(text(sql)) as result: + with session.execute(text(sql), {"param1": p1, "param2": p2}) as result: res = result.fetchall() res_list = [ColumnSchema(*item) for item in res] return res_list @@ -315,7 +315,7 @@ def get_fields(ds: CoreDatasource, table_name: str = None): if ds.type == 'dm': with dmPython.connect(user=conf.username, password=conf.password, server=conf.host, port=conf.port) as conn, conn.cursor() as cursor: - cursor.execute(sql, timeout=conf.timeout) + cursor.execute(sql, {"param1": p1, "param2": p2}, timeout=conf.timeout) res = cursor.fetchall() res_list = [ColumnSchema(*item) for item in res] return res_list @@ -323,7 +323,7 @@ def get_fields(ds: CoreDatasource, table_name: str = None): with pymysql.connect(user=conf.username, passwd=conf.password, host=conf.host, port=conf.port, db=conf.database, connect_timeout=conf.timeout, read_timeout=conf.timeout) as conn, conn.cursor() as cursor: - cursor.execute(sql) + cursor.execute(sql, {"param1": p1, "param2": p2}) res = cursor.fetchall() res_list = [ColumnSchema(*item) for item in res] return res_list @@ -331,7 +331,7 @@ def get_fields(ds: CoreDatasource, table_name: str = None): with redshift_connector.connect(host=conf.host, port=conf.port, database=conf.database, user=conf.username, password=conf.password, timeout=conf.timeout) as conn, conn.cursor() as cursor: - cursor.execute(sql) + cursor.execute(sql, {"param1": p1, "param2": p2}) res = cursor.fetchall() res_list = [ColumnSchema(*item) for item in res] return res_list diff --git a/backend/apps/db/db_sql.py b/backend/apps/db/db_sql.py index 10af38f8..f5483779 100644 --- a/backend/apps/db/db_sql.py +++ b/backend/apps/db/db_sql.py @@ -34,17 +34,17 @@ def get_version_sql(ds: CoreDatasource, conf: DatasourceConf): def get_table_sql(ds: CoreDatasource, conf: DatasourceConf, db_version: str = ''): if ds.type == "mysql" or ds.type == "doris": - return f""" + return """ SELECT TABLE_NAME, TABLE_COMMENT FROM information_schema.TABLES WHERE - TABLE_SCHEMA = '{conf.database}' - """ + TABLE_SCHEMA = :param + """, conf.database elif ds.type == "sqlServer": - return f""" + return """ SELECT TABLE_NAME AS [TABLE_NAME], ISNULL(ep.value, '') AS [TABLE_COMMENT] @@ -57,10 +57,10 @@ def get_table_sql(ds: CoreDatasource, conf: DatasourceConf, db_version: str = '' AND ep.name = 'MS_Description' WHERE t.TABLE_TYPE IN ('BASE TABLE', 'VIEW') - AND t.TABLE_SCHEMA = '{conf.dbSchema}' - """ + AND t.TABLE_SCHEMA = :param + """, conf.dbSchema elif ds.type == "pg" or ds.type == "excel": - return f""" + return """ SELECT c.relname AS TABLE_NAME, COALESCE(d.description, obj_description(c.oid)) AS TABLE_COMMENT FROM pg_class c @@ -68,59 +68,59 @@ def get_table_sql(ds: CoreDatasource, conf: DatasourceConf, db_version: str = '' pg_namespace n ON n.oid = c.relnamespace LEFT JOIN pg_description d ON d.objoid = c.oid AND d.objsubid = 0 - WHERE n.nspname = '{conf.dbSchema}' + WHERE n.nspname = :param AND c.relkind IN ('r', 'v', 'p', 'm') AND c.relname NOT LIKE 'pg_%' AND c.relname NOT LIKE 'sql_%' ORDER BY c.relname \ - """ + """, conf.dbSchema elif ds.type == "oracle": - return f""" + return """ SELECT t.TABLE_NAME AS "TABLE_NAME", NVL(c.COMMENTS, '') AS "TABLE_COMMENT" FROM ( SELECT TABLE_NAME, 'TABLE' AS OBJECT_TYPE FROM DBA_TABLES - WHERE OWNER = '{conf.dbSchema}' + WHERE OWNER = :param UNION ALL SELECT VIEW_NAME AS TABLE_NAME, 'VIEW' AS OBJECT_TYPE FROM DBA_VIEWS - WHERE OWNER = '{conf.dbSchema}' + WHERE OWNER = :param ) t LEFT JOIN DBA_TAB_COMMENTS c ON t.TABLE_NAME = c.TABLE_NAME AND c.TABLE_TYPE = t.OBJECT_TYPE - AND c.OWNER = '{conf.dbSchema}' + AND c.OWNER = :param ORDER BY t.TABLE_NAME - """ + """, conf.dbSchema elif ds.type == "ck": version = int(db_version.split('.')[0]) if version < 22: - return f""" + return """ SELECT name, null as comment FROM system.tables - WHERE database = '{conf.database}' + WHERE database = :param AND engine NOT IN ('Dictionary') ORDER BY name - """ + """, conf.database else: - return f""" + return """ SELECT name, comment FROM system.tables - WHERE database = '{conf.database}' + WHERE database = :param AND engine NOT IN ('Dictionary') ORDER BY name - """ + """, conf.database elif ds.type == 'dm': - return f""" + return """ select table_name, comments from all_tab_comments - where owner='{conf.dbSchema}' + where owner=:param AND (table_type = 'TABLE' or table_type = 'VIEW') - """ + """, conf.dbSchema elif ds.type == 'redshift': - return f""" + return """ SELECT relname AS TableName, obj_description(relfilenode::regclass, 'pg_class') AS TableDescription @@ -128,13 +128,13 @@ def get_table_sql(ds: CoreDatasource, conf: DatasourceConf, db_version: str = '' pg_class WHERE relkind in ('r','p', 'f') - AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = '{conf.dbSchema}') - """ + AND relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = :param) + """, conf.dbSchema def get_field_sql(ds: CoreDatasource, conf: DatasourceConf, table_name: str = None): if ds.type == "mysql" or ds.type == "doris": - sql1 = f""" + sql1 = """ SELECT COLUMN_NAME, DATA_TYPE, @@ -142,12 +142,12 @@ def get_field_sql(ds: CoreDatasource, conf: DatasourceConf, table_name: str = No FROM INFORMATION_SCHEMA.COLUMNS WHERE - TABLE_SCHEMA = '{conf.database}' + TABLE_SCHEMA = :param1 """ - sql2 = f" AND TABLE_NAME = '{table_name}'" if table_name is not None and table_name != "" else "" - return sql1 + sql2 + sql2 = " AND TABLE_NAME = :param2" if table_name is not None and table_name != "" else "" + return sql1 + sql2, conf.database, table_name elif ds.type == "sqlServer": - sql1 = f""" + sql1 = """ SELECT COLUMN_NAME AS [COLUMN_NAME], DATA_TYPE AS [DATA_TYPE], @@ -160,12 +160,12 @@ def get_field_sql(ds: CoreDatasource, conf: DatasourceConf, table_name: str = No AND EP.minor_id = C.ORDINAL_POSITION AND EP.name = 'MS_Description' WHERE - C.TABLE_SCHEMA = '{conf.dbSchema}' + C.TABLE_SCHEMA = :param1 """ - sql2 = f" AND C.TABLE_NAME = '{table_name}'" if table_name is not None and table_name != "" else "" - return sql1 + sql2 + sql2 = " AND C.TABLE_NAME = :param2" if table_name is not None and table_name != "" else "" + return sql1 + sql2, conf.dbSchema, table_name elif ds.type == "pg" or ds.type == "excel" or ds.type == "redshift": - sql1 = f""" + sql1 = """ SELECT a.attname AS COLUMN_NAME, pg_catalog.format_type(a.atttypid, a.atttypmod) AS DATA_TYPE, col_description(c.oid, a.attnum) AS COLUMN_COMMENT @@ -174,14 +174,14 @@ def get_field_sql(ds: CoreDatasource, conf: DatasourceConf, table_name: str = No pg_catalog.pg_class c ON a.attrelid = c.oid JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace - WHERE n.nspname = '{conf.dbSchema}' + WHERE n.nspname = :param1 AND a.attnum > 0 AND NOT a.attisdropped \ """ - sql2 = f" AND c.relname = '{table_name}'" if table_name is not None and table_name != "" else "" - return sql1 + sql2 + sql2 = " AND c.relname = :param2" if table_name is not None and table_name != "" else "" + return sql1 + sql2, conf.dbSchema, table_name elif ds.type == "oracle": - sql1 = f""" + sql1 = """ SELECT col.COLUMN_NAME AS "COLUMN_NAME", (CASE @@ -201,23 +201,23 @@ def get_field_sql(ds: CoreDatasource, conf: DatasourceConf, table_name: str = No AND col.TABLE_NAME = com.TABLE_NAME AND col.COLUMN_NAME = com.COLUMN_NAME WHERE - col.OWNER = '{conf.dbSchema}' + col.OWNER = :param1 """ - sql2 = f" AND col.TABLE_NAME = '{table_name}'" if table_name is not None and table_name != "" else "" - return sql1 + sql2 + sql2 = " AND col.TABLE_NAME = :param2" if table_name is not None and table_name != "" else "" + return sql1 + sql2, conf.dbSchema, table_name elif ds.type == "ck": - sql1 = f""" + sql1 = """ SELECT name AS COLUMN_NAME, type AS DATA_TYPE, comment AS COLUMN_COMMENT FROM system.columns - WHERE database = '{conf.database}' + WHERE database = :param1 """ - sql2 = f" AND table = '{table_name}'" if table_name is not None and table_name != "" else "" - return sql1 + sql2 + sql2 = " AND table = :param2" if table_name is not None and table_name != "" else "" + return sql1 + sql2, conf.database, table_name elif ds.type == 'dm': - sql1 = f""" + sql1 = """ SELECT c.COLUMN_NAME AS "COLUMN_NAME", c.DATA_TYPE AS "DATA_TYPE", @@ -230,7 +230,7 @@ def get_field_sql(ds: CoreDatasource, conf: DatasourceConf, table_name: str = No AND c.TABLE_NAME = com.TABLE_NAME AND c.COLUMN_NAME = com.COLUMN_NAME WHERE - c.OWNER = '{conf.dbSchema}' + c.OWNER = :param1 """ - sql2 = f" AND c.TABLE_NAME = '{table_name}'" if table_name is not None and table_name != "" else "" - return sql1 + sql2 + sql2 = " AND c.TABLE_NAME = :param2" if table_name is not None and table_name != "" else "" + return sql1 + sql2, conf.dbSchema, table_name