TL;DR
ターミナル開いて以下叩くとls
が実行されます。
$ ruby -e 'require("logger"); Logger.new("| ls")'
概要
Ruby/Rails界隈でもeval
や``(バッククウォート)は
ユーザからの入力値入れちゃったら大変だから気をつけろ〜的なのは散々言われていますが
Logger
で任意シェルコマンド実行できるのは知らなかったのでメモとして残しておきたかったのと
それに付随してrailsのconstantize
は危険な場合があるという話です
動作環境
Ruby 2.3.1
Rails 5.0.0
Loggerでのコマンド実行方法
TL;DRにも書きましたが、単にLogger.new
の引数に|
+好きなコマンド
を入れるだけで実行できます
> require("logger")
> Logger.new("|pwd")
どういう時に危険か
The Safest Way to Constantize... (これ読んでLogger
でコマンド実行できること知りました)
この記事はRailsのconstantize
が危ないよという記事です。
constantize
とはレシーバの文字列をクラスとして返してくれるやつですね
> puts "Fixnum".class
# => String
> puts "Fixnum".constantize
# => Fixnum
動的にクラスを引っ張ってくるので地味に便利なのですが
仮にユーザからの入力値に対してconstantize
した場合に気をつける必要があります。
例えば
class ContentsController < ApplicationController
# GET /contents
def index
obj = params[:type].constantize.new(params[:value])
end
end
なんていうコントローラがあった場合に/contents?type=Logger&value=|悪意のあるコマンド
(実際にはエンコードされてるでしょう)を叩くとLogger.new("|悪意のあるコマンド")
ができあがってしまい、いとも簡単に|
以降のコマンドを実行してしまいます。
ではどうやってconstantize
を安全に使うかというのは先ほどの「The Safest Way to Constantize...」に載ってるのでそちらを参照して下さい。
まとめ
よくよく考えるとあんまこんなコード書かないかもしれませんが知ってるのと知ってないのとでは大違いなので頭の片隅にでも置いておくといいかもしれませんね