Limit instance emoji to image types

Else malicious emoji packs or our EmojiStealer MRF can
put payloads into the same domain as the instance itself.
Sanitising the content type should prevent proper clients
from acting on any potential payload.

Note, this does not affect the default emoji shipped with Akkoma
as they are handled by another plug. However, those are fully trusted
and thus not in needed of sanitisation.
This commit is contained in:
Oneric 2024-03-07 00:00:25 +01:00
parent 0ec62acb9d
commit ba558c0c24
3 changed files with 36 additions and 8 deletions

View file

@ -3,8 +3,12 @@
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Plugs.InstanceStatic do
import Plug.Conn
require Pleroma.Constants
alias Pleroma.Web.Plugs.Utils
@moduledoc """
This is a shim to call `Plug.Static` but with runtime `from` configuration.
@ -43,11 +47,25 @@ def call(conn, _) do
conn
end
defp call_static(conn, opts, from) do
defp set_static_content_type(conn, "/emoji/" <> _ = request_path) do
real_mime = MIME.from_path(request_path)
safe_mime = Utils.get_safe_mime_type(%{allowed_mime_types: ["image"]}, real_mime)
put_resp_header(conn, "content-type", safe_mime)
end
defp set_static_content_type(conn, request_path) do
put_resp_header(conn, "content-type", MIME.from_path(request_path))
end
defp call_static(%{request_path: request_path} = conn, opts, from) do
opts =
opts
|> Map.put(:from, from)
|> Map.put(:set_content_type, false)
Plug.Static.call(conn, opts)
conn
|> set_static_content_type(request_path)
|> Pleroma.Web.Plugs.StaticNoCT.call(opts)
end
end

View file

@ -11,6 +11,7 @@ defmodule Pleroma.Web.Plugs.UploadedMedia do
require Logger
alias Pleroma.Web.MediaProxy
alias Pleroma.Web.Plugs.Utils
@behaviour Plug
# no slashes
@ -76,14 +77,9 @@ defp media_is_banned(_, {:url, url}), do: MediaProxy.in_banned_urls(url)
defp media_is_banned(_, _), do: false
defp get_safe_mime_type(%{allowed_mime_types: allowed_mime_types} = _opts, mime) do
[maintype | _] = String.split(mime, "/", parts: 2)
if maintype in allowed_mime_types, do: mime, else: "application/octet-stream"
end
defp set_content_type(conn, opts, filepath) do
real_mime = MIME.from_path(filepath)
clean_mime = get_safe_mime_type(opts, real_mime)
clean_mime = Utils.get_safe_mime_type(opts, real_mime)
put_resp_header(conn, "content-type", clean_mime)
end

View file

@ -0,0 +1,14 @@
# Akkoma: Magically expressive social media
# Copyright © 2024 Akkoma Authors <https://akkoma.dev>
# SPDX-License-Identifier: AGPL-3.0-only
defmodule Pleroma.Web.Plugs.Utils do
@moduledoc """
Some helper functions shared across several plugs
"""
def get_safe_mime_type(%{allowed_mime_types: allowed_mime_types} = _opts, mime) do
[maintype | _] = String.split(mime, "/", parts: 2)
if maintype in allowed_mime_types, do: mime, else: "application/octet-stream"
end
end