2008-11-06 84 views
4

我們剛剛獲得了以下代碼,作爲離岸開發人員提供的新應用程序中複雜搜索查詢的解決方案。我對使用動態SQL持懷疑態度,因爲我可以使用';'關閉SQL語句。然後執行將在數據庫上執行的討厭!動態SQL的危害是什麼,可以避免嗎?

關於如何解決噴射攻擊的任何想法?

ALTER procedure [dbo].[SearchVenues] --'','',10,1,1,'' 
@selectedFeature as varchar(MAX), 
@searchStr as varchar(100), 
@pageCount as int, 
@startIndex as int, 
@searchId as int, 
@venueName as varchar(100), 
@range int, 
@latitude varchar(100), 
@longitude varchar(100), 
@showAll int, 
@OrderBy varchar(50), 
@SearchOrder varchar(10) 

AS 
DECLARE @sqlRowNum as varchar(max) 
DECLARE @sqlRowNumWhere as varchar(max) 
DECLARE @withFunction as varchar(max) 
DECLARE @withFunction1 as varchar(max) 
DECLARE @endIndex as int 
SET @endIndex = @startIndex + @pageCount -1 

SET @sqlRowNum = ' SELECT Row_Number() OVER (ORDER BY ' 

IF @OrderBy = 'Distance' 
    SET @sqlRowNum = @sqlRowNum + 'dbo.GeocodeDistanceMiles(Latitude,Longitude,' + @latitude + ',' + @longitude + ') ' [email protected] 
ELSE 
    SET @sqlRowNum = @sqlRowNum + @OrderBy + ' '+ @SearchOrder 

SET @sqlRowNum = @sqlRowNum + ') AS RowNumber,ID,RecordId,EliteStatus,Name,Description, 
Address,TotalReviews,AverageFacilityRating,AverageServiceRating,Address1,Address2,Address3,Address4,Address5,Address6,PhoneNumber, 
visitCount,referalCount,requestCount,imgUrl,Latitude,Longitude, 
Convert(decimal(10,2),dbo.GeocodeDistanceMiles(Latitude,Longitude,' + @latitude + ',' + @longitude + ')) as distance 
FROM VenueAllData ' 

SET @sqlRowNumWhere = 'where Enabled=1 and EliteStatus <> 3 ' 

--PRINT('@sqlRowNum ='[email protected]) 
IF @searchStr <> '' 
BEGIN 

    IF (@searchId = 1) -- county search 
    BEGIN 
     SET @sqlRowNumWhere = @sqlRowNumWhere + ' and Address5 like ''' + @searchStr + '%''' 
    END 
    ELSE IF(@searchId = 2 ) -- Town search 
    BEGIN 
     SET @sqlRowNumWhere = @sqlRowNumWhere + ' and Address4 like ''' + @searchStr + '%''' 
    END 
    ELSE IF(@searchId = 3 ) -- postcode search 
    BEGIN 
     SET @sqlRowNumWhere = @sqlRowNumWhere + ' and Address6 like ''' + @searchStr + '%''' 
    END  

    IF (@searchId = 4) -- Search By Name 
    BEGIN 
     IF @venueName <> '' 
      SET @sqlRowNumWhere = @sqlRowNumWhere + ' and (Name like ''%' + @venueName + '%'' OR Address like ''%'+ @venueName+'%'') ' 
     ELSE 
      SET @sqlRowNumWhere = @sqlRowNumWhere + ' and (Name like ''%' + @searchStr + '%'' OR Address like ''%'+ @searchStr+'%'') ' 
    END 
END 


IF @venueName <> '' AND @searchId <> 4 
    SET @sqlRowNumWhere = @sqlRowNumWhere + ' and (Name like ''%' + @venueName + '%'' OR Address like ''%'+ @venueName+'%'') ' 


set @sqlRowNum = @sqlRowNum + ' ' + @sqlRowNumWhere 


--PRINT(@sqlRowNum) 

IF @selectedFeature <> '' 
    BEGIN 
     DECLARE @val1 varchar (255) 
     Declare @SQLAttributes varchar(max) 
     Set @SQLAttributes = '' 
     Declare @tempAttribute varchar(max) 
     Declare @AttrId int 
     while (@selectedFeature <> '') 
      BEGIN 
       SET @AttrId = CAST(SUBSTRING(@selectedFeature,1,CHARINDEX(',',@selectedFeature)-1) AS Int) 
       Select @tempAttribute = ColumnName from Attribute where id = @AttrId 
       SET @selectedFeature = SUBSTRING(@selectedFeature,len(@AttrId)+2,len(@selectedFeature)) 
       SET @SQLAttributes = @SQLAttributes + ' ' + @tempAttribute + ' = 1 And ' 
      END 
     Set @SQLAttributes = SUBSTRING(@SQLAttributes,0,LEN(@SQLAttributes)-3) 
     set @sqlRowNum = @sqlRowNum + ' and ID in (Select VenueId from ' 
     set @sqlRowNum = @sqlRowNum + ' CachedVenueAttributes WHERE ' + @SQLAttributes + ') ' 

    END 

IF @showAll <> 1 
    set @sqlRowNum = @sqlRowNum + ' and dbo.GeocodeDistanceMiles(Latitude,Longitude,' + @latitude + ',' + @longitude + ') <= ' + convert(varchar,@range) 


