我试图编写一个接受字符串数组的Ruby方法(例如,["EG", "K", "C"]
,并返回icao_code
字段以Airport.where("icao_code LIKE ?", "#{icao_start}%")
字段开头的数据库表中的所有记录那些字符串(例如,KORD,EGLL和CYVR都匹配)。数组的长度会有所不同,并且会由用户输入,因此需要对其进行清理。
如果我只搜索单个字符串,我可以执行def in_region(icao_starts)
where_clause = icao_starts.map{|i| "icao_code LIKE '#{i}%'"}.join(" OR ")
return Airport.where(where_clause)
end
之类的操作。但是,由于我需要搜索任意数量的字符串,我无法使用该语法。
现在,我的工作原理如下:
library(plotly)
whole_dat = data.frame(x1 = rnorm(50), y1 = rnorm(50), z1 = rnorm(50))
p <-
plot_ly() %>%
add_markers(
x = whole_dat$x1,
y = whole_dat$y1,
z = whole_dat$z1)
p = layout(p,
scene = list(
annotations = list(list(
x = 0.3,
y = -3,
z = -0.1,
text = "12345",
textangle= 0,
ax = 0,
ay = -75,
xref='x',
axref='x',
yref = 'paper',
ayref = 'paper',
zref = 'paper',
#showarrow=TRUE,
arrowcolor= "black",
arrowsize= 3,
arrowwidth= 1,
arrowhead= 1
))
)
)
htmlwidgets::saveWidget(as_widget(p), "test.html")
但是,我有点担心使用不受信任的用户输入这样的设置,因为我怀疑它会受到SQL注入的攻击。</ p>
有更好的方法以更安全的方式获得相同的结果吗?
答案 0 :(得分: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
)。
如果我是你,我还会在你做任何事情之前在.uniq
上执行icao_starts
,在一些合理的长度上限,截断数组,并且还有一个允许值的白名单< / s>(哦,忘记了,我以为用户正在按机场代码搜索)。这应该是绝对可靠的。
答案 1 :(得分: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的解决方案非常相似,但是没有使用正则表达式来摆脱最后的&#34; OR&#34;