Discourseがアップロードされたファイルを誤って画像として検出する

エンジニアリングユーザーが、一般的ではないファイル拡張子を持つデータファイルを投稿に添付したいと考えています。これらは基本的にプレーンテキストファイルですが、拡張ASCII文字が含まれています。

DiscourseのNGINX設定を更新してこれらのファイルのMIMEメディアタイプを指定しようとしましたが、うまくいきませんでした。2週間前にこの件についてトピック(https://meta.discourse.org/t/how-to-customize-mime-media-type-emitted-for-certain-attachments/282111)を投稿しましたが、まだ回答がありません。NGINXが更新されなくても、不明なファイルタイプはフォールバックMIMEタイプ「application/octet-stream」で提供されます。それは今のところ問題ありません。

しかし、ユーザーがこれらのデータファイルを投稿にアップロードしようとすると(「アップロード」ボタンを使用するか、ドラッグアンドドロップするか)、Discourseから次のようなエラーポップアップが表示されます。

ユーザーがファイルをアップロードすると、Discourseは賢く振る舞い、画像かそれ以外のファイルタイプかを検出しているようです。さらに、この判定はファイルの内容を見て行っているようです(標準のUnixコマンド「file」のように)。これは、Discourseがインラインで表示するか、添付ファイルとして横に配置するかを決定するためだと推測されます。

これらのデータファイルの場合、このチェックは誤ってファイルを画像として識別しています。試しに、これらのデータファイルの一部をUbuntuボックスに置いて「file」コマンドで確認したところ、案の定、「JPEG image data」と識別されました。

Discourseが画像かどうかを検出せずにファイルをアップロードする方法はありますか?つまり、「それが何であれ、インライン表示せずに添付ファイルとしてアップロードしてください」というような方法です。

あるいは、Discourseでzipファイルを許可するように設定し、ユーザーにアップロード前にファイルをzip化するように指示することもできますが、ランダムなzipファイルアップロードをサイトに許可したくはありません。それはセキュリティ上の問題のように思えます。

ご協力ありがとうございます!

別の回避策は、それらの奇妙なファイル(.bin.data、または本当に.anythinggoesなど)に拡張子を付けることです。これにより、Discourseはそのファイルをそのままにしておくのに十分です。

迅速なご対応ありがとうございます!しかし、試してみましたが、うまくいきません。Discourse は、画像かどうかを判断するために、拡張子ではなくファイルの内容を確実に調べています。

「いいね!」 1

これについて何か考えはありますか?これはかなり重大なバグのように思えます。

この問題について調査しました。

要するに、あなたのファイルは、この種のファイルと同じシグネチャで始まるため、JPEGとして検出されています。
Discourseでこの動作を修正することは可能ですが、変更が必要です。(最後に参照)


技術的な詳細をいくつか示します。
この問題はここで始まります:

FastImageライブラリはファイルを開き、タイプとサイズを決定します。
予想どおり、JPEGというタイプが返されます。

JPEGシグネチャを見ると、次のようになります。

JPEGマーカー

詳細情報:List of file signatures - Wikipedia
JPEG - Wikipedia

常に次のマーカーバイトで始まります:FF D8

サンプルファイルをHexエディタで確認すると、同じように始まっていることがわかります。

次に、FastImageがJPEGをどのように検出するかを見ると、ここで確認できます。

ただし、必要なバイトがすべて存在しないため、画像情報を抽出することはできません。

Discourseでこの問題をどのように修正しますか?
FastImageのコードを見ると、渡すことができる便利なオプションがあります。

このオプションを使用すると、エラー(SizeNotFoundImageFetchFailureCannotParseImageUnknownImageTypeBadImageURI)が発生しても画像情報は返されず、ファイルは画像として検出されなくなります。

@image_info =
  begin
    FastImage.new(@file, :raise_on_failure => true)
  rescue StandardError
    nil
  end
...
is_image ||= @image_info && FileHelper.is_supported_image?("test.#{@image_info.type}")

その後、機能するはずです:

後でPRを作成できます。このオプションの使用は理にかなっています。:+1:

「いいね!」 2

素晴らしい!これは驚異的な分析です!ありがとうございます!

いくつか簡単な質問があります。

  1. これらの変更により、ファイルは画像として検出されなくなり、非画像としてアップロードされて投稿の右側に表示されるようになりますか?

  2. 私が正しく理解していれば、この変更をローカルのDiscourseインスタンスで行って試すか、または将来のDiscourseリリースに含まれるまでこれを使用することを提案されています。しかし、どのようにすればよいですか?(私は経験豊富なソフトウェア開発者ですが、Dockerの経験は限られており、Rubyの経験はありません。)

  3. 調整が必要なFastImageの呼び出しは、models/upload.rbにありますよね?

  1. はい、その通りです。上記のスクリーンショットのように。

  2. 修正を提案しているわけではありません。しかし、待てない場合は、その変更をテストできます。

  • 一時的な変更(再構築後に消える):
cd /var/discourse
./launcher enter app
sed -i "s/FastImage.new(@file)/FastImage.new(@file, :raise_on_failure=true)/" lib/upload_creator.rb
sed -i "s/FastImage.new(original_path)/FastImage.new(original_path, :raise_on_failure=true)/" app/models/upload.rb
exit
  • 永続的な変更(再構築後も残る):
cd /var/discourse
nano containers/app.yml (お好みのエディタを使用してください)

以下のカスタムコマンドを末尾(runセクション)に追加します:

  - replace:
      filename: "/var/www/discourse/lib/upload_creator.rb"
      from: "FastImage.new(@file)"
      to: "FastImage.new(@file, :raise_on_failure=true)"
  - replace:
      filename: "/var/www/discourse/app/models/upload.rb"
      from: "FastImage.new(original_path)"
      to: "FastImage.new(original_path, :raise_on_failure=true)"

その後、再構築します:

./launcher rebuild app
  1. 拡張子のないファイルをアップロードする予定であれば、そうだと思います。他の箇所でも同様の変更が必要かどうかは確認していません。
「いいね!」 1

@Arkshine – これらの詳細について、大変ありがとうございました。両方の修正を個別にテストすることができました(それぞれを新しく復元したVMでテストしました)が、どちらも機能しました!

注:

  1. 一時的な修正については、変更を有効にするために「./launcher restart app」を実行する必要がありました。

  2. 「spec/models/optimized_image_spec.rb」にもFastImage.new()への参照があるようです。これも他のものと同様に更新する必要がありますか?

ご協力いただき、重ねて感謝いたします!

動作してよかったです。 :slight_smile:

  1. これはテスト目的のためだけなので、心配する必要はありません。

素晴らしい!ありがとうございます!開発環境でこれをテストしたので、テスト環境と運用環境にデプロイします。

ところで、お時間があれば、関連する問題(https://meta.discourse.org/t/how-to-customize-mime-media-type-emitted-for-certain-attachments/282111)についてもご意見を伺いたいです。

「いいね!」 1

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.