BULK INSERT报错3:路径无法找到及SQL注入防护问题排查
问题:SQL注入防护后OPENROWSET(BULK)无法正常解析路径
- 初始代码(运行正常但存在SQL注入风险):
select @CHEMIN_FICHIER = 'C:\\crm_tmp\\Images\\Equipements\\' + @NOM_FICHIER;
- 为防注入修改后的代码(PRINT验证路径一致,但BULK INSERT无法运行):
select @CHEMIN_FICHIER = 'C:\\rm_tmp\\Images\\Equipements\\' + REPLACE(REPLACE(QUOTENAME(@NOM_FICHIER) , '[', ''), ']', '');
对应的动态执行语句:
select @COMMANDE = 'INSERT INTO [image] (nom, donnees) SELECT '''' + @NOM_FICHIER + ''', BulkColumn FROM OPENROWSET(Bulk ''''+ @CHEMIN_FICHIER + ''', SINGLE_BLOB) AS BLOB';
- 尝试参数化方案B(@NOM_FICHIER未被解析,路径错误):
set @ParamDefinition = '@NOM_FICHIER nvarchar(255)' select @CHEMIN_FICHIER = 'C:\\crm_tmp\\Images\\Equipements\\@NOM_FICHIER'; select @COMMANDE = 'INSERT INTO [image] (nom, donnees) SELECT '''' + @NOM_FICHIER + ''', BulkColumn FROM OPENROWSET(Bulk ''''+ @CHEMIN_FICHIER + ''', SINGLE_BLOB) AS BLOB'; execute sp_executesql @COMMANDE, @ParamDefinition, @NOM_FICHIER
错误提示:Cannot bulk load because the file, BULK INSERT error code 3: The system cannot find the path specified,生成的路径为C:\\crm_tmp\\Images\\Equipements\\@NOM_FICHIER而非预期的C:\\crm_tmp\\Images\\Equipements\\test.png
解决方案
方法1:安全拼接文件名+合法性验证
通过严格过滤非法字符、验证文件存在性,在可控范围内拼接路径:
-- 过滤文件名中的路径遍历/非法字符 set @NOM_FICHIER = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( @NOM_FICHIER, '\', ''), '/', ''), ':', ''), '*', ''), '?', ''), '"', ''), '<', ''), '>', ''), '|', ''); -- 拼接合法路径 select @CHEMIN_FICHIER = 'C:\\crm_tmp\\Images\\Equipements\\' + @NOM_FICHIER; -- 验证文件是否存在(需确保SQL Server账户有路径访问权限) declare @fileExists int; exec xp_fileexist @CHEMIN_FICHIER, @fileExists output; if @fileExists = 1 begin -- 转义单引号避免SQL语法错误 select @COMMANDE = 'INSERT INTO [image] (nom, donnees) SELECT ''' + REPLACE(@NOM_FICHIER, '''', '''''') + ''', BulkColumn FROM OPENROWSET(Bulk ''' + REPLACE(@CHEMIN_FICHIER, '''', '''''') + ''', SINGLE_BLOB) AS BLOB'; execute sp_executesql @COMMANDE; end else begin raiserror('文件不存在或路径非法', 16, 1); end
方法2:参数化路径(SQL Server 2017+支持)
从SQL Server 2017开始,OPENROWSET支持直接使用参数传递路径,彻底避免拼接风险:
declare @COMMANDE nvarchar(max); declare @ParamDefinition nvarchar(max); declare @CHEMIN_FICHIER nvarchar(500); -- 先过滤非法字符 set @NOM_FICHIER = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( @NOM_FICHIER, '\', ''), '/', ''), ':', ''), '*', ''), '?', ''), '"', ''), '<', ''), '>', ''), '|', ''); select @CHEMIN_FICHIER = 'C:\\crm_tmp\\Images\\Equipements\\' + @NOM_FICHIER; -- 构造参数化动态SQL set @ParamDefinition = '@FilePath nvarchar(500), @FileName nvarchar(255)'; set @COMMANDE = N'INSERT INTO [image] (nom, donnees) SELECT @FileName, BulkColumn FROM OPENROWSET(BULK @FilePath, SINGLE_BLOB) AS BLOB'; execute sp_executesql @COMMANDE, @ParamDefinition, @FilePath = @CHEMIN_FICHIER, @FileName = @NOM_FICHIER;
注意:需确保SQL Server服务账户拥有目标文件路径的读取权限。
内容的提问来源于stack exchange,提问作者user609511
相关产品推荐
相关产品推荐

