我有一个SQL查询,它接受用户输入,因此存在安全漏洞。
现有查询为:
SELECT BUS_NM, STR_ADDR_1, CITY_NM, STATE_CD, POSTAL_CD, COUNTRY_CD,
BUS_PHONE_NB,PEG_ACCOUNT_ID, GDN_ALERT_ID, GBIN, GDN_MON_REF_NB,
ALERT_DT, ALERT_TYPE, ALERT_DESC,ALERT_PRIORITY
FROM ( SELECT A.BUS_NM, AE.STR_ADDR_1, A.CITY_NM, A.STATE_CD, A.POSTAL_CD,
CC.COUNTRY_CD, A.BUS_PHONE_NB, A.PEG_ACCOUNT_ID, 'I' ||
LPAD(INTL_ALERT_DTL_ID, 9,'0') GDN_ALERT_ID,
LPAD(IA.GBIN, 9,'0') GBIN, IA.GDN_MON_REF_NB,
DATE(IAD.ALERT_TS) ALERT_DT,
XMLCAST(XMLQUERY('$A/alertTypeConfig/biqCode/text()' passing
IAC.INTL_ALERT_TYPE_CONFIG as "A") AS CHAR(4)) ALERT_TYPE,
, ROW_NUMBER() OVER () AS "RN"
FROM ACCOUNT A, Other tables
WHERE IA.GDN_MON_REF_NB = '100'
AND A.PEG_ACCOUNT_ID = IAAR.PEG_ACCOUNT_ID
AND CC.COUNTRY_CD = A.COUNTRY_ISO3_CD
ORDER BY IA.INTL_ALERT_ID ASC )
WHERE ALERT_TYPE IN (" +TriggerType+ ");
我将其更改为接受来自setString的TriggerType,例如:
SELECT BUS_NM, STR_ADDR_1, CITY_NM, STATE_CD, POSTAL_CD, COUNTRY_CD,
BUS_PHONE_NB,PEG_ACCOUNT_ID, GDN_ALERT_ID, GBIN, GDN_MON_REF_NB,
ALERT_DT, ALERT_TYPE, ALERT_DESC,ALERT_PRIORITY
FROM ( SELECT A.BUS_NM, AE.STR_ADDR_1, A.CITY_NM, A.STATE_CD, A.POSTAL_CD,
CC.COUNTRY_CD, A.BUS_PHONE_NB, A.PEG_ACCOUNT_ID,
'I' || LPAD(INTL_ALERT_DTL_ID, 9,'0') GDN_ALERT_ID,
LPAD(IA.GBIN, 9,'0') GBIN, IA.GDN_MON_REF_NB,
DATE(IAD.ALERT_TS) ALERT_DT,
XMLCAST(XMLQUERY('$A/alertTypeConfig/biqCode/text()' passing
IAC.INTL_ALERT_TYPE_CONFIG as "A") AS CHAR(4)) ALERT_TYPE,
ROW_NUMBER() OVER () AS "RN"
FROM ACCOUNT A, other tables
WHERE IA.GDN_MON_REF_NB = '100'
AND A.PEG_ACCOUNT_ID = IAAR.PEG_ACCOUNT_ID
AND CC.COUNTRY_CD = A.COUNTRY_ISO3_CD
ORDER BY IA.INTL_ALERT_ID ASC )
WHERE ALERT_TYPE IN (?);
设置触发器类型如下:
if (StringUtils.isNotBlank(request.getTriggerType())) {
preparedStatement.setString(1, triggerType != null ? triggerType.toString() : "");
}
获取错误为
由以下原因引起:com.ibm.db2.jcc.am.SqlDataException: DB2 SQL 错误: SQLCODE=-302, SQLSTATE=22001, SQLERRMC=null, DRIVER=4.19.26
参数的IN
谓词用法错误。
不要期望IN ('AAAA, M250, ABCD')
(当您尝试将逗号分隔的字符串作为单个参数传递时)可以IN ('AAAA', 'M250', 'ABCD')
工作(根据需要)。这些谓词不等效。
如果你想传递这样一个逗号分隔的字符串,你需要一些"字符串分词器",如下所示。
select t.*
from
(
select XMLCAST(XMLQUERY('$A/alertTypeConfig/biqCode/text()' passing IAC.INTL_ALERT_TYPE_CONFIG as "A") AS CHAR(4)) ALERT_TYPE
from table(values xmlparse(document '<alertTypeConfig><biqCode>M250, really big code</biqCode></alertTypeConfig>')) IAC(INTL_ALERT_TYPE_CONFIG)
) t
--WHERE ALERT_TYPE IN ('AAAA, M250, ABCD')
join xmltable('for $id in tokenize($s, ",s?") return <i>{string($id)}</i>'
passing cast('AAA, M250 , ABCD' as varchar(200)) as "s"
columns token varchar(200) path '.') x on x.token=t.ALERT_TYPE
;
按原样运行语句。然后,您可以使用WHERE
子句取消注释字符串,并注释掉其余部分以查看您尝试执行的操作。
PS:
您得到的错误可能是因为您没有指定参数的数据类型(您不使用类似IN (cast(? as varchar(xxx)))
的东西,并且 db2 编译器假定其长度等于ALERT_TYPE
表达式的长度(4 个字节)。
-302 SQLCODE 表示某种转换错误。
SQLSTATE 22001 通过告诉我们您正在尝试将大字符串强制为小变量来缩小范围。鉴于您问题中的信息有限,我猜罪魁祸首是XMLCAST
。
DB2 不会把 30 磅的垃圾塞进一个 4 磅重的袋子里,可以这么说,它会给你一个错误。也许在演员阵容中给XML一些额外的空间可能会有所帮助。如果您需要确保它最终只有 4 个字符长,您可以显式执行LEFT(XMLCAST( ... AS VARCHAR(64)), 4)
.这样,XMLCAST
就有了它需要的空间,但你把它剪掉了,以适应你的变量在抓取时。
另一件事可能是传递给参数标记的变量太长。DB2 将根据ALERT_TYPE
的长度猜测类型和长度。请注意,只能通过参数标记传递单个值。如果传递逗号分隔列表,它将不会按预期运行(除非您希望ALERT_TYPE
也包含逗号分隔列表)。如果要从表中获取逗号分隔的列表,则可以改用子选择。