TL;DR
- Ruby on Rails 4.10, Ruby 2.4 な環境で
- AWS ElasticBeanstalk Platform の version を Amazon Linux 2016.03 v2.1.0 から
2017.09 v2.6.5
に更新した - PaperClip 4.7 でエラーが出るようになったので調べたら
ImageMagick
のpolicy.xml
でHTTPS
から直接画像を指定できないようになっていたためだった- なので、S3からダウンロードしてファイルパスを Paperclip に渡すようにした
経緯
もともと、Paperclip を使って S3 上の画像ファイルを使ってゴニョゴニョしていた。S3上のファイルは https の Endpoint を指定していた。
で、Ruby バージョンを更新することにしたので、それならついでに AWS ElasticBeanstalk Platform も更新するかー、としてみた。
すると、Paperclip を使った処理で Paperclip::Errors::NotIdentifiedByImageMagickError
が発生するようになった。
原因特定と対策
Paperclip::Errors::NotIdentifiedByImageMagickError
だけだと原因が分からないのだが、すでに以前、 ImageMagick の policy.xml が更新されたことで、rmagick
が動かなくなる現象に出会ったことがあった。こちらも rmagick
で convert
に S3 の Endpoint を渡すようにしていたためで、この時は画像をダウンロードしてから使うことにした。
同じ原因だろう、とログを差し込んで、 Paperclip で https なEndpointを指定していることを確認して原因の特定は完了。
ImageMagick の policy.xml
2016年に公開された ImageMagick の脆弱性対策のため policy.xml で制御する、という対策が取られた。
脆弱性の内容自体は次の記事が分かりやすい。
ImageMagickの脆弱性(CVE-2016-3714他)についてまとめてみた - piyolog
ImageMagickの脆弱性(ImageTragick) - てきとうなメモ
Amazon Linux もこの対策を採用している。
https://alas.aws.amazon.com/ALAS-2016-699.html
Note: This update contains an updated /etc/ImageMagick/policy.xml file that disables the EPHEMERAL, HTTPS, HTTP, URL, FTP, MVG, MSL, TEXT, and LABEL coders. If you experience any problems after the update, it may be necessary to manually adjust the policy.xml file to match your requirements. Please take additional precautions to ensure that your applications using the ImageMagick library do not process malicious or untrusted files before doing so.
実際に EC2 上の policy.xml を見てみると HTTPS は制限されている。
<policymap> <policy domain="coder" rights="none" pattern="EPHEMERAL" /> <policy domain="coder" rights="none" pattern="HTTPS" /> <policy domain="coder" rights="none" pattern="HTTP" /> <policy domain="coder" rights="none" pattern="URL" /> <policy domain="coder" rights="none" pattern="FTP" /> <policy domain="coder" rights="none" pattern="MVG" /> <policy domain="coder" rights="none" pattern="MSL" /> <policy domain="coder" rights="none" pattern="TEXT" /> <policy domain="coder" rights="none" pattern="LABEL" /> <policy domain="path" rights="none" pattern="@*" /> </policymap>
該当行をコメントアウトすると、今までどおりの処理がされた。
<policymap> <policy domain="coder" rights="none" pattern="EPHEMERAL" /> <!--<policy domain="coder" rights="none" pattern="HTTPS" />--> <policy domain="coder" rights="none" pattern="HTTP" /> <policy domain="coder" rights="none" pattern="URL" /> <policy domain="coder" rights="none" pattern="FTP" /> <policy domain="coder" rights="none" pattern="MVG" /> <policy domain="coder" rights="none" pattern="MSL" /> <policy domain="coder" rights="none" pattern="TEXT" /> <policy domain="coder" rights="none" pattern="LABEL" /> <policy domain="path" rights="none" pattern="@*" /> </policymap>
HTTPSの制御をコメントアウトして良いのか?
HTTPS で指定したファイルを使えるようにする、というのは果たして良いのだろうか?
せっかく塞いである穴を自ら開けることになるので、せめてホワイトリスト指定ができれば良い。
ImageMagick 6.9.7-7 では、そのような機能が入ったらしい。
Behavior of policy changed from 6.9.7-7 · Issue #377 · ImageMagick/ImageMagick · GitHub
ImageMagick 6.9.7-7 から policy の挙動が変わりました - awm-Tech
ただし、URLをホワイトリスト指定する方法は調べた感じなさそう。ソースコードを追いかけたわけではないので、実装上できないのかは分からない。
また、私が使っている AmazonLinux 上の ImageMagick は 6.7.8-9
なので、そもそもホワイトリスト指定は使えない。yum update
すれば良い話だけど。
やはりセキュリティの穴を自ら開けるのは嫌なので別の方法を検討する。
Paperclip コミュニティではどのように対策を?
Paperclipコミュニティでは、どのような解決方法を検討しているのか調べてみた。
- cve-2016-3714 "magic byte" validation · Issue #2190 · thoughtbot/paperclip · GitHub
- ImageMagick の脆弱性対策に対して、どう対応するか検討している
- Paperclip::Geometry.from_file not working with new ImageMagick version for urls that have https · Issue #2198 · thoughtbot/paperclip · GitHub
- https を http にすれば解決した、というコメントだが、それもまた穴あけである
結局ダウンロードしてからPaperclipに渡すことにした
他の手もあるとは思うが、仕方がないので PaperClip の Wrapper を作ることにした。 モンキーパッチは避ける主義なので、Wrapperクラスをべた書き。
Dir.mktmpdir do |tmpdir| image_file = File.basename(URI.parse(image_url).path) download_path = Pathname(dir).join(image_file) File.open(download_path, "wb") do |output| OpenURI.open_uri(image_url) do |data| output.write(data.read) end end Paperclip::Geometry.from_file(download_path) end