jerkjs 2.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -6
- package/docs/EXTENSION_MANUAL.md +955 -0
- package/docs/FIREWALL_MANUAL.md +416 -0
- package/docs/HOOKS_REFERENCE_IMPROVED.md +596 -0
- package/docs/MANUAL_API_SDK.md +536 -0
- package/docs/MARIADB_TOKENS_IMPLEMENTATION.md +110 -0
- package/docs/MIDDLEWARE_MANUAL.md +518 -0
- package/docs/OAUTH2_GOOGLE_MANUAL.md +405 -0
- package/docs/frontend-and-sessions.md +6 -6
- package/examples/advanced/controllers/productController.js +64 -0
- package/examples/advanced/controllers/userController.js +85 -0
- package/examples/advanced/routes.json +51 -0
- package/examples/advanced_example.js +93 -0
- package/examples/basic/controllers/userController.js +85 -0
- package/examples/basic_example.js +72 -0
- package/examples/mvc_example/app.js +138 -0
- package/examples/mvc_example/views/home/index.html +26 -0
- package/examples/mvc_example/views/home/simple.html +3 -0
- package/examples/mvc_example/views/layout.html +23 -0
- package/examples/mvc_example/views/test.html +3 -0
- package/examples/mvc_example/views/user/invalid.html +6 -0
- package/examples/mvc_example/views/user/list.html +36 -0
- package/examples/mvc_example/views/user/notfound.html +6 -0
- package/examples/mvc_example/views/user/profile.html +11 -0
- package/examples/mvc_routes_example/app.js +34 -0
- package/examples/mvc_routes_example/controllers/mainController.js +27 -0
- package/examples/mvc_routes_example/controllers/productController.js +47 -0
- package/examples/mvc_routes_example/controllers/userController.js +76 -0
- package/examples/mvc_routes_example/routes.json +30 -0
- package/examples/mvc_routes_example/views/layout.html +31 -0
- package/examples/mvc_routes_example/views/main/index.html +11 -0
- package/examples/mvc_routes_example/views/product/catalog.html +24 -0
- package/examples/mvc_routes_example/views/user/invalid.html +6 -0
- package/examples/mvc_routes_example/views/user/list.html +40 -0
- package/examples/mvc_routes_example/views/user/notfound.html +6 -0
- package/examples/mvc_routes_example/views/user/profile.html +18 -0
- package/examples/mvc_welcome/README.md +34 -0
- package/examples/mvc_welcome/app.js +50 -0
- package/examples/mvc_welcome/controllers/welcomeController.js +41 -0
- package/examples/mvc_welcome/package.json +26 -0
- package/examples/mvc_welcome/views/home/welcome.html +82 -0
- package/examples/v2/README.md +72 -0
- package/examples/v2/app.js +74 -0
- package/examples/v2/app_fixed.js +74 -0
- package/examples/v2/controllers/authController.js +64 -0
- package/examples/v2/controllers/mainController.js +24 -0
- package/examples/v2/controllers/protectedController.js +12 -0
- package/examples/v2/controllers/userController.js +16 -0
- package/examples/v2/package.json +27 -0
- package/examples/v2/routes.json +30 -0
- package/examples/v2/test_api.sh +47 -0
- package/examples/v2/tokens_example.sqlite +0 -0
- package/examples/v2.1_firewall_demo/README.md +113 -0
- package/examples/v2.1_firewall_demo/app.js +182 -0
- package/examples/v2.1_firewall_demo/package.json +27 -0
- package/examples/v2.1_hooks_demo/README.md +85 -0
- package/examples/v2.1_hooks_demo/app.js +101 -0
- package/examples/v2.1_hooks_demo/controllers/hooksController.js +29 -0
- package/examples/v2.1_hooks_demo/controllers/mainController.js +18 -0
- package/examples/v2.1_hooks_demo/package.json +27 -0
- package/examples/v2.1_hooks_demo/routes.json +16 -0
- package/examples/v2.1_openapi_demo/README.md +82 -0
- package/examples/v2.1_openapi_demo/app.js +296 -0
- package/examples/v2.1_openapi_demo/package.json +26 -0
- package/examples/v2_cors/README.md +82 -0
- package/examples/v2_cors/app.js +108 -0
- package/examples/v2_cors/package.json +23 -0
- package/examples/v2_json_auth/README.md +83 -0
- package/examples/v2_json_auth/app.js +72 -0
- package/examples/v2_json_auth/controllers/authController.js +67 -0
- package/examples/v2_json_auth/controllers/mainController.js +16 -0
- package/examples/v2_json_auth/controllers/protectedController.js +12 -0
- package/examples/v2_json_auth/controllers/tokenController.js +28 -0
- package/examples/v2_json_auth/controllers/userController.js +15 -0
- package/examples/v2_json_auth/package.json +26 -0
- package/examples/v2_json_auth/routes.json +37 -0
- package/examples/v2_json_auth/tokens.json +20 -0
- package/examples/v2_mariadb_auth/README.md +94 -0
- package/examples/v2_mariadb_auth/app.js +81 -0
- package/examples/v2_mariadb_auth/controllers/authController.js +95 -0
- package/examples/v2_mariadb_auth/controllers/mainController.js +31 -0
- package/examples/v2_mariadb_auth/controllers/protectedController.js +12 -0
- package/examples/v2_mariadb_auth/controllers/userController.js +17 -0
- package/examples/v2_mariadb_auth/package.json +27 -0
- package/examples/v2_mariadb_auth/routes.json +37 -0
- package/examples/v2_no_auth/README.md +75 -0
- package/examples/v2_no_auth/app.js +72 -0
- package/examples/v2_no_auth/controllers/healthController.js +14 -0
- package/examples/v2_no_auth/controllers/mainController.js +19 -0
- package/examples/v2_no_auth/controllers/productController.js +31 -0
- package/examples/v2_no_auth/controllers/publicController.js +16 -0
- package/examples/v2_no_auth/package.json +22 -0
- package/examples/v2_no_auth/routes.json +37 -0
- package/examples/v2_oauth/README.md +70 -0
- package/examples/v2_oauth/app.js +90 -0
- package/examples/v2_oauth/controllers/mainController.js +45 -0
- package/examples/v2_oauth/controllers/oauthController.js +247 -0
- package/examples/v2_oauth/controllers/protectedController.js +13 -0
- package/examples/v2_oauth/controllers/userController.js +17 -0
- package/examples/v2_oauth/package.json +26 -0
- package/examples/v2_oauth/routes.json +44 -0
- package/examples/v2_openapi/README.md +77 -0
- package/examples/v2_openapi/app.js +222 -0
- package/examples/v2_openapi/controllers/authController.js +52 -0
- package/examples/v2_openapi/controllers/mainController.js +26 -0
- package/examples/v2_openapi/controllers/productController.js +17 -0
- package/examples/v2_openapi/controllers/userController.js +27 -0
- package/examples/v2_openapi/package.json +26 -0
- package/examples/v2_openapi/routes.json +37 -0
- package/index.js +11 -3
- package/lib/core/handler.js +1 -1
- package/lib/core/hooks.js +1 -1
- package/lib/core/router.js +1 -1
- package/lib/core/server.js +1 -1
- package/lib/loader/controllerLoader.js +1 -1
- package/lib/loader/routeLoader.js +1 -1
- package/lib/middleware/auditLogger.js +1 -1
- package/lib/middleware/authenticator.js +1 -1
- package/lib/middleware/compressor.js +1 -1
- package/lib/middleware/cors.js +1 -1
- package/lib/middleware/firewall.js +1 -1
- package/lib/middleware/rateLimiter.js +1 -1
- package/lib/middleware/session.js +1 -1
- package/lib/middleware/validator.js +1 -1
- package/lib/mvc/controllerBase.js +207 -0
- package/lib/mvc/viewEngine.js +752 -0
- package/lib/utils/configParser.js +1 -1
- package/lib/utils/logger.js +1 -1
- package/lib/utils/openapiGenerator.js +1 -1
- package/lib/utils/tokenManager.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const {
|
|
2
|
+
APIServer,
|
|
3
|
+
Authenticator,
|
|
4
|
+
RouteLoader,
|
|
5
|
+
Logger,
|
|
6
|
+
SQLiteTokenAdapter
|
|
7
|
+
} = require('../../index.js');
|
|
8
|
+
|
|
9
|
+
async function startServer() {
|
|
10
|
+
// Crear instancia del servidor
|
|
11
|
+
const server = new APIServer({
|
|
12
|
+
port: 8088,
|
|
13
|
+
host: 'localhost'
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// Crear instancia del logger
|
|
17
|
+
const logger = new Logger({ level: 'info' });
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
// Crear instancia del adaptador de tokens SQLite
|
|
21
|
+
const tokenAdapter = new SQLiteTokenAdapter({
|
|
22
|
+
dbPath: './tokens_example.sqlite',
|
|
23
|
+
tableName: 'example_tokens'
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Inicializar el adaptador de tokens
|
|
27
|
+
await tokenAdapter.initialize();
|
|
28
|
+
logger.info('SQLite Token Adapter inicializado correctamente');
|
|
29
|
+
|
|
30
|
+
// Crear instancia del autenticador
|
|
31
|
+
const authenticator = new Authenticator({ logger });
|
|
32
|
+
|
|
33
|
+
// Registrar estrategia de autenticación JWT que utiliza el adaptador SQLite
|
|
34
|
+
authenticator.use('jwt-sqlite', async (req, options = {}) => {
|
|
35
|
+
const authHeader = req.headers.authorization;
|
|
36
|
+
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
|
|
37
|
+
|
|
38
|
+
if (!token) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Validar el token contra la base de datos SQLite
|
|
43
|
+
const tokenRecord = await tokenAdapter.validateToken(token);
|
|
44
|
+
|
|
45
|
+
if (tokenRecord) {
|
|
46
|
+
// Agregar información del usuario a la solicitud
|
|
47
|
+
req.user = { userId: tokenRecord.user_id, tokenType: tokenRecord.token_type };
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return false;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Agregar el autenticador al servidor para que pueda ser usado por el RouteLoader
|
|
55
|
+
server.authenticator = authenticator;
|
|
56
|
+
|
|
57
|
+
// Cargar rutas desde archivo JSON
|
|
58
|
+
const routeLoader = new RouteLoader();
|
|
59
|
+
await routeLoader.loadRoutes(server, './routes.json');
|
|
60
|
+
|
|
61
|
+
// Iniciar el servidor
|
|
62
|
+
server.start();
|
|
63
|
+
|
|
64
|
+
logger.info('Servidor iniciado en http://localhost:8088');
|
|
65
|
+
} catch (error) {
|
|
66
|
+
logger.error('Error iniciando el servidor:', error.message);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Iniciar el servidor
|
|
72
|
+
startServer();
|
|
73
|
+
|
|
74
|
+
module.exports = { startServer };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
const jwt = require('jsonwebtoken');
|
|
2
|
+
const { SQLiteTokenAdapter } = require('../../../index.js');
|
|
3
|
+
|
|
4
|
+
// Adaptador de tokens para este controlador
|
|
5
|
+
const tokenAdapter = new SQLiteTokenAdapter({
|
|
6
|
+
dbPath: './tokens_example.sqlite',
|
|
7
|
+
tableName: 'example_tokens'
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
// Asegurarse de que el adaptador esté inicializado
|
|
11
|
+
tokenAdapter.initialize().catch(console.error);
|
|
12
|
+
|
|
13
|
+
const authController = {
|
|
14
|
+
login: async (req, res) => {
|
|
15
|
+
try {
|
|
16
|
+
const { username, password } = req.body;
|
|
17
|
+
|
|
18
|
+
// Validación simple de credenciales (esto debería ser más robusto en producción)
|
|
19
|
+
if (!username || !password) {
|
|
20
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
21
|
+
res.end(JSON.stringify({ error: 'Nombre de usuario y contraseña requeridos' }));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Simulación de autenticación (en una aplicación real, esto verificaría contra una base de datos)
|
|
26
|
+
if (username === 'admin' && password === 'password') {
|
|
27
|
+
// Generar un token JWT
|
|
28
|
+
const payload = {
|
|
29
|
+
userId: 1,
|
|
30
|
+
username: username,
|
|
31
|
+
role: 'admin'
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// Secret para firmar el token (en producción, debería estar en variables de entorno)
|
|
35
|
+
const secret = 'super-secret-key-for-example';
|
|
36
|
+
const token = jwt.sign(payload, secret, { expiresIn: '1h' });
|
|
37
|
+
|
|
38
|
+
// Guardar el token en la base de datos SQLite
|
|
39
|
+
await tokenAdapter.saveToken(
|
|
40
|
+
token,
|
|
41
|
+
{ userId: 1 },
|
|
42
|
+
'access',
|
|
43
|
+
new Date(Date.now() + 60 * 60 * 1000) // 1 hora
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
47
|
+
res.end(JSON.stringify({
|
|
48
|
+
message: 'Inicio de sesión exitoso',
|
|
49
|
+
token: token,
|
|
50
|
+
user: payload
|
|
51
|
+
}));
|
|
52
|
+
} else {
|
|
53
|
+
res.writeHead(401, { 'Content-Type': 'application/json' });
|
|
54
|
+
res.end(JSON.stringify({ error: 'Credenciales inválidas' }));
|
|
55
|
+
}
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error('Error en login:', error);
|
|
58
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
59
|
+
res.end(JSON.stringify({ error: 'Error interno del servidor' }));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
module.exports = authController;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const jwt = require('jsonwebtoken');
|
|
2
|
+
const { SQLiteTokenAdapter } = require('../../../index.js');
|
|
3
|
+
|
|
4
|
+
// Adaptador de tokens para este controlador
|
|
5
|
+
const tokenAdapter = new SQLiteTokenAdapter({
|
|
6
|
+
dbPath: './tokens_example.sqlite',
|
|
7
|
+
tableName: 'example_tokens'
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const mainController = {
|
|
11
|
+
home: (req, res) => {
|
|
12
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
13
|
+
res.end(JSON.stringify({
|
|
14
|
+
message: 'Bienvenido a la API de ejemplo con autenticación SQLite',
|
|
15
|
+
endpoints: {
|
|
16
|
+
'POST /login': 'Iniciar sesión y obtener token',
|
|
17
|
+
'GET /protected': 'Contenido protegido (requiere token)',
|
|
18
|
+
'GET /profile': 'Perfil de usuario (requiere token)'
|
|
19
|
+
}
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
module.exports = mainController;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const protectedController = {
|
|
2
|
+
getProtectedData: (req, res) => {
|
|
3
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
4
|
+
res.end(JSON.stringify({
|
|
5
|
+
message: 'Datos protegidos accesados exitosamente',
|
|
6
|
+
user: req.user,
|
|
7
|
+
timestamp: new Date().toISOString()
|
|
8
|
+
}));
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
module.exports = protectedController;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const userController = {
|
|
2
|
+
getProfile: (req, res) => {
|
|
3
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
4
|
+
res.end(JSON.stringify({
|
|
5
|
+
profile: {
|
|
6
|
+
id: req.user.userId,
|
|
7
|
+
username: req.user.username || 'Usuario',
|
|
8
|
+
role: req.user.role || 'guest',
|
|
9
|
+
tokenType: req.user.tokenType
|
|
10
|
+
},
|
|
11
|
+
message: 'Perfil de usuario obtenido exitosamente'
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
module.exports = userController;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jerk-example-v2",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Ejemplo de API con autenticación SQLite usando el Framework JERK",
|
|
5
|
+
"main": "app.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node app.js",
|
|
8
|
+
"dev": "nodemon app.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"api",
|
|
12
|
+
"sdk",
|
|
13
|
+
"authentication",
|
|
14
|
+
"sqlite",
|
|
15
|
+
"jwt",
|
|
16
|
+
"framework"
|
|
17
|
+
],
|
|
18
|
+
"author": "JERK Framework",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"jsonwebtoken": "^9.0.0",
|
|
22
|
+
"sqlite3": "^5.1.6"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"nodemon": "^3.0.0"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"path": "/",
|
|
4
|
+
"method": "GET",
|
|
5
|
+
"controller": "./controllers/mainController.js",
|
|
6
|
+
"handler": "home",
|
|
7
|
+
"auth": "none"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
"path": "/login",
|
|
11
|
+
"method": "POST",
|
|
12
|
+
"controller": "./controllers/authController.js",
|
|
13
|
+
"handler": "login",
|
|
14
|
+
"auth": "none"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"path": "/protected",
|
|
18
|
+
"method": "GET",
|
|
19
|
+
"controller": "./controllers/protectedController.js",
|
|
20
|
+
"handler": "getProtectedData",
|
|
21
|
+
"auth": "jwt-sqlite"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"path": "/profile",
|
|
25
|
+
"method": "GET",
|
|
26
|
+
"controller": "./controllers/userController.js",
|
|
27
|
+
"handler": "getProfile",
|
|
28
|
+
"auth": "jwt-sqlite"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
echo "Iniciando prueba de la API con autenticación SQLite..."
|
|
4
|
+
|
|
5
|
+
# Iniciar el servidor en segundo plano
|
|
6
|
+
node app.js &
|
|
7
|
+
SERVER_PID=$!
|
|
8
|
+
|
|
9
|
+
# Esperar a que el servidor inicie
|
|
10
|
+
sleep 3
|
|
11
|
+
|
|
12
|
+
echo "Probando endpoints..."
|
|
13
|
+
|
|
14
|
+
# Probar endpoint público
|
|
15
|
+
echo "1. Probando endpoint público (/)"
|
|
16
|
+
curl -s -w "\n%{http_code}\n" -X GET http://localhost:8088/
|
|
17
|
+
|
|
18
|
+
# Probar login
|
|
19
|
+
echo -e "\n2. Probando login..."
|
|
20
|
+
TOKEN=$(curl -s -X POST http://localhost:8088/login \
|
|
21
|
+
-H "Content-Type: application/json" \
|
|
22
|
+
-d '{"username": "admin", "password": "password"}' | jq -r '.token')
|
|
23
|
+
|
|
24
|
+
if [ "$TOKEN" != "null" ] && [ -n "$TOKEN" ]; then
|
|
25
|
+
echo "Login exitoso, token obtenido: ${TOKEN:0:20}..."
|
|
26
|
+
|
|
27
|
+
# Probar endpoint protegido con token
|
|
28
|
+
echo -e "\n3. Probando endpoint protegido (/protected) con token..."
|
|
29
|
+
curl -s -w "\n%{http_code}\n" -X GET http://localhost:8088/protected \
|
|
30
|
+
-H "Authorization: Bearer $TOKEN"
|
|
31
|
+
|
|
32
|
+
# Probar endpoint de perfil con token
|
|
33
|
+
echo -e "\n4. Probando endpoint de perfil (/profile) con token..."
|
|
34
|
+
curl -s -w "\n%{http_code}\n" -X GET http://localhost:8088/profile \
|
|
35
|
+
-H "Authorization: Bearer $TOKEN"
|
|
36
|
+
else
|
|
37
|
+
echo "Error: No se pudo obtener el token de login"
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Probar endpoint protegido sin token (debería fallar)
|
|
41
|
+
echo -e "\n5. Probando endpoint protegido (/protected) sin token (debería fallar)..."
|
|
42
|
+
curl -s -w "\n%{http_code}\n" -X GET http://localhost:8088/protected
|
|
43
|
+
|
|
44
|
+
echo -e "\nPrueba completada."
|
|
45
|
+
|
|
46
|
+
# Detener el servidor
|
|
47
|
+
kill $SERVER_PID
|
|
Binary file
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Ejemplo de API con Funcionalidades de Firewall Avanzado (v2.1.0)
|
|
2
|
+
|
|
3
|
+
Este ejemplo demuestra las funcionalidades de firewall avanzado implementadas en la versión 2.1.0 del Framework JERK, incluyendo el sistema de hooks para eventos de seguridad.
|
|
4
|
+
|
|
5
|
+
## Características del Firewall
|
|
6
|
+
|
|
7
|
+
- **Detección de Patrones de Ataque**: Identificación de SQL Injection, XSS, Path Traversal
|
|
8
|
+
- **Bloqueo de IPs**: Sistema de bloqueo tras múltiples intentos fallidos
|
|
9
|
+
- **Listas Blancas y Negras**: IPs permitidas o prohibidas permanentemente
|
|
10
|
+
- **Reglas Personalizadas**: Posibilidad de definir reglas personalizadas de firewall
|
|
11
|
+
- **Sistema de Hooks**: Integración con el sistema de hooks para eventos de seguridad
|
|
12
|
+
- **Monitoreo de Solicitudes Sospechosas**: Registro y seguimiento de actividades sospechosas
|
|
13
|
+
|
|
14
|
+
## Configuración
|
|
15
|
+
|
|
16
|
+
No se requieren dependencias adicionales más allá del Framework JERK.
|
|
17
|
+
|
|
18
|
+
## Uso
|
|
19
|
+
|
|
20
|
+
1. Inicia el servidor:
|
|
21
|
+
```bash
|
|
22
|
+
node app.js
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
2. El servidor escuchará en `http://localhost:8097`
|
|
26
|
+
|
|
27
|
+
## Endpoints de Prueba
|
|
28
|
+
|
|
29
|
+
- `GET /` - Página de inicio con información del firewall
|
|
30
|
+
- `GET /test-attacks` - Prueba de detección de ataques
|
|
31
|
+
- `GET /test-sql-injection` - Prueba de detección de SQL injection (será bloqueada)
|
|
32
|
+
- `GET /test-xss` - Prueba de detección de XSS (será bloqueada)
|
|
33
|
+
- `GET /test-path-traversal` - Prueba de detección de path traversal (será bloqueada)
|
|
34
|
+
- `GET /firewall-status` - Estado actual del firewall
|
|
35
|
+
|
|
36
|
+
## Pruebas de Seguridad
|
|
37
|
+
|
|
38
|
+
### Prueba de SQL Injection
|
|
39
|
+
```bash
|
|
40
|
+
curl -X GET "http://localhost:8097/test-sql-injection?id=1'%20OR%20'1'='1"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Prueba de XSS
|
|
44
|
+
```bash
|
|
45
|
+
curl -X GET "http://localhost:8097/test-xss?input=<script>alert('xss')</script>"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Prueba de Path Traversal
|
|
49
|
+
```bash
|
|
50
|
+
curl -X GET "http://localhost:8097/test-path-traversal?file=../../../etc/passwd"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Prueba de User Agent Sospechoso
|
|
54
|
+
```bash
|
|
55
|
+
curl -X GET http://localhost:8097/test-attacks -H "User-Agent: sqlmap/1.0"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Sistema de Hooks de Seguridad
|
|
59
|
+
|
|
60
|
+
El ejemplo demuestra cómo usar el sistema de hooks para eventos de seguridad:
|
|
61
|
+
|
|
62
|
+
- `firewall_rule_triggered` - Se dispara cuando se activa una regla de firewall
|
|
63
|
+
- `firewall_ip_blocked` - Se dispara cuando se bloquea una IP
|
|
64
|
+
- `firewall_security_event` - Se dispara para eventos generales de seguridad
|
|
65
|
+
|
|
66
|
+
## Configuración del Firewall
|
|
67
|
+
|
|
68
|
+
El firewall se puede configurar con las siguientes opciones:
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
const firewall = new Firewall({
|
|
72
|
+
maxAttempts: 5, // Número máximo de intentos antes de bloquear
|
|
73
|
+
blockDuration: 900000, // Duración del bloqueo en ms (15 minutos)
|
|
74
|
+
whitelist: ['127.0.0.1'], // IPs que no deben ser bloqueadas
|
|
75
|
+
blacklist: [], // IPs que siempre deben ser bloqueadas
|
|
76
|
+
rules: [ // Reglas personalizadas de firewall
|
|
77
|
+
{
|
|
78
|
+
name: 'large_payload',
|
|
79
|
+
condition: (req) => {
|
|
80
|
+
// Condición para activar la regla
|
|
81
|
+
},
|
|
82
|
+
action: 'block', // 'block' o 'monitor'
|
|
83
|
+
reason: 'Motivo del bloqueo'
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
logger: logger // Instancia de logger para eventos
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Estructura del proyecto
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
examples/v2.1_firewall_demo/
|
|
94
|
+
├── app.js # Punto de entrada de la aplicación con firewall
|
|
95
|
+
├── controllers/ # Controladores de las rutas
|
|
96
|
+
│ └── (controladores según sea necesario)
|
|
97
|
+
└── README.md
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Reglas de Firewall Integradas
|
|
101
|
+
|
|
102
|
+
1. **SQL Injection Detection**: Detecta patrones comunes de inyección SQL
|
|
103
|
+
2. **XSS Detection**: Detecta patrones comunes de Cross-Site Scripting
|
|
104
|
+
3. **Path Traversal**: Detecta intentos de navegación fuera del directorio permitido
|
|
105
|
+
4. **Large Payload**: Bloquea solicitudes con cuerpos excesivamente grandes
|
|
106
|
+
5. **Suspicious User Agents**: Detecta user agents asociados con herramientas de ataque
|
|
107
|
+
|
|
108
|
+
## Seguridad
|
|
109
|
+
|
|
110
|
+
- El firewall bloquea automáticamente solicitudes que contienen patrones de ataque conocidos
|
|
111
|
+
- Las IPs que generan múltiples violaciones son bloqueadas temporalmente
|
|
112
|
+
- Las reglas personalizadas permiten una protección adaptada a necesidades específicas
|
|
113
|
+
- El sistema de hooks permite una respuesta personalizada a eventos de seguridad
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ejemplo de API con funcionalidades de firewall avanzado (v2.1.0)
|
|
3
|
+
* Demostrando el uso del sistema de firewall con el sistema de hooks
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const {
|
|
7
|
+
APIServer,
|
|
8
|
+
Authenticator,
|
|
9
|
+
RateLimiter,
|
|
10
|
+
Logger,
|
|
11
|
+
HookSystem,
|
|
12
|
+
Firewall
|
|
13
|
+
} = require('../../index.js');
|
|
14
|
+
|
|
15
|
+
async function startServer() {
|
|
16
|
+
// Crear instancia del servidor
|
|
17
|
+
const server = new APIServer({
|
|
18
|
+
port: 8097,
|
|
19
|
+
host: 'localhost'
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Crear instancia del logger
|
|
23
|
+
const logger = new Logger({ level: 'info' });
|
|
24
|
+
|
|
25
|
+
// Crear instancia del sistema de hooks
|
|
26
|
+
const hooks = new HookSystem();
|
|
27
|
+
|
|
28
|
+
// Crear instancia del firewall
|
|
29
|
+
const firewall = new Firewall({
|
|
30
|
+
maxAttempts: 3,
|
|
31
|
+
blockDuration: 300000, // 5 minutos para pruebas
|
|
32
|
+
whitelist: ['127.0.0.1', '::1'], // IPs locales
|
|
33
|
+
blacklist: [], // Ninguna IP bloqueada por defecto
|
|
34
|
+
rules: [
|
|
35
|
+
{
|
|
36
|
+
name: 'large_payload',
|
|
37
|
+
condition: (req) => {
|
|
38
|
+
// Bloquear solicitudes con cuerpo muy grande
|
|
39
|
+
const contentLength = req.headers['content-length'];
|
|
40
|
+
return contentLength && parseInt(contentLength) > 1024 * 100; // 100KB
|
|
41
|
+
},
|
|
42
|
+
action: 'block',
|
|
43
|
+
reason: 'Solicitud con payload excesivamente grande'
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'suspicious_user_agent',
|
|
47
|
+
condition: (req) => {
|
|
48
|
+
const userAgent = req.headers['user-agent'] || '';
|
|
49
|
+
// Detectar user agents sospechosos
|
|
50
|
+
const suspiciousAgents = [
|
|
51
|
+
/sqlmap/i,
|
|
52
|
+
/nikto/i,
|
|
53
|
+
/nessus/i,
|
|
54
|
+
/nmap/i,
|
|
55
|
+
/dirbuster/i
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
return suspiciousAgents.some(agent => agent.test(userAgent));
|
|
59
|
+
},
|
|
60
|
+
action: 'block',
|
|
61
|
+
reason: 'User agent sospechoso detectado'
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
logger
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
// Registrar hooks para eventos de firewall
|
|
69
|
+
hooks.addAction('firewall_rule_triggered', (rule, clientIP, req) => {
|
|
70
|
+
logger.info(`[[FIREWALL-HOOK]] Regla activada: ${rule.name} para IP: ${clientIP}`);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
hooks.addAction('firewall_ip_blocked', (ip, reason) => {
|
|
74
|
+
logger.warn(`[[FIREWALL-HOOK]] IP bloqueada: ${ip} por razón: ${reason}`);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
hooks.addAction('firewall_security_event', (event, details) => {
|
|
78
|
+
logger.info(`[[FIREWALL-HOOK]] Evento de seguridad: ${event}`, details);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Aplicar middleware de firewall al servidor
|
|
82
|
+
server.use(firewall.middleware());
|
|
83
|
+
|
|
84
|
+
// Ruta pública
|
|
85
|
+
server.addRoute('GET', '/', (req, res) => {
|
|
86
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
87
|
+
res.end(JSON.stringify({
|
|
88
|
+
message: 'API con funcionalidades de firewall avanzado (v2.1.0)',
|
|
89
|
+
features: [
|
|
90
|
+
'Detección de patrones de ataque (SQL Injection, XSS, Path Traversal)',
|
|
91
|
+
'Bloqueo de IPs tras intentos fallidos',
|
|
92
|
+
'Listas blancas y negras de IPs',
|
|
93
|
+
'Reglas personalizadas de firewall',
|
|
94
|
+
'Sistema de hooks para eventos de seguridad',
|
|
95
|
+
'Monitoreo de solicitudes sospechosas'
|
|
96
|
+
],
|
|
97
|
+
firewallStatus: firewall.getStatus(),
|
|
98
|
+
timestamp: new Date().toISOString()
|
|
99
|
+
}));
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Ruta para probar diferentes tipos de ataques
|
|
103
|
+
server.addRoute('GET', '/test-attacks', (req, res) => {
|
|
104
|
+
// Disparar un hook personalizado para demostrar el sistema
|
|
105
|
+
hooks.doAction('firewall_security_event', 'attack_test_requested', {
|
|
106
|
+
clientIP: firewall.getClientIP(req),
|
|
107
|
+
userAgent: req.headers['user-agent'],
|
|
108
|
+
timestamp: new Date().toISOString()
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
112
|
+
res.end(JSON.stringify({
|
|
113
|
+
message: 'Prueba de ataques completada',
|
|
114
|
+
clientIP: firewall.getClientIP(req),
|
|
115
|
+
securityLevel: 'monitored',
|
|
116
|
+
timestamp: new Date().toISOString()
|
|
117
|
+
}));
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Ruta para probar SQL injection (esta debería ser bloqueada)
|
|
121
|
+
server.addRoute('GET', '/test-sql-injection', (req, res) => {
|
|
122
|
+
// Esta ruta no debería ser accesible si se detecta SQL injection en la URL
|
|
123
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
124
|
+
res.end(JSON.stringify({
|
|
125
|
+
message: '¡Esto no debería verse si se detectó SQL injection!',
|
|
126
|
+
status: 'compromised',
|
|
127
|
+
timestamp: new Date().toISOString()
|
|
128
|
+
}));
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Ruta para probar XSS (esta debería ser bloqueada)
|
|
132
|
+
server.addRoute('GET', '/test-xss', (req, res) => {
|
|
133
|
+
// Esta ruta no debería ser accesible si se detecta XSS en la URL
|
|
134
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
135
|
+
res.end(JSON.stringify({
|
|
136
|
+
message: '¡Esto no debería verse si se detectó XSS!',
|
|
137
|
+
status: 'compromised',
|
|
138
|
+
timestamp: new Date().toISOString()
|
|
139
|
+
}));
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Ruta para probar path traversal (esta debería ser bloqueada)
|
|
143
|
+
server.addRoute('GET', '/test-path-traversal', (req, res) => {
|
|
144
|
+
// Esta ruta no debería ser accesible si se detecta path traversal
|
|
145
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
146
|
+
res.end(JSON.stringify({
|
|
147
|
+
message: '¡Esto no debería verse si se detectó path traversal!',
|
|
148
|
+
status: 'compromised',
|
|
149
|
+
timestamp: new Date().toISOString()
|
|
150
|
+
}));
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Ruta para verificar estado del firewall
|
|
154
|
+
server.addRoute('GET', '/firewall-status', (req, res) => {
|
|
155
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
156
|
+
res.end(JSON.stringify({
|
|
157
|
+
firewall: firewall.getStatus(),
|
|
158
|
+
timestamp: new Date().toISOString()
|
|
159
|
+
}));
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// Iniciar el servidor
|
|
163
|
+
server.start();
|
|
164
|
+
|
|
165
|
+
logger.info('Servidor con firewall avanzado iniciado en http://localhost:8097');
|
|
166
|
+
logger.info('Endpoints disponibles:');
|
|
167
|
+
logger.info('- GET / - Página de inicio con información de firewall');
|
|
168
|
+
logger.info('- GET /test-attacks - Prueba de detección de ataques');
|
|
169
|
+
logger.info('- GET /test-sql-injection - Prueba de detección de SQL injection (será bloqueada)');
|
|
170
|
+
logger.info('- GET /test-xss - Prueba de detección de XSS (será bloqueada)');
|
|
171
|
+
logger.info('- GET /test-path-traversal - Prueba de detección de path traversal (será bloqueada)');
|
|
172
|
+
logger.info('- GET /firewall-status - Estado actual del firewall');
|
|
173
|
+
} catch (error) {
|
|
174
|
+
logger.error('Error iniciando el servidor:', error.message);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Iniciar el servidor
|
|
180
|
+
startServer();
|
|
181
|
+
|
|
182
|
+
module.exports = { startServer };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "jerk-firewall-demo",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Ejemplo de API con funcionalidades de firewall avanzado usando el Framework JERK",
|
|
5
|
+
"main": "app.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node app.js",
|
|
8
|
+
"dev": "nodemon app.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"api",
|
|
12
|
+
"sdk",
|
|
13
|
+
"firewall",
|
|
14
|
+
"security",
|
|
15
|
+
"advanced",
|
|
16
|
+
"protection",
|
|
17
|
+
"framework"
|
|
18
|
+
],
|
|
19
|
+
"author": "JERK Framework",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"jsonwebtoken": "^9.0.0"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"nodemon": "^3.0.0"
|
|
26
|
+
}
|
|
27
|
+
}
|