我正在使用 Firebase 产品开发一个无服务器后端,我的端点被实现为 onCall 云函数 (v2)。我创建了一个中间件功能来确保只有经过身份验证的用户才能访问特定功能。此外,我的一些 API 需要 Firebase 身份验证令牌中的自定义声明 { Roles: ["admin", "superadmin"] }。
我最近发现可以修改 Firebase Auth 令牌 (JWT) 中的角色属性,该令牌是根据 Firebase Auth 中注册的自定义声明生成的。这引发了人们对用户是否可以篡改令牌来升级权限(例如,授予自己管理员权限)的担忧。
我想确认这是否是真正的安全问题,或者我的代码中是否遗漏了某些内容。
下面是我用来处理身份验证和基于角色的访问控制的中间件:
export const withAuthentication =
(
requiredAccessRoles?: string[] // Roles are optional
) =>
(
handler: (request: CallableRequest) => Promise<any> // Function to handle the request
): ((request: CallableRequest) => Promise<any>) => {
return async (request) => {
const authHeader = request.rawRequest.headers.authorization as
| string
| undefined;
// Check if Authorization header is present and properly formatted
if (!authHeader || !authHeader.startsWith("Bearer "))
throw new HttpsError("unauthenticated", "Invalid or missing ID token.");
if (!request.auth || !request.auth.uid)
throw new HttpsError("unauthenticated", "Unauthenticated user");
// Extract the ID token from the header
const idToken = authHeader.slice(7).trim();
try {
// Validate the ID token
await getAuth().verifyIdToken(idToken);
} catch (error) {
throw new HttpsError("unauthenticated", "Invalid or expired ID token.");
}
// If roles are required, perform the role check
if (requiredAccessRoles && requiredAccessRoles.length > 0) {
// Check if the user has at least one of the required roles
const hasAnyRole = requiredAccessRoles.some((role) =>
request.auth?.token.roles.includes(role)
);
if (!hasAnyRole)
throw new HttpsError("permission-denied", "Insufficient privileges");
}
// Proceed with the original handler
return handler(request);
};
};
这是处理请求并使用中间件执行基于角色的访问控制的 onCall 云函数:
export const testApiEndpoint = onCall(
withAuthentication(["admin", "superadmin"])(async (request) => {
try {
return {
message: "access granted"
};
} catch (error) {
throw new HttpsError("internal", "Something went wrong");
}
})
);
问题:
任何见解将不胜感激!
更新:以下是重现问题的步骤:
Firebase Auth 在运行 getAuth().verifyIdToken(idToken) 时确实可以防止伪造,但它不会检查伪造的自定义声明。例如,如果您尝试更改令牌的到期日期,verifyIdToken(idToken) 将抛出错误。
我最近发现可以修改 Firebase Auth 令牌 (JWT) 中的角色属性,该令牌是根据 Firebase Auth 中注册的自定义声明生成的。
要为项目创建 Firebase 身份验证 JWT,您必须有权访问该项目的管理凭据。 他们获取这些凭据的唯一方法是您将他们作为管理员添加到项目中,或者管理员共享凭据和他们在一起。
一旦有人有权访问这些管理凭据,他们就可以在项目上做任何他们想做的事情。他们不需要创建 JWT 来执行此操作,因为他们已经拥有管理凭据的完全访问权限