此 ruby 数据库查询中 SQL 占位符的意外替换
有人可以解释这里发生了什么吗? 看起来 SQL 语句字符串中的占位语法没有按预期工作(或者,换句话说,它违反了最小意外原则),并且在运行时对 进行了意外的替换/转义var2
:
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"]]
那么什么是安全的方法来使其工作呢?
Can someone explain what's happening here?
It seems that the placeholding syntax in SQL statement string doesn't work as expected (or, to say it in a different way, it violates the principle of least surprise), and during runtime an unexpected substitution/escaping is done for var2
:
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"]]
Without the SQL placeholder it works (but exposes the db to SQL injections!):
ruby-1.9.2-p290 :013 > db.execute( "SELECT * FROM devices WHERE deviceaddr='#{var2}'" )
=> [["TEST_DEVICE", "1.2.3.4"]]
So what is a safe way to make this work?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
TL;DR:SQLite 使用 UTF;转换 Addrinfo 的 8 位 ASCII 输出。
一种“安全”的方法是对
Addrinfo
的输出使用force_encoding("UTF-8")
,因此:TL;DR: SQLite uses UTF; convert Addrinfo's 8-bit ASCII output.
One "safe" way is to use
force_encoding("UTF-8")
on the output fromAddrinfo
, so: