Skip to content

Commit

Permalink
安全修复
Browse files Browse the repository at this point in the history
  • Loading branch information
SunWuyuan committed Dec 29, 2024
1 parent df7f5b4 commit 4445b74
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 81 deletions.
25 changes: 21 additions & 4 deletions middleware/auth.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,42 @@
import logger from "../utils/logger.js";
import configManager from "../utils/configManager.js";

/**
* 需要登录的中间件
* @param {import("express").Request} req
* @param {import("express").Response} res
* @param {import("express").NextFunction} next
*/
async function needlogin(req, res, next) {
if (!res.locals.login) {
// 未登录,返回401 Unauthorized状态码
logger.info(`[needlogin] - ${req.ip} - 未登录,返回401 Unauthorized状态码`);
return res.status(401).send({ status: "0", msg: "请先登录以继续操作" });
}
next(); // 已登录,继续处理请求
}

/**
* 需要管理员权限的中间件
* @param {import("express").Request} req
* @param {import("express").Response} res
* @param {import("express").NextFunction} next
*/
async function needadmin(req, res, next) {
if (!res.locals.login) {
// 未登录,返回401 Unauthorized状态码
logger.info(`[needadmin] - ${req.ip} - 未登录,返回401 Unauthorized状态码`);
return res.status(401).send({ status: "0", msg: "请先登录以继续操作" });
}
if (res.locals.email !==await configManager.getConfig("security.adminuser")) {
// 未登录,返回401 Unauthorized状态码

const adminEmail = await configManager.getConfig("security.adminuser");
if (res.locals.email !== adminEmail) {
logger.info(`[needadmin] - ${req.ip} - 权限不足,返回401 Unauthorized状态码`);
return res.status(401).send({ status: "0", msg: "权限不足" });
}
next(); // 已登录,继续处理请求
}

export {
needlogin,
needadmin
};

58 changes: 29 additions & 29 deletions middleware/captcha.js
Original file line number Diff line number Diff line change
@@ -1,39 +1,39 @@
import { error as _error, debug } from "../logger.js";
import { error as loggerError, debug } from "../logger.js";
import { getConfig } from "../configManager.js";
import axios from "axios";
import { URL } from "url";

import express from "express";

const app = express();
import { post } from "request";

app.use(async (req, res, next) => {
const recaptcha =
req.body.recaptcha || req.body.re || req.query.recaptcha || req.query.re;
const captchaMiddleware = async (req, res, next) => {
const recaptcha = req.body.recaptcha || req.query.recaptcha;

if (!recaptcha) {
return res.status(200).send({ message: "请完成验证码" });
return res.status(400).send({ message: "请完成验证码" });
}

post(
{
url: await getConfig('captcha.reverify'),
form: { secret: await getConfig('captcha.resecret'), response: recaptcha },
},
function (error, httpResponse, body) {
if (error) {
_error("Error verifying recaptcha:", error);
res.status(200).send({ message: "验证码验证失败", error: error });
}
try {
const { url, secret } = await getConfig("captcha");

const response = JSON.parse(body);
debug(response);
if (response.success) {
next();
} else {
res.status(200).send({ message: "验证码无效", response: response });
const response = await axios.post(
new URL("/siteverify", url),
null,
{
params: {
secret,
response: recaptcha,
},
}
);

if (response.data.success) {
next();
} else {
res.status(400).send({ message: "验证码无效", response: response.data });
}
);
});
} catch (error) {
loggerError("Error verifying recaptcha:", error);
res.status(500).send({ message: "验证码验证失败", error: error.message });
}
};

export default captchaMiddleware;

export default app;
52 changes: 24 additions & 28 deletions middleware/geetest.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,38 @@
import logger from "../utils/logger.js";
import configManager from "../utils/configManager.js";

import express from "express";
import { parse } from "querystring";
import { createHmac } from "crypto";
import axios from "axios";

const app = express();

// 从配置中读取极验的相关信息
import { parse } from "url";
import { createHmac } from "crypto";

const GEE_CAPTCHA_ID = await configManager.getConfig("captcha.GEE_CAPTCHA_ID");
const GEE_CAPTCHA_KEY = await configManager.getConfig("captcha.GEE_CAPTCHA_KEY");
const GEE_API_SERVER = await configManager.getConfig("captcha.GEE_API_SERVER");
const API_URL = `${GEE_API_SERVER}/validate?captcha_id=${GEE_CAPTCHA_ID}`;
logger.debug(API_URL);

// 中间件处理极验验证码验证
app.use(async (req, res, next) => {
/**
* 生成签名的函数,使用 HMAC-SHA256
* @param {String} value - 待签名的字符串
* @param {String} key - 签名密钥
* @returns {String} 签名结果
*/
function hmacSha256Encode(value, key) {
return createHmac("sha256", key).update(value, "utf8").digest("hex");
}

/**
* 验证码中间件
* @param {Object} req - express的request对象
* @param {Object} res - express的response对象
* @param {Function} next - express的next函数
*/
async function geetestMiddleware(req, res, next) {

// 如果是开发环境,直接放行
if (process.env.NODE_ENV === "development") {
logger.debug("In development environment, bypass geetest validation.");
next();
return;
}

// 验证码信息
Expand Down Expand Up @@ -53,7 +63,7 @@ app.use(async (req, res, next) => {
logger.debug(geetest);

// 生成签名
const sign_token = hmac_sha256_encode(geetest.lot_number, GEE_CAPTCHA_KEY);
const signToken = hmacSha256Encode(geetest.lot_number, GEE_CAPTCHA_KEY);

// 准备请求参数
const datas = {
Expand All @@ -68,19 +78,11 @@ app.use(async (req, res, next) => {
// 发送请求到极验服务
logger.debug("Sending request to Geetest server...");
logger.debug(API_URL);
const result = await axios({
method: "post",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
url: API_URL, // 极验验证码验证接口
data: datas,
});
const result = await axios.post(API_URL, datas);

if (result.data.result === "success") {
next(); // 验证成功,继续处理请求
} else {
console.log(result.data);
logger.debug(`Validate fail: ${result.data.reason}`);
res.status(500).send({
code: 500,
Expand All @@ -92,13 +94,7 @@ app.use(async (req, res, next) => {
logger.error("Geetest server error:", error);
next(); // 极验服务器出错时放行,避免阻塞业务逻辑
}
});
};

// 生成签名的函数,使用 HMAC-SHA256
function hmac_sha256_encode(value, key) {
logger.debug(value);
logger.debug(key);
return createHmac("sha256", key).update(value, "utf8").digest("hex");
}
export default geetestMiddleware;

export default app;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"crypto-js": "^4.1.1",
"csrf-csrf": "^3.1.0",
"dotenv": "^16.4.7",
"ejs": "^3.1.10",
"express": "^4.21.2",
Expand Down
20 changes: 10 additions & 10 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions routes/router_account.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ router.all("*", function (req, res, next) {
});


import geetest from "../middleware/geetest.js";
import geetestMiddleware from "../middleware/geetest.js";
router.post("/login", async function (req, res, next) {
try {
if (
Expand Down Expand Up @@ -116,7 +116,7 @@ router.get("/logout", function (req, res) {
res.redirect("/");
});

router.post("/register", geetest, async function (req, res, next) {
router.post("/register", geetestMiddleware, async function (req, res, next) {
try {
const email = req.body.un;
var SQL = `SELECT id FROM ow_users WHERE email='${email}' LIMIT 1`;
Expand Down Expand Up @@ -155,7 +155,7 @@ router.post("/register", geetest, async function (req, res, next) {
}
});

router.post("/repw", geetest, async function (req, res, next) {
router.post("/repw", geetestMiddleware, async function (req, res, next) {
try {
if (req.body.un == "" || req.body.un == null) {
res.status(200).send({ message: "账户格式错误" });
Expand Down Expand Up @@ -189,7 +189,7 @@ router.post("/repw", geetest, async function (req, res, next) {
}
});

router.post("/torepw", geetest, async function (req, res, next) {
router.post("/torepw", geetestMiddleware, async function (req, res, next) {
let SET;
let UPDATE;
try {
Expand Down Expand Up @@ -398,7 +398,7 @@ router.post("/totp/protected-route", validateTotpToken, (req, res) => {
});
});

router.post("/magiclink/generate", geetest, async (req, res) => {
router.post("/magiclink/generate", geetestMiddleware, async (req, res) => {
try {
const { email } = req.body;
if (!email || !emailTest(email)) {
Expand Down
10 changes: 5 additions & 5 deletions routes/router_my.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { createHash } from "crypto";
import { msg_fail, S3update, checkhash, hash as _hash,prisma } from "../utils/global.js";
//数据库
import { query, qww } from "../utils/database.js";
import geetest from "../middleware/geetest.js";
import geetestMiddleware from "../middleware/geetest.js";

router.all("*", function (req, res, next) {
//限定访问该模块的权限:必须已登录
Expand Down Expand Up @@ -249,7 +249,7 @@ router.post("/project/del", function (req, res) {
res.status(200).send({ status: "success", msg: "删除成功" });
});
});
router.post("/set/avatar", geetest,async (req, res) => {
router.post("/set/avatar", geetestMiddleware,async (req, res) => {
if (!req.files?.file) {
return res.status(200).send({ status: "文件上传失败" });
}
Expand All @@ -269,7 +269,7 @@ router.post("/set/avatar", geetest,async (req, res) => {
});
});
//修改个人信息
router.post("/set/userinfo", geetest, function (req, res) {
router.post("/set/userinfo", geetestMiddleware, function (req, res) {
var UPDATE = `UPDATE ow_users SET ? WHERE id=${res.locals.userid} LIMIT 1`;
var SET = {
display_name: req.body["display_name"],
Expand All @@ -290,7 +290,7 @@ router.post("/set/userinfo", geetest, function (req, res) {
});
});
//修改个人信息
router.post("/set/username", geetest, function (req, res) {
router.post("/set/username", geetestMiddleware, function (req, res) {
var UPDATE = `UPDATE ow_users SET ? WHERE id=${res.locals.userid} LIMIT 1`;
var SET = {
username: req.body.username,
Expand All @@ -308,7 +308,7 @@ router.post("/set/username", geetest, function (req, res) {
});
});
//修改密码:动作
router.post("/set/pw", geetest, function (req, res) {
router.post("/set/pw", geetestMiddleware, function (req, res) {
SQL = `SELECT password FROM ow_users WHERE id=? LIMIT 1`;
id = res.locals.userid;

Expand Down

0 comments on commit 4445b74

Please sign in to comment.