Skip to content

Commit

Permalink
Merge pull request jason5ng32#196 from jason5ng32/dev
Browse files Browse the repository at this point in the history
Security Updates
  • Loading branch information
jason5ng32 authored May 5, 2024
2 parents 7dadcaf + a702a6d commit 8eac75f
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 29 deletions.
8 changes: 5 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
PORT=11966
BACKEND_PORT=18966
FRONTEND_PORT=11966
BING_MAP_API_KEY=""
ALLOWED_DOMAINS=""
IPINFO_API_TOKEN=""
Expand All @@ -7,5 +8,6 @@ IPCHECKING_API_KEY=""
CLOUDFLARE_API=""
VITE_RECAPTCHA_SITE_KEY=""
RECAPTCHA_SECRET_KEY=""
BLACKLIST_LOG_FILE_PATH=""
RATE_LIMIT=""
SECURITY_BLACKLIST_LOG_FILE_PATH=""
SECURITY_RATE_LIMIT=""
SECURITY_DELAY_AFTER=""
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,11 @@ You can use the program without adding any environment variables, but if you wan

| Variable Name | Required | Default Value | Description |
| --- | --- | --- | --- |
| `PORT` | No | `18966` | The port on which the program runs |
| `BACKEND_PORT` | No | `18966` | The running port of the backend part of the program |
| `FRONTEND_PORT` | No | `11966` | The running port of the frontend part of the program |
| `SECURITY_RATE_LIMIT` | No | `0` | Controls the number of requests an IP can make to the backend server every 60 minutes (set to 0 for no limit) |
| `SECURITY_DELAY_AFTER` | No | `0` | Controls the first X requests from an IP every 20 minutes that are not subject to speed limits, and after X requests, the delay will increase |
| `SECURITY_BLACKLIST_LOG_FILE_PATH` | No | `logs/blacklist-ip.log` | Path setting. Records the list of IPs that triggered the limit after SECURITY_RATE_LIMIT is enabled |
| `BING_MAP_API_KEY` | No | `""` | API Key for Bing Maps, used to display the location of the IP on a map |
| `ALLOWED_DOMAINS` | No | `""` | Allowed domains for access, separated by commas, used to prevent misuse of the backend API |
| `IPCHECKING_API_KEY` | No | `""` | API Key for IPCheck.ing, used to obtain accurate IP geolocation information |
Expand All @@ -109,6 +113,8 @@ You can use the program without adding any environment variables, but if you wan
| `VITE_RECAPTCHA_SITE_KEY` | No | `""` | Google reCAPTCHA's Site Key, used to display reCAPTCHA verification on the frontend |
| `RECAPTCHA_SECRET_KEY` | No | `""` | Google reCAPTCHA's Secret Key, used to verify reCAPTCHA verification on the backend |

*Environment variables starting with `SECURITY_` are only valid when deploying using npm or Docker.*

### Using Environment Variables in a Node Environment

Create environment variables:
Expand All @@ -120,7 +126,8 @@ cp .env.example .env
Modify `.env`, and for example, add the following:

```bash
PORT=18966
BACKEND_PORT=18966
FRONTEND_PORT=11966
BING_MAP_API_KEY="YOUR_KEY_HERE"
ALLOWED_DOMAINS="example.com"
IPCHECKING_API="YOUR_KEY_HERE"
Expand Down
11 changes: 9 additions & 2 deletions README_FR.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,11 @@ Vous pouvez utiliser le programme sans ajouter de variables d'environnement, mai

| Nom de la variable | Requis | Valeur par défaut | Description |
| --- | --- | --- | --- |
| `PORT` | Non | `18966` | Le port sur lequel le programme s'exécute |
| `BACKEND_PORT` | Non | `18966` | Le port d'exécution de la partie backend du programme |
| `FRONTEND_PORT` | Non | `11966` | Le port d'exécution de la partie frontend du programme |
| `SECURITY_RATE_LIMIT` | Non | `0` | Contrôle le nombre de requêtes qu'une adresse IP peut faire au serveur backend toutes les 60 minutes (réglé sur 0 pour aucune limite) |
| `SECURITY_DELAY_AFTER` | Non | `0` | Contrôle les premières X requêtes d'une adresse IP toutes les 20 minutes qui ne sont pas soumises à des limites de vitesse, et après X requêtes, le délai augmentera |
| `SECURITY_BLACKLIST_LOG_FILE_PATH` | Non | `logs/blacklist-ip.log` | Paramètre de chemin. Enregistre la liste des adresses IP qui ont déclenché la limite après que `SECURITY_RATE_LIMIT` soit activé |
| `BING_MAP_API_KEY` | Non | `""` | Clé API pour Bing Maps, utilisée pour afficher l'emplacement de l'adresse IP sur une carte |
| `ALLOWED_DOMAINS` | Non | `""` | Domaines autorisés pour l'accès, séparés par des virgules, utilisés pour empêcher une utilisation abusive de l'API backend |
| `IPCHECKING_API_KEY` | Non | `""` | Clé API pour IPCheck.ing, utilisée pour obtenir des informations de géolocalisation précises sur l'adresse IP |
Expand All @@ -109,6 +113,8 @@ Vous pouvez utiliser le programme sans ajouter de variables d'environnement, mai
| `VITE_RECAPTCHA_SITE_KEY` | Non | `""` | Clé de site reCAPTCHA de Google, utilisée pour afficher la vérification reCAPTCHA sur le frontend |
| `RECAPTCHA_SECRET_KEY` | Non | `""` | Clé secrète reCAPTCHA de Google, utilisée pour vérifier la vérification reCAPTCHA sur le backend |

*Les variables d'environnement commençant par `SECURITY_` ne sont valides que lors du déploiement à l'aide de npm ou de Docker.*

### Utilisation des variables d'environnement dans un environnement Node

Créez les variables d'environnement :
Expand All @@ -120,7 +126,8 @@ cp .env.example .env
Modifiez le fichier `.env`, et par exemple, ajoutez ce qui suit :

```bash
PORT=18966
BACKEND_PORT=18966
FRONTEND_PORT=11966
BING_MAP_API_KEY="YOUR_KEY_HERE"
ALLOWED_DOMAINS="example.com"
IPCHECKING_API="YOUR_KEY_HERE"
Expand Down
11 changes: 9 additions & 2 deletions README_ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,11 @@ docker run -d -p 18966:18966 --name myip --restart always jason5ng32/myip:latest

