diff --git a/packages/backend/src/remote/activitypub/check-fetch.ts b/packages/backend/src/remote/activitypub/check-fetch.ts
index ab46d97f85..a170e3eb3a 100644
--- a/packages/backend/src/remote/activitypub/check-fetch.ts
+++ b/packages/backend/src/remote/activitypub/check-fetch.ts
@@ -10,8 +10,6 @@ import type { IncomingMessage } from "http";
 import type { CacheableRemoteUser } from "@/models/entities/user.js";
 import type { UserPublickey } from "@/models/entities/user-publickey.js";
 import { verify } from "node:crypto";
-import { toSingle } from "@/prelude/array.js";
-import { createHash } from "node:crypto";
 
 export async function hasSignature(req: IncomingMessage): Promise<string> {
 	const meta = await fetchMeta();
@@ -158,20 +156,3 @@ export function verifySignature(
 		return false;
 	}
 }
-
-export function verifyDigest(
-	body: string,
-	digest: string | string[] | undefined,
-): boolean {
-	digest = toSingle(digest);
-	if (
-		body == null ||
-		digest == null ||
-		!digest.toLowerCase().startsWith("sha-256=")
-	)
-		return false;
-
-	return (
-		createHash("sha256").update(body).digest("base64") === digest.substring(8)
-	);
-}
diff --git a/packages/backend/src/server/activitypub.ts b/packages/backend/src/server/activitypub.ts
index 3af3d3c7ac..660db98e48 100644
--- a/packages/backend/src/server/activitypub.ts
+++ b/packages/backend/src/server/activitypub.ts
@@ -23,7 +23,6 @@ import { getUserKeypair } from "@/misc/keypair-store.js";
 import {
 	checkFetch,
 	getSignatureUser,
-	verifyDigest,
 } from "@/remote/activitypub/check-fetch.js";
 import { getInstanceActor } from "@/services/instance-actor.js";
 import { fetchMeta } from "@/misc/fetch-meta.js";
@@ -35,6 +34,9 @@ import Outbox, { packActivity } from "./activitypub/outbox.js";
 import { serverLogger } from "./index.js";
 import config from "@/config/index.js";
 import Koa from "koa";
+import * as crypto from "node:crypto";
+import { inspect } from "node:util";
+import type { IActivity } from "@/remote/activitypub/type.js";
 
 // Init router
 const router = new Router();
@@ -43,27 +45,94 @@ const router = new Router();
 
 function inbox(ctx: Router.RouterContext) {
 	if (ctx.req.headers.host !== config.host) {
+		serverLogger.warn("inbox: Invalid Host");
 		ctx.status = 400;
+		ctx.message = "Invalid Host";
 		return;
 	}
 
-	let signature;
+	let signature: httpSignature.IParsedSignature;
 
 	try {
 		signature = httpSignature.parseRequest(ctx.req, {
 			headers: ["(request-target)", "digest", "host", "date"],
 		});
 	} catch (e) {
+		serverLogger.warn(`inbox: signature parse error: ${inspect(e)}`);
 		ctx.status = 401;
+
+		if (e instanceof Error) {
+			if (e.name === "ExpiredRequestError")
+				ctx.message = "Expired Request Error";
+			if (e.name === "MissingHeaderError")
+				ctx.message = "Missing Required Header";
+		}
+
 		return;
 	}
 
-	if (!verifyDigest(ctx.request.rawBody, ctx.headers.digest)) {
+	// Validate signature algorithm
+	if (
+		!signature.algorithm
+			.toLowerCase()
+			.match(/^((dsa|rsa|ecdsa)-(sha256|sha384|sha512)|ed25519-sha512|hs2019)$/)
+	) {
+		serverLogger.warn(
+			`inbox: invalid signature algorithm ${signature.algorithm}`,
+		);
 		ctx.status = 401;
+		ctx.message = "Invalid Signature Algorithm";
+		return;
+
+		// hs2019
+		// keyType=ED25519 => ed25519-sha512
+		// keyType=other => (keyType)-sha256
+	}
+
+	// Validate digest header
+	const digest = ctx.req.headers.digest;
+
+	if (typeof digest !== "string") {
+		serverLogger.warn(
+			"inbox: zero or more than one digest header(s) are present",
+		);
+		ctx.status = 401;
+		ctx.message = "Invalid Digest Header";
 		return;
 	}
 
-	processInbox(ctx.request.body, signature);
+	const match = digest.match(/^([0-9A-Za-z-]+)=(.+)$/);
+
+	if (match == null) {
+		serverLogger.warn("inbox: unrecognized digest header");
+		ctx.status = 401;
+		ctx.message = "Invalid Digest Header";
+		return;
+	}
+
+	const digestAlgo = match[1];
+	const expectedDigest = match[2];
+
+	if (digestAlgo.toUpperCase() !== "SHA-256") {
+		serverLogger.warn("inbox: unsupported digest algorithm");
+		ctx.status = 401;
+		ctx.message = "Unsupported Digest Algorithm";
+		return;
+	}
+
+	const actualDigest = crypto
+		.createHash("sha256")
+		.update(ctx.request.rawBody)
+		.digest("base64");
+
+	if (expectedDigest !== actualDigest) {
+		serverLogger.warn("inbox: Digest Mismatch");
+		ctx.status = 401;
+		ctx.message = "Digest Missmatch";
+		return;
+	}
+
+	processInbox(ctx.request.body as IActivity, signature);
 
 	ctx.status = 202;
 }