2017-08-10 61 views
1

我試圖編寫一個接受字符串數組的Ruby方法(例如,["EG", "K", "C"],並返回數據庫表中的所有記錄,其中icao_code字段以任何這些字符串(例如,KORD,EGLL和CYVR都是匹配的),陣列的長度會有所不同,並且會由用戶輸入,因此需要對其進行消毒。Ruby on Rails中的任意長度的LIKE子句ActiveRecord

如果我只是在搜索對於單個字符串,我可以執行類似於Airport.where("icao_code LIKE ?", "#{icao_start}%")的操作。但是,由於我需要針對任意數量的字符串進行搜索,所以我不能使用該語法。 OT它的工作如下:

def in_region(icao_starts) 
    where_clause = icao_starts.map{|i| "icao_code LIKE '#{i}%'"}.join(" OR ") 
    return Airport.where(where_clause) 
end 

不過,我使用的是設置這樣的不受信任的用戶輸入,因爲我懷疑這將是容易受到SQL注入有點擔心。

有沒有更好的方法以更安全的方式獲得相同的結果?

回答

1

你可以考慮這樣的事情:

def in_region(icao_starts) 
    where_clause = "icao_code LIKE '#?%' OR " * icao_starts.length 
    return Airport.where(where_clause.sub(/\ OR\ $/, ''), *icao_starts) 
end 

這將建立一個(可能很長?)字符串?佔位符。 *icao_starts將把該數組擴展爲where子句的參數,因此每個?都將最終被安全替換。 sub(/\ OR\ $/, '')只是簡單修剪最後的OR(如果需要,您可以附加1=0)。

如果我是你,我也將在icao_starts執行.uniq你做任何事情之前,截斷陣列在一些明智的上長度的限制,,也有允許值的白名單(哦,忘了,我還以爲用戶正在按機場代碼搜索)。這應該是非常正確的。

+1

結束了使用'compact'和'uniq'的。我也做了一個map {| s | s.upcase.tr {「^ A-Z」,「」)}'處理輸入小寫字母的用戶並刪除任何非字母字符。 – bogardpd

1

你是對的,沒有插入用戶輸入到你的SQL查詢。這很危險,並且使您的代碼容易受到SQLI攻擊。

def in_region(icao_starts) 
    conditions = icao_starts.map { "icao_code LIKE ?"} 
    Airport.where(conditions.join(' OR '), *icao_starts.map { |name| "#{name}%"}) 
end 

它比bogardpd的解決方案非常相似,但不使用正規擺脫過去的「OR」

相關問題