feat: 加强安全性 传输过程使用salt sha256

This commit is contained in:
手瓜一十雪
2025-04-19 19:50:52 +08:00
parent b1047309c9
commit fda050d3fe
6 changed files with 40 additions and 17 deletions

View File

@@ -20,25 +20,26 @@ export const CheckDefaultTokenHandler: RequestHandler = async (_, res) => {
export const LoginHandler: RequestHandler = async (req, res) => {
// 获取WebUI配置
const WebUiConfigData = await WebUiConfig.GetWebUIConfig();
// 获取请求体中的token
const { token } = req.body;
// 获取请求体中的hash
const { hash } = req.body;
// 获取客户端IP
const clientIP = req.ip || req.socket.remoteAddress || '';
// 如果token为空返回错误信息
if (isEmpty(token)) {
if (isEmpty(hash)) {
return sendError(res, 'token is empty');
}
// 检查登录频率
if (!WebUiDataRuntime.checkLoginRate(clientIP, WebUiConfigData.loginRate)) {
return sendError(res, 'login rate limit');
}
//验证config.token是否等于token
if (WebUiConfigData.token !== token) {
//验证config.token hash是否等于token hash
if (!AuthHelper.comparePasswordHash(WebUiConfigData.token, hash)) {
return sendError(res, 'token is invalid');
}
// 签发凭证
const signCredential = Buffer.from(JSON.stringify(AuthHelper.signCredential(WebUiConfigData.token))).toString(
const signCredential = Buffer.from(JSON.stringify(AuthHelper.signCredential(hash))).toString(
'base64'
);
// 返回成功信息

View File

@@ -5,13 +5,13 @@ export class AuthHelper {
/**
* 签名凭证方法。
* @param token 待签名的凭证字符串。
* @param hash 待签名的凭证字符串。
* @returns 签名后的凭证对象。
*/
public static signCredential(token: string): WebUiCredentialJson {
public static signCredential(hash: string): WebUiCredentialJson {
const innerJson: WebUiCredentialInnerJson = {
CreatedTime: Date.now(),
TokenEncoded: token,
HashEncoded: hash,
};
const jsonString = JSON.stringify(innerJson);
const hmac = crypto.createHmac('sha256', AuthHelper.secretKey).update(jsonString, 'utf8').digest('hex');
@@ -57,8 +57,7 @@ export class AuthHelper {
const currentTime = Date.now() / 1000;
const createdTime = credentialJson.Data.CreatedTime;
const timeDifference = currentTime - createdTime;
return timeDifference <= 3600 && credentialJson.Data.TokenEncoded === token;
return timeDifference <= 3600 && credentialJson.Data.HashEncoded === AuthHelper.generatePasswordHash(token);
}
/**
@@ -85,4 +84,23 @@ export class AuthHelper {
return store.exists(`revoked:${hmac}`) > 0;
}
/**
* 生成密码Hash
* @param password 密码
* @returns 生成的Hash值
*/
public static generatePasswordHash(password: string): string {
return crypto.createHash('sha256').update(password + '.napcat').digest().toString('hex')
}
/**
* 对比密码和Hash值
* @param password 密码
* @param hash Hash值
* @returns 布尔值表示密码是否匹配Hash值
*/
public static comparePasswordHash(password: string, hash: string): boolean {
return this.generatePasswordHash(password) === hash;
}
}

View File

@@ -21,17 +21,18 @@ export async function auth(req: Request, res: Response, next: NextFunction) {
return sendError(res, 'Unauthorized');
}
// 获取token
const token = authorization[1];
const hash = authorization[1];
if(!hash) return sendError(res, 'Unauthorized');
// 解析token
let Credential: WebUiCredentialJson;
try {
Credential = JSON.parse(Buffer.from(token, 'base64').toString('utf-8'));
Credential = JSON.parse(Buffer.from(hash, 'base64').toString('utf-8'));
} catch (e) {
return sendError(res, 'Unauthorized');
}
// 获取配置
const config = await WebUiConfig.GetWebUIConfig();
// 验证凭证在1小时内有效且token与原始token相同
// 验证凭证在1小时内有效
const credentialJson = AuthHelper.validateCredentialWithinOneHour(config.token, Credential);
if (credentialJson) {
// 通过验证

View File

@@ -1,6 +1,6 @@
interface WebUiCredentialInnerJson {
CreatedTime: number;
TokenEncoded: string;
HashEncoded: string;
}
interface WebUiCredentialJson {