Skip to content

Use magic bytes for image validations instead of extension #14

@achempion

Description

@achempion

to address the stavro/arc#263 from @speeddragon and stavro/arc#73 from @cichaczem

Since last vulnerabilities with GhostScript, and because ImageMagick use it (for example when we use convert), should we include and modify the current examples to use ones that check for magic bytes ?

So instead of using this for image validation,

defmodule Avatar do
  use Arc.Definition
  @extension_whitelist ~w(.jpg .jpeg .gif .png)

  def validate({file, _}) do
    file_extension = file.file_name |> Path.extname() |> String.downcase()
    Enum.member?(@extension_whitelist, file_extension)
  end
end
defmodule Helper do
@doc """
  JPG magic bytes: 0xffd8
  """
  @spec is_jpg(String.t()) :: boolean
  def is_jpg(file) do
    with {:ok, file_content} <- :file.open(file, [:read, :binary]),
         {:ok, <<255, 216>>} <- :file.read(file_content, 2) do
      true
    else
      _error ->
        false
    end
  end

  @doc """
  PNG magic bytes: 0x89504e470d0a1a0a
  """
  @spec is_png(String.t()) :: boolean
  def is_png(file) do
    with {:ok, file_content} <- :file.open(file, [:read, :binary]),
         {:ok, <<137, 80, 78, 71, 13, 10, 26, 10>>} <- :file.read(file_content, 8) do
      true
    else
      _error ->
        false
    end
  end
end

defmodule Avatar do
  use Arc.Definition
  @extension_whitelist ~w(.jpg .jpeg .gif .png)

  def validate({file, _}) do
    file_extension = file.file_name |> Path.extname() |> String.downcase()
    Enum.member?(@extension_whitelist, file_extension) && (Helper.is_jpg(file.path) || Helper.is_png(file.path))
  end
end

I can also try to add for GIF or other file formats.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions