2011-10-27 18 views
2

有人可以解釋這裏發生了什麼嗎? 看起來,SQL語句字符串中的佔位符語法不能按預期工作(或者以不同的方式說,它違反了最不讓人驚訝的原則),並且在運行時期間爲var2執行了意外的替換/轉義:SQL佔位符在這個ruby數據庫查詢中意外的替代

ruby-1.9.2-p290 :001 > puts RUBY_VERSION 
1.9.2 
=> nil 

ruby-1.9.2-p290 :002 > require 'ipaddr' 
=> true 

ruby-1.9.2-p290 :003 > require 'sqlite3' 
=> true 

ruby-1.9.2-p290 :004 > var1 = Addrinfo.ip("1.2.3.4") 
=> #<Addrinfo: 1.2.3.4> 

ruby-1.9.2-p290 :005 > var2 = var1.ip_address 
=> "1.2.3.4" 

ruby-1.9.2-p290 :006 > var3 = "1.2.3.4" 
=> "1.2.3.4" 

ruby-1.9.2-p290 :007 > var2 == var3 
=> true 

ruby-1.9.2-p290 :008 > var2 === var3 
=> true 

ruby-1.9.2-p290 :009 > var2.eql?(var3) 
=> true 

ruby-1.9.2-p290 :010 > db = SQLite3::Database.open("test.db") 
=> #<SQLite3::Database:0x00000100bcfce0> 

ruby-1.9.2-p290 :011 > db.execute("SELECT * FROM devices WHERE deviceaddr=?", var2) 
=> [] 

ruby-1.9.2-p290 :011 > db.execute("SELECT * FROM devices WHERE deviceaddr=?", var2.to_s) 
=> [] 

ruby-1.9.2-p290 :012 > db.execute("SELECT * FROM devices WHERE deviceaddr=?", var3) 
=> [["TEST_DEVICE", "1.2.3.4"]] 

沒有SQL佔位符它工作(但公開分貝SQL注入!):

ruby-1.9.2-p290 :013 > db.execute("SELECT * FROM devices WHERE deviceaddr='#{var2}'") 
=> [["TEST_DEVICE", "1.2.3.4"]] 

那麼什麼是使這項工作以安全的方式?

回答

4

TL; DR:SQLite使用UTF;轉換Addrinfo的8位ASCII輸出。

一個「安全」的方法是在使用輸出force_encoding("UTF-8")Addrinfo,所以:

> var1.ip_address.encoding 
=> #<Encoding:ASCII-8BIT> 
> var3.encoding 
=> #<Encoding:UTF-8> 
> db.execute("SELECT * FROM foo WHERE ip=?", var2.force_encoding("UTF-8")) 
=> [["1.2.3.4"]]  
+1

我想答案是長2行不包括代碼示例如何需要一個TL; DR :) – mikej

+0

@ mikej對於代碼過敏,或threeshat知道一個更好的方法:)(我編輯了一些。) –

+0

是的,這是正確的。只需要添加一件事:可能確定正確編碼的最好方法是從db本身:'enc = db.encoding',然後執行var1.ip_address.encode(enc)或var2.encode(enc) –