set @withFunction = 'WITH LogEntries AS (' + @sqlRowNum + ') 

SELECT * FROM LogEntries WHERE RowNumber between '+ Convert(varchar,@startIndex) + 
' and ' + Convert(varchar,@endIndex) + ' ORDER BY ' + @OrderBy + ' ' + @SearchOrder 


print(@withFunction) 
exec(@withFunction) 

回答

5

順便說一句,我不會用EXEC;而是我會使用sp_executesql。有關使用動態sql的原因和其他信息,請參閱這篇極好的文章,The Curse and Blessings of Dynamic SQL

+0

這篇文章是amazzing。每個動態SQL開發人員都應該使用它。 – digiguru 2008-11-06 11:32:47

1

下面是上面查詢的優化版本不使用動態SQL ...

Declare @selectedFeature as varchar(MAX), 
@searchStr as varchar(100), 
@pageCount as int, 
@startIndex as int, 
@searchId as int, 
@venueName as varchar(100), 
@range int, 
@latitude varchar(100), 
@longitude varchar(100), 
@showAll int, 
@OrderBy varchar(50), 
@SearchOrder varchar(10) 

Set @startIndex = 1 
Set @pageCount = 50 



Set @searchStr = 'e' 
Set @searchId = 4 
Set @OrderBy = 'Address1' 
Set @showAll = 1 
--Select dbo.GeocodeDistanceMiles(Latitude,Longitude,@latitude,@longitude) 


DECLARE @endIndex int 
SET @endIndex = @startIndex + @pageCount -1 
; 

WITH LogEntries as (
SELECT 
    Row_Number() 
     OVER (ORDER BY 
      CASE @OrderBy 
       WHEN 'Distance' THEN Cast(dbo.GeocodeDistanceMiles(Latitude,Longitude,@latitude,@longitude) as varchar(10)) 
       WHEN 'Name' THEN Name 
       WHEN 'Address1' THEN Address1 
       WHEN 'RecordId' THEN Cast(RecordId as varchar(10)) 
       WHEN 'EliteStatus' THEN Cast(EliteStatus as varchar(10)) 
      END) AS RowNumber, 
RecordId,EliteStatus,Name,Description, 
Address,TotalReviews,AverageFacilityRating,AverageServiceRating,Address1,Address2,Address3,Address4,Address5,Address6,PhoneNumber, 
visitCount,referalCount,requestCount,imgUrl,Latitude,Longitude, 
Convert(decimal(10,2),dbo.GeocodeDistanceMiles(Latitude,Longitude,@latitude,@longitude)) as distance 
FROM VenueAllData 
where Enabled=1 and EliteStatus <> 3 
And 
    (
     (Address5 like @searchStr + '%' And @searchId = 1) OR 
     (Address4 like @searchStr + '%' And @searchId = 2) OR 
     (Address6 like @searchStr + '%' And @searchId = 3) OR 
     (
      (
       @searchId = 4 And 
        (Name like '%' + @venueName + '%' OR Address like '%'+ @searchStr+'%') 
      ) 
     ) 
    ) 
And 
    ID in (
     Select VenueID 
     From CachedVenueAttributes 
     --Extra Where Clause for the processing of VenueAttributes using @selectedFeature 
    ) 
And 
    ( 
     (@showAll = 1) Or 
     (@showAll <> 1 and dbo.GeocodeDistanceMiles(Latitude,Longitude,@latitude,@longitude) <= convert(varchar,@range)) 
    ) 
) 

SELECT * FROM LogEntries 
WHERE RowNumber between @startIndex and @endIndex 
ORDER BY CASE @OrderBy 
       WHEN 'Distance' THEN Cast(Distance as varchar(10)) 
       WHEN 'Name' THEN Name 
       WHEN 'Address1' THEN Address1 
       WHEN 'RecordId' THEN Cast(RecordId as varchar(10)) 
       WHEN 'EliteStatus' THEN Cast(EliteStatus as varchar(10)) 
      END 

我沒有固定的唯一事情是從CachedVenueAttributes選擇,似乎建立一個WHERE語句在一個循環中。我想我可能會把它放在一個表值函數中,並將其重構爲程序的其餘部分。

+0

除了修復可能的SQL注入攻擊之外,這個非動態SQL很可能會因使用'錯誤'的緩存查詢計劃而受到影響(請參閱參數嗅探)。 – 2008-11-16 04:53:57

0

我喜歡用於搜索的動態SQL。

我過去曾經使用過.Net準備好的語句,任何用戶生成的字符串都作爲參數傳入,而不作爲SQL中的文本包含在內。

要與現有解決方案一起運行,您可以做許多事情來降低風險。

  1. 白名單輸入驗證輸入,所以它只能包含A-ZA-Z0-9 \ w(字母數字和空格)(不好,如果你需要支持Unicode字符)
  2. 執行任何動態sql作爲受限用戶。將存儲過程的所有者設置爲只能讀取相關表的用戶。拒絕寫入所有表格等。另外,當調用這個存儲過程時,你可能需要與一個用戶做類似的限制,因爲它的應用程序MS-SQL在storedproc中執行動態sql作爲調用用戶而不是storedproc的所有者。
相關問題