Fossil SCM

Reduce the timeout for anonymous logins to 1 hours. Add the IP address to the anonymous login cookie.

drh 2025-08-14 12:46 trunk
Commit 60a9fac4e1dca5f43cbf68101adaf0f8ac7f7496b8686ded994ab742634dcd77
1 file changed +16 -9
+16 -9
--- src/login.c
+++ src/login.c
@@ -341,32 +341,35 @@
341341
}
342342
}
343343
344344
/* Sets a cookie for an anonymous user login, which looks like this:
345345
**
346
-** HASH/TIME/anonymous
346
+** HASH/TIME:IPADDR/anonymous
347347
**
348
-** Where HASH is the sha1sum of TIME/SECRET, in which SECRET is captcha-secret.
348
+** Where HASH is the sha1sum of TIME:IPADDR/SECRET, in which SECRET
349
+** is captcha-secret.
349350
**
350351
** If zCookieDest is not NULL then the generated cookie is assigned to
351352
** *zCookieDest and the caller must eventually free() it.
352353
**
353354
** If bSessionCookie is true, the cookie will be a session cookie.
354355
*/
355356
void login_set_anon_cookie(char **zCookieDest, int bSessionCookie){
356357
char *zNow; /* Current time (julian day number) */
357358
char *zCookie; /* The login cookie */
359
+ const char *zIpAddr; /* IP Address */
358360
const char *zCookieName; /* Name of the login cookie */
359361
Blob b; /* Blob used during cookie construction */
360
- int expires = bSessionCookie ? 0 : 6*3600;
362
+ int expires = bSessionCookie ? 0 : 3600; /* Valid for 60 minutes */
361363
zCookieName = login_cookie_name();
362364
zNow = db_text("0", "SELECT julianday('now')");
363365
assert( zCookieName && zNow );
364366
blob_init(&b, zNow, -1);
365
- blob_appendf(&b, "/%z", captcha_secret(0));
367
+ zIpAddr = PD("REMOTE_ADDR","nil");
368
+ blob_appendf(&b, ":%s/%z", zIpAddr, captcha_secret(0));
366369
sha1sum_blob(&b, &b);
367
- zCookie = mprintf("%s/%s/anonymous", blob_buffer(&b), zNow);
370
+ zCookie = mprintf("%s/%s:%s/anonymous", blob_buffer(&b), zNow, zIpAddr);
368371
blob_reset(&b);
369372
cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), expires);
370373
if( zCookieDest ){
371374
*zCookieDest = zCookie;
372375
}else{
@@ -1458,20 +1461,24 @@
14581461
}
14591462
}
14601463
if( zUser==0 ){
14611464
/* Invalid cookie */
14621465
}else if( fossil_strcmp(zUser, "anonymous")==0 ){
1463
- /* Cookies of the form "HASH/TIME/anonymous". The TIME must not be
1464
- ** too old and the sha1 hash of TIME/SECRET must match HASH.
1465
- ** SECRET is the "captcha-secret" value in the repository.
1466
+ /* Cookies of the form "HASH/TIME:IPADDR/anonymous". The TIME must
1467
+ ** not be too old and the sha1 hash of TIME:IPADDR/SECRET must match
1468
+ ** HASH. SECRET is the "captcha-secret" value in the repository.
14661469
*/
14671470
double rTime = atof(zArg);
1471
+ const char *zCookieIP;
14681472
Blob b;
14691473
char *zSecret;
14701474
int n = 0;
14711475
1476
+ zCookieIP = strchr(zArg,':');
1477
+ if( zCookieIP && strcmp(zCookieIP+1,zIpAddr)!=0 ) zCookieIP = 0;
14721478
do{
1479
+ if( zCookieIP==0 ) break;
14731480
blob_zero(&b);
14741481
zSecret = captcha_secret(n++);
14751482
if( zSecret==0 ) break;
14761483
blob_appendf(&b, "%s/%s", zArg, zSecret);
14771484
sha1sum_blob(&b, &b);
@@ -1478,11 +1485,11 @@
14781485
if( fossil_strcmp(zHash, blob_str(&b))==0 ){
14791486
uid = db_int(0,
14801487
"SELECT uid FROM user WHERE login='anonymous'"
14811488
" AND octet_length(cap)>0"
14821489
" AND octet_length(pw)>0"
1483
- " AND %.17g+0.25>julianday('now')",
1490
+ " AND %.17g+0.0416667>julianday('now')",
14841491
rTime
14851492
);
14861493
}
14871494
}while( uid==0 );
14881495
blob_reset(&b);
14891496
--- src/login.c
+++ src/login.c
@@ -341,32 +341,35 @@
341 }
342 }
343
344 /* Sets a cookie for an anonymous user login, which looks like this:
345 **
346 ** HASH/TIME/anonymous
347 **
348 ** Where HASH is the sha1sum of TIME/SECRET, in which SECRET is captcha-secret.
 
349 **
350 ** If zCookieDest is not NULL then the generated cookie is assigned to
351 ** *zCookieDest and the caller must eventually free() it.
352 **
353 ** If bSessionCookie is true, the cookie will be a session cookie.
354 */
355 void login_set_anon_cookie(char **zCookieDest, int bSessionCookie){
356 char *zNow; /* Current time (julian day number) */
357 char *zCookie; /* The login cookie */
 
358 const char *zCookieName; /* Name of the login cookie */
359 Blob b; /* Blob used during cookie construction */
360 int expires = bSessionCookie ? 0 : 6*3600;
361 zCookieName = login_cookie_name();
362 zNow = db_text("0", "SELECT julianday('now')");
363 assert( zCookieName && zNow );
364 blob_init(&b, zNow, -1);
365 blob_appendf(&b, "/%z", captcha_secret(0));
 
366 sha1sum_blob(&b, &b);
367 zCookie = mprintf("%s/%s/anonymous", blob_buffer(&b), zNow);
368 blob_reset(&b);
369 cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), expires);
370 if( zCookieDest ){
371 *zCookieDest = zCookie;
372 }else{
@@ -1458,20 +1461,24 @@
1458 }
1459 }
1460 if( zUser==0 ){
1461 /* Invalid cookie */
1462 }else if( fossil_strcmp(zUser, "anonymous")==0 ){
1463 /* Cookies of the form "HASH/TIME/anonymous". The TIME must not be
1464 ** too old and the sha1 hash of TIME/SECRET must match HASH.
1465 ** SECRET is the "captcha-secret" value in the repository.
1466 */
1467 double rTime = atof(zArg);
 
1468 Blob b;
1469 char *zSecret;
1470 int n = 0;
1471
 
 
1472 do{
 
1473 blob_zero(&b);
1474 zSecret = captcha_secret(n++);
1475 if( zSecret==0 ) break;
1476 blob_appendf(&b, "%s/%s", zArg, zSecret);
1477 sha1sum_blob(&b, &b);
@@ -1478,11 +1485,11 @@
1478 if( fossil_strcmp(zHash, blob_str(&b))==0 ){
1479 uid = db_int(0,
1480 "SELECT uid FROM user WHERE login='anonymous'"
1481 " AND octet_length(cap)>0"
1482 " AND octet_length(pw)>0"
1483 " AND %.17g+0.25>julianday('now')",
1484 rTime
1485 );
1486 }
1487 }while( uid==0 );
1488 blob_reset(&b);
1489
--- src/login.c
+++ src/login.c
@@ -341,32 +341,35 @@
341 }
342 }
343
344 /* Sets a cookie for an anonymous user login, which looks like this:
345 **
346 ** HASH/TIME:IPADDR/anonymous
347 **
348 ** Where HASH is the sha1sum of TIME:IPADDR/SECRET, in which SECRET
349 ** is captcha-secret.
350 **
351 ** If zCookieDest is not NULL then the generated cookie is assigned to
352 ** *zCookieDest and the caller must eventually free() it.
353 **
354 ** If bSessionCookie is true, the cookie will be a session cookie.
355 */
356 void login_set_anon_cookie(char **zCookieDest, int bSessionCookie){
357 char *zNow; /* Current time (julian day number) */
358 char *zCookie; /* The login cookie */
359 const char *zIpAddr; /* IP Address */
360 const char *zCookieName; /* Name of the login cookie */
361 Blob b; /* Blob used during cookie construction */
362 int expires = bSessionCookie ? 0 : 3600; /* Valid for 60 minutes */
363 zCookieName = login_cookie_name();
364 zNow = db_text("0", "SELECT julianday('now')");
365 assert( zCookieName && zNow );
366 blob_init(&b, zNow, -1);
367 zIpAddr = PD("REMOTE_ADDR","nil");
368 blob_appendf(&b, ":%s/%z", zIpAddr, captcha_secret(0));
369 sha1sum_blob(&b, &b);
370 zCookie = mprintf("%s/%s:%s/anonymous", blob_buffer(&b), zNow, zIpAddr);
371 blob_reset(&b);
372 cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), expires);
373 if( zCookieDest ){
374 *zCookieDest = zCookie;
375 }else{
@@ -1458,20 +1461,24 @@
1461 }
1462 }
1463 if( zUser==0 ){
1464 /* Invalid cookie */
1465 }else if( fossil_strcmp(zUser, "anonymous")==0 ){
1466 /* Cookies of the form "HASH/TIME:IPADDR/anonymous". The TIME must
1467 ** not be too old and the sha1 hash of TIME:IPADDR/SECRET must match
1468 ** HASH. SECRET is the "captcha-secret" value in the repository.
1469 */
1470 double rTime = atof(zArg);
1471 const char *zCookieIP;
1472 Blob b;
1473 char *zSecret;
1474 int n = 0;
1475
1476 zCookieIP = strchr(zArg,':');
1477 if( zCookieIP && strcmp(zCookieIP+1,zIpAddr)!=0 ) zCookieIP = 0;
1478 do{
1479 if( zCookieIP==0 ) break;
1480 blob_zero(&b);
1481 zSecret = captcha_secret(n++);
1482 if( zSecret==0 ) break;
1483 blob_appendf(&b, "%s/%s", zArg, zSecret);
1484 sha1sum_blob(&b, &b);
@@ -1478,11 +1485,11 @@
1485 if( fossil_strcmp(zHash, blob_str(&b))==0 ){
1486 uid = db_int(0,
1487 "SELECT uid FROM user WHERE login='anonymous'"
1488 " AND octet_length(cap)>0"
1489 " AND octet_length(pw)>0"
1490 " AND %.17g+0.0416667>julianday('now')",
1491 rTime
1492 );
1493 }
1494 }while( uid==0 );
1495 blob_reset(&b);
1496

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button