在此ruby数据库查询中意外替换了SQL占位符

时间:2011-10-27 16:51:26

标签: ruby sqlite sqlite3-ruby

有人可以解释这里发生了什么吗? 似乎SQL语句字符串中的占位语法不能按预期工作(或者,以不同的方式说,它违反了最小意外的原则),并且在运行时期间为{{1}执行了意外的替换/转义。 }}:

var2

没有SQL占位符它可以工作(但是将数据库暴露给SQL注入!):

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"]] 

那么这项工作的安全方法是什么?

1 个答案:

答案 0 :(得分:4)

TL; DR:SQLite使用UTF;转换Addrinfo的8位ASCII输出。

一个&#34;安全&#34;方法是对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"]]