Version 18.40

This commit is contained in:
Antonio Cañas Vargas 2019-02-13 15:06:02 +01:00
parent c62e46d617
commit 3c4dc97d5b
6 changed files with 136 additions and 25 deletions

View File

@ -522,9 +522,19 @@ CREATE TABLE IF NOT EXISTS files (
INDEX(ZoneUsrCod),
INDEX(PublisherUsrCod));
--
-- Table firewall: stores the most recent IPs in order to mitigate denial of service attacks
-- Table firewall_banned: stores the banned IPs in order to mitigate denial of service attacks
--
CREATE TABLE IF NOT EXISTS firewall (
CREATE TABLE IF NOT EXISTS firewall_banned (
IP CHAR(15) NOT NULL,
BanTime DATETIME NOT NULL,
UnbanTime DATETIME NOT NULL,
INDEX(IP,UnbanTime),
INDEX(BanTime),
INDEX(UnbanTime));
--
-- Table firewall_log: stores the most recent IPs in order to mitigate denial of service attacks
--
CREATE TABLE IF NOT EXISTS firewall_log (
ClickTime DATETIME NOT NULL,
IP CHAR(15) NOT NULL,
INDEX(ClickTime),

View File

@ -335,9 +335,6 @@ Buenos d
// TODO: Que la opción por defecto en "Permitir que los profesores vean este examen" la configuren los profesores en cada asignatura"
// TODO: URGENTE: Bego del Pino, una columna en resultados de test que indique los descriptores de ese examen
// TODO: Pedro Villar Castro:
// Al asignar un TFG a alumnos, no escribir el DNI del alumno, sino escogerlo de una lista de entre los alumnos inscritos en la asignatura.
// TODO: Cuando se muestre un usuario duplicado, que SWAD calcule automáticamente sus cifras no calculadas sin tener que pulsar en Calcular
// TODO: Miguel Damas Hermoso sugiere poder editar texto enriquecido (Markdown) en las preguntas de tipo test
@ -361,6 +358,15 @@ Buenos d
// TODO: Tabla de asistencia con símbolos tip ok como entidades HTML
// TODO: Pedro Villar Castro:
// Al asignar un TFG a alumnos, no escribir el DNI del alumno, sino escogerlo de una lista de entre los alumnos inscritos en la asignatura.
// TODO: Pedro Villar Castro:
// Bloquear individualmente la edición con una casilla de configuración para cada TFG, sólo el profesor de la asignatura (Perico) podría bloquear/desbloquear
// Que haya una opción general que los bloquee todos y que los desbloquee todos
// Para bloquear/desbloquear se usará un icono candado
// Para preasignado/no preasignado usar otro icono (usuario/usuario tachado, por ej.)
/*****************************************************************************/
/****************************** Public constants *****************************/
/*****************************************************************************/
@ -380,11 +386,16 @@ En OpenSWAD:
ps2pdf source.ps destination.pdf
*/
#define Log_PLATFORM_VERSION "SWAD 18.39 (2019-02-13)"
#define Log_PLATFORM_VERSION "SWAD 18.40 (2019-02-13)"
#define CSS_FILE "swad18.33.css"
#define JS_FILE "swad18.32.1.js"
/*
Version 18.39: Feb 13, 2019 New module swad_firewall to mitigate mitigate DoS attacks. (239101 lines)
Version 18.40: Feb 13, 2019 New table for banned IPs to mitigate DoS attacks. (239198 lines)
2 changes necessary in database:
RENAME TABLE firewall TO firewall_log;
CREATE TABLE IF NOT EXISTS firewall_banned (IP CHAR(15) NOT NULL,BanTime DATETIME NOT NULL,UnbanTime DATETIME NOT NULL,INDEX(IP,UnbanTime),INDEX(BanTime),INDEX(UnbanTime));
Version 18.39: Feb 13, 2019 New module swad_firewall to mitigate DoS attacks. (239101 lines)
1 change necessary in database:
CREATE TABLE IF NOT EXISTS firewall (ClickTime DATETIME NOT NULL,IP CHAR(15) NOT NULL,INDEX(ClickTime),INDEX(IP));

View File

@ -1149,9 +1149,29 @@ mysql> DESCRIBE files;
"INDEX(ZoneUsrCod),"
"INDEX(PublisherUsrCod))");
/***** Table firewall *****/
/***** Table firewall_banned *****/
/*
mysql> DESCRIBE firewall;
mysql> DESCRIBE firewall_banned;
+-----------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------+------+-----+---------+-------+
| IP | char(15) | NO | MUL | NULL | |
| BanTime | datetime | NO | MUL | NULL | |
| UnbanTime | datetime | NO | MUL | NULL | |
+-----------+----------+------+-----+---------+-------+
3 rows in set (0.00 sec)
*/
DB_CreateTable ("CREATE TABLE IF NOT EXISTS firewall_banned ("
"IP CHAR(15) NOT NULL," // Cns_MAX_BYTES_IP
"BanTime DATETIME NOT NULL,"
"UnbanTime DATETIME NOT NULL,"
"INDEX(IP,UnbanTime),"
"INDEX(BanTime),"
"INDEX(UnbanTime));");
/***** Table firewall_log *****/
/*
mysql> DESCRIBE firewall_log;
+-----------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+----------+------+-----+---------+-------+
@ -1160,7 +1180,7 @@ mysql> DESCRIBE firewall;
+-----------+----------+------+-----+---------+-------+
2 rows in set (0.00 sec)
*/
DB_CreateTable ("CREATE TABLE IF NOT EXISTS firewall ("
DB_CreateTable ("CREATE TABLE IF NOT EXISTS firewall_log ("
"ClickTime DATETIME NOT NULL,"
"IP CHAR(15) NOT NULL," // Cns_MAX_BYTES_IP
"INDEX(ClickTime),"

View File

@ -38,9 +38,14 @@ extern struct Globals Gbl;
/***************************** Private constants *****************************/
/*****************************************************************************/
/* The maximum number of clicks in the interval
should be large enough to prevent an IP from being banned
due to automatic refresh when the user is viewing the last clicks. */
#define Fw_CHECK_INTERVAL ((time_t)(10UL)) // Check clicks in the last 10 seconds
#define Fw_MAX_CLICKS_IN_INTERVAL 30 // Maximum of 30 clicks allowed in 10 seconds
#define Fw_TIME_BANNED ((time_t)(60UL*60UL)) // Ban IP for 1 hour
#define Fw_TIME_TO_DELETE_OLD_CLICKS Fw_CHECK_INTERVAL // Remove clicks older than these seconds
/*****************************************************************************/
@ -51,6 +56,8 @@ extern struct Globals Gbl;
/***************************** Internal prototypes ***************************/
/*****************************************************************************/
static void FW_BanIP (void);
/*****************************************************************************/
/************************** Log access into firewall *************************/
/*****************************************************************************/
@ -58,13 +65,67 @@ extern struct Globals Gbl;
void FW_LogAccess (void)
{
/***** Log access in firewall recent log *****/
DB_QueryINSERT ("can not log access into firewall",
"INSERT INTO firewall (ClickTime,IP) VALUES (NOW(),'%s')",
DB_QueryINSERT ("can not log access into firewall_log",
"INSERT INTO firewall_log"
" (ClickTime,IP)"
" VALUES"
" (NOW(),'%s')",
Gbl.IP);
}
/*****************************************************************************/
/************************** Log access into firewall *************************/
/********************** Remove old clicks from firewall **********************/
/*****************************************************************************/
void FW_PurgeFirewall (void)
{
/***** Remove old clicks *****/
DB_QueryDELETE ("can not purge firewall log",
"DELETE LOW_PRIORITY FROM firewall_log"
" WHERE ClickTime<FROM_UNIXTIME(UNIX_TIMESTAMP()-%lu)",
(unsigned long) Fw_TIME_TO_DELETE_OLD_CLICKS);
}
/*****************************************************************************/
/*************************** Check if IP is banned ***************************/
/*****************************************************************************/
void FW_CheckFirewallAndExitIfBanned (void)
{
unsigned long NumCurrentBans;
/***** Get number of current bans from database *****/
NumCurrentBans = DB_QueryCOUNT ("can not check firewall log",
"SELECT COUNT(*) FROM firewall_banned"
" WHERE IP='%s' AND UnbanTime>NOW()",
Gbl.IP);
/***** Exit with status 403 if banned *****/
/* RFC 6585 suggests "429 Too Many Requests", according to
https://stackoverflow.com/questions/7447283/proper-http-status-to-return-for-hacking-attempts
https://tools.ietf.org/html/rfc2616#section-10.4.4 */
if (NumCurrentBans)
{
/* Return status 403 Forbidden */
fprintf (stdout,"Content-Type: text/html; charset=windows-1252\n"
"Status: 403\r\n\r\n"
"<html>"
"<head>"
"<title>Forbidden</title>"
"</head>"
"<body>"
"<h1>You are banned temporarily</h1>"
"</body>"
"</html>\n");
/* Close database connection and exit */
DB_CloseDBConnection ();
exit (0);
}
}
/*****************************************************************************/
/**************** Check if too many connections from this IP *****************/
/*****************************************************************************/
void FW_CheckFirewallAndExitIfTooManyRequests (void)
@ -72,8 +133,8 @@ void FW_CheckFirewallAndExitIfTooManyRequests (void)
unsigned long NumClicks;
/***** Get number of clicks from database *****/
NumClicks = DB_QueryCOUNT ("can not check firewall",
"SELECT COUNT(*) FROM firewall"
NumClicks = DB_QueryCOUNT ("can not check firewall log",
"SELECT COUNT(*) FROM firewall_log"
" WHERE IP='%s'"
" AND ClickTime>FROM_UNIXTIME(UNIX_TIMESTAMP()-%lu)",
Gbl.IP,
@ -85,9 +146,12 @@ void FW_CheckFirewallAndExitIfTooManyRequests (void)
https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429 */
if (NumClicks > Fw_MAX_CLICKS_IN_INTERVAL)
{
/* Ban this IP */
FW_BanIP ();
/* Return status 429 Too Many Requests */
fprintf (stdout,"Content-Type: text/html; charset=windows-1252\n"
"Retry-After: 3600\n"
"Retry-After: %lu\n"
"Status: 429\r\n\r\n"
"<html>"
"<head>"
@ -96,7 +160,8 @@ void FW_CheckFirewallAndExitIfTooManyRequests (void)
"<body>"
"<h1>Please stop that</h1>"
"</body>"
"</html>\n");
"</html>\n",
(unsigned long) Fw_TIME_BANNED);
/* Close database connection and exit */
DB_CloseDBConnection ();
@ -105,14 +170,16 @@ void FW_CheckFirewallAndExitIfTooManyRequests (void)
}
/*****************************************************************************/
/********************** Remove old clicks from firewall **********************/
/********************************* Ban an IP *********************************/
/*****************************************************************************/
void FW_PurgeFirewall (void)
static void FW_BanIP (void)
{
/***** Remove old clicks *****/
DB_QueryDELETE ("can not purge firewall",
"DELETE LOW_PRIORITY FROM firewall"
" WHERE ClickTime<FROM_UNIXTIME(UNIX_TIMESTAMP()-%lu)",
Fw_TIME_TO_DELETE_OLD_CLICKS);
/***** Insert IP into table of banned IPs *****/
DB_QueryINSERT ("can not ban IP",
"INSERT INTO firewall_banned"
" (IP,BanTime,UnbanTime)"
" VALUES"
" ('%s',NOW(),FROM_UNIXTIME(UNIX_TIMESTAMP()+%lu))",
Gbl.IP,(unsigned long) Fw_TIME_BANNED);
}

View File

@ -36,7 +36,9 @@
/*****************************************************************************/
void FW_LogAccess (void);
void FW_CheckFirewallAndExitIfTooManyRequests (void);
void FW_PurgeFirewall (void);
void FW_CheckFirewallAndExitIfBanned (void);
void FW_CheckFirewallAndExitIfTooManyRequests (void);
#endif

View File

@ -112,6 +112,7 @@ int main (void)
Par_GetMainParameters ();
/***** Mitigate DoS attacks *****/
FW_CheckFirewallAndExitIfBanned ();
FW_LogAccess ();
FW_CheckFirewallAndExitIfTooManyRequests ();