我有执行动态方法的这些代码。我在这里使用eval
来执行它,但是我想做的就是将其更改为public_send
,因为这样告诉我,它更安全。
当前代码:
# update workstep logic here.
incoming_status = params[params[:name]]
# grab workflow, this is current data, use this to compare status to in comming status
workflow = get_workorder_product_workstep(params[:workflow_id])
# check current status if its pending allow to update
# security concern EVAL!
if eval("workflow.can_#{incoming_status}?")
# update status
eval("workflow.#{incoming_status}")
# updated attribute handled_by
workflow.update_attributes(handled_by_id: @curr_user.id)
workflow.save
else
flash[:notice] = 'Action not allowed'
end
这里是eval
。如何将其更改为public_send
这是我的工作。
public_send("workflow.can_#{incoming_status}?")
public_send("#{workflow}.can_#{incoming_status}?")
它们都不起作用。给我没有方法的错误。第一个公共错误返回此undefined method workflow.can_queue? for #<Spree::Admin::WorkordersController:0x00007ff71c8e6f00>
但是它应该工作,因为我有方法workflow.can_queue?
公开的第二个错误是
undefined method #<Spree::WorkorderProductWorkstep:0x00007ff765663550>.can_queue? for #<Spree::Admin::WorkordersController:0x00007ff76597f798>
我认为第二个workflow
正在单独评估?我不确定。
答案 0 :(得分:4)
使用public_send
,您可以将相关行更改为:
if workflow.public_send("can_#{incoming_status}?")
# update status
workflow.public_send(incoming_status.to_s)
# ...
有关安全性和风险的说明
workflow.public_send("can_#{xyz}?")
只能在workflow
上调用public
且以前缀can_
开头并以?
结尾的方法。那可能只是少数方法,您可以轻松决定是否要允许所有这些方法。
workflow.public_send("#{incoming_status'})
有所不同,因为它允许workflow
甚至destroy
上的所有公共方法。这意味着在没有"can_#{incoming_status}?"
的情况下使用它可能是一个坏主意。或者,您至少应该首先检查incoming_status
是否在允许的方法的白名单中。
eval
是最糟糕的,因为它将在没有任何上下文的情况下评估整个字符串(例如workflow
之类的对象)。对您拥有eval("workflow.#{incoming_status}")
的映像进行检查,无需先检查是否实际允许incoming_status
。如果有人随后像这样发送incoming_status
"to_s; system('xyz')"
,那么xyz
可能就是一切-例如通过电子邮件发送隐藏文件,安装后门或删除某些文件的命令。