| 变量名 | 是否必须 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `PORT` || `18966` | 程序运行的端口 |
| `BACKEND_PORT` || `18966` | 程序后端部分的运行端口 |
| `FRONTEND_PORT` || `11966` | 程序前端部分的运行端口 |
| `SECURITY_RATE_LIMIT` || `0` | 控制每 60 分钟一个 IP 可以对后端服务器请求的次数(设置为 0 则为不限制) |
| `SECURITY_DELAY_AFTER` || `0` | 控制每 20 分钟一个 IP 的前 X 次请求不受速度限制,超过 X 次后会逐次增加延迟 |
| `SECURITY_BLACKLIST_LOG_FILE_PATH` || `logs/blacklist-ip.log` | 路径设置。记录由 SECURITY_RATE_LIMIT 开启后,触发限制的 IP 列表 |
| `BING_MAP_API_KEY` || `""` | Bing 地图的 API Key,用于展示 IP 所在地的地图 |
| `ALLOWED_DOMAINS` || `""` | 允许访问的域名,用逗号分隔,用于防止后端 API 被滥用 |
| `IPCHECKING_API_KEY` || `""` | IPCheck.ing 的 API Key,用于获取精准的 IP 归属地信息 |
Expand All @@ -111,6 +115,8 @@ docker run -d -p 18966:18966 --name myip --restart always jason5ng32/myip:latest
| `VITE_RECAPTCHA_SITE_KEY` || `""` | Google reCAPTCHA 的 Site Key,用于在前端显示 reCAPTCHA 验证 |
| `RECAPTCHA_SECRET_KEY` || `""` | Google reCAPTCHA 的 Secret Key,用于在后端验证 reCAPTCHA 验证 |

*`SECURITY_` 开头的环境变量仅在使用 npm 或 Docker 部署时有效。*

### 在 Node 环境里使用环境变量

创建环境变量:
Expand All @@ -122,7 +128,8 @@ cp .env.example .env
修改 `.env` 里的内容,比如:

```bash
PORT=18966
BACKEND_PORT=18966
FRONTEND_PORT=11966
BING_MAP_API_KEY="YOUR_KEY_HERE"
ALLOWED_DOMAINS="example.com"
IPCHECKING_API="YOUR_KEY_HERE"
Expand Down
42 changes: 30 additions & 12 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ import { slowDown } from 'express-slow-down'
dotenv.config();

const app = express();
const port = process.env.PORT || 11966;
const blackListIPLogFilePath = process.env.BLACKLIST_LOG_FILE_PATH || '';
const rateLimitSet = process.env.RATE_LIMIT || '60';
const deleyAfter = process.env.DELAY_AFTER || '60';
const backEndPort = process.env.BACKEND_PORT || 11966;
const blackListIPLogFilePath = process.env.SECURITY_BLACKLIST_LOG_FILE_PATH || 'logs/blacklist-ip.log';
const rateLimitSet = process.env.SECURITY_RATE_LIMIT || '0';
const speedLimitSet = process.env.SECURITY_DELAY_AFTER || '0';

app.set('trust proxy', 1);

Expand All @@ -42,6 +42,14 @@ function formatDate(timestamp) {
function logLimitedIP(ip) {
const logPath = path.join(__dirname, blackListIPLogFilePath);

// 如果 logs 目录不存在,则创建
const logDir = path.dirname(logPath);
if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir, { recursive: true });
console.log('Created log directory:', logDir);
}

// 读取日志文件,更新 IP 计数,如果文件不存在则创建新的日志文件
fs.readFile(logPath, 'utf8', (err, data) => {
if (err && err.code !== 'ENOENT') {
console.error('Error reading the log file:', err);
Expand All @@ -60,6 +68,7 @@ function logLimitedIP(ip) {
if (currentIp === ip) {
newCount = parseInt(count, 10) + 1;
logExists = true;
console.log(`IP ${ip} has been limited ${newCount} times`);
return `${ip},${newCount},${timestamp}`; // Update count but keep the original timestamp
}
return line;
Expand All @@ -69,6 +78,7 @@ function logLimitedIP(ip) {
if (!logExists) {
const newLine = `${ip},${newCount},${formatDate(now)}`;
updatedData += (updatedData ? '\n' : '') + newLine;
console.log(`IP ${ip} has been limited for the first time`);
}

fs.writeFile(logPath, updatedData, 'utf8', err => {
Expand All @@ -79,7 +89,7 @@ function logLimitedIP(ip) {
});
}

const apiLimiter = rateLimit({
const rateLimiter = rateLimit({
windowMs: 20 * 60 * 1000,
max: parseInt(rateLimitSet, 10),
message: 'Too Many Requests',
Expand All @@ -94,12 +104,22 @@ const apiLimiter = rateLimit({

const speedLimiter = slowDown({
windowMs: 60 * 60 * 1000,
delayAfter: parseInt(deleyAfter, 10),
delayAfter: parseInt(speedLimitSet, 10),
delayMs: (hits) => hits * 400,
})

app.use('/api', apiLimiter);
app.use('/api', speedLimiter);
// 如果 rateLimitSet 为 0,则不启用限流
if (parseInt(rateLimitSet, 10) !== 0) {
app.use('/api', rateLimiter);
console.log('Rate limiter is enabled');
}

// 如果 deleyAfter 为 0,则不启用延迟
if (parseInt(speedLimitSet, 10) !== 0) {
app.use('/api', speedLimiter);
console.log('Speed limiter is enabled');
}


// APIs
app.get('/api/map', mapHandler);
Expand All @@ -110,8 +130,6 @@ app.get('/api/ipchecking', ipCheckingHandler);
app.get('/api/ipsb', ipsbHandler);
app.get('/api/cfradar', cfHander);
app.get('/api/recaptcha', recaptchaHandler);

// DNS Resolver
app.get('/api/dnsresolver', dnsResolver);

// 使用查询参数处理所有配置请求
Expand All @@ -124,6 +142,6 @@ app.use(express.static(path.join(__dirname, './dist')));


// 启动服务器
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}`);
app.listen(backEndPort, () => {
console.log(`Server running on http://localhost:${backEndPort}`);
});
10 changes: 5 additions & 5 deletions static-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@ import { createProxyMiddleware } from 'http-proxy-middleware';
dotenv.config();

const staticApp = express();
const staticPort = 18966;
const apiPort = process.env.PORT || 11966;
const backEndPort = process.env.BACKEND_PORT || 11966;
const frontEndPort = process.env.FRONTEND_PORT || 18966;

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// API 请求代理到后端服务
staticApp.use('/api', createProxyMiddleware({
target: `http://localhost:${apiPort}`,
target: `http://localhost:${backEndPort}`,
changeOrigin: true
}));

// 设置静态文件目录
staticApp.use(express.static(path.join(__dirname, './dist')));

// 启动静态文件服务
staticApp.listen(staticPort, () => {
console.log(`Static file server running on port http://localhost:${staticPort}`);
staticApp.listen(frontEndPort, () => {
console.log(`Static file server running on port http://localhost:${frontEndPort}`);
});
7 changes: 4 additions & 3 deletions vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { CodeInspectorPlugin } from 'code-inspector-plugin';

dotenv.config();

const apiPort = process.env.PORT || 11966;
const backEndPort = process.env.BACKEND_PORT || 11966;
const frontEndPort = process.env.FRONTEND_PORT || 18966;

export default defineConfig({
plugins: [
Expand Down Expand Up @@ -85,9 +86,9 @@ export default defineConfig({
},
server: {
host: '0.0.0.0',
port: 18966,
port: frontEndPort,
proxy: {
'/api': `http://localhost:${apiPort}`
'/api': `http://localhost:${backEndPort}`
}
}
})

0 comments on commit 8eac75f

Please sign in to comment.