Fossil SCM

Make anonymous cookies valid for 8 hours. Include the client IP address as part of the cookie hash, but do not display the client IP address within the text of the cookie.

drh 2025-08-17 17:16 trunk
Commit 68da4784aa3d5f3efae6e549957c65d6c8cace01e0c52d7b43fa5c96ab97f29e
1 file changed +21 -15
+21 -15
--- src/login.c
+++ src/login.c
@@ -339,37 +339,44 @@
339339
}else{
340340
free(zCookie);
341341
}
342342
}
343343
344
+/*
345
+** Lifetime of an anoymous cookie, in seconds.
346
+*/
347
+#define ANONYMOUS_COOKIE_LIFESPAN 28800 /* 28800 seconds == 8 hours */
348
+
344349
/* Sets a cookie for an anonymous user login, which looks like this:
345350
**
346
-** HASH/TIME:IPADDR/anonymous
351
+** HASH/TIME/anonymous
347352
**
348
-** Where HASH is the sha1sum of TIME:IPADDR/SECRET, in which SECRET
353
+** Where HASH is the sha1sum of TIME/IPADDR/SECRET, in which SECRET
349354
** is captcha-secret.
350355
**
351356
** If zCookieDest is not NULL then the generated cookie is assigned to
352357
** *zCookieDest and the caller must eventually free() it.
353358
**
354359
** If bSessionCookie is true, the cookie will be a session cookie.
360
+**
361
+** Search for tag-20250817a to find the code that recognizes this cookie.
355362
*/
356363
void login_set_anon_cookie(char **zCookieDest, int bSessionCookie){
357364
char *zNow; /* Current time (julian day number) */
358365
char *zCookie; /* The login cookie */
359366
const char *zIpAddr; /* IP Address */
360367
const char *zCookieName; /* Name of the login cookie */
361368
Blob b; /* Blob used during cookie construction */
362
- int expires = bSessionCookie ? 0 : 3600; /* Valid for 60 minutes */
369
+ int expires = bSessionCookie ? 0 : ANONYMOUS_COOKIE_LIFESPAN;
363370
zCookieName = login_cookie_name();
364371
zNow = db_text("0", "SELECT julianday('now')");
365372
assert( zCookieName && zNow );
366373
blob_init(&b, zNow, -1);
367374
zIpAddr = PD("REMOTE_ADDR","nil");
368
- blob_appendf(&b, ":%s/%z", zIpAddr, captcha_secret(0));
375
+ blob_appendf(&b, "/%s/%z", zIpAddr, captcha_secret(0));
369376
sha1sum_blob(&b, &b);
370
- zCookie = mprintf("%s/%s:%s/anonymous", blob_buffer(&b), zNow, zIpAddr);
377
+ zCookie = mprintf("%s/%s/anonymous", blob_buffer(&b), zNow);
371378
blob_reset(&b);
372379
cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), expires);
373380
if( zCookieDest ){
374381
*zCookieDest = zCookie;
375382
}else{
@@ -1412,36 +1419,35 @@
14121419
}
14131420
}
14141421
if( zUser==0 ){
14151422
/* Invalid cookie */
14161423
}else if( fossil_strcmp(zUser, "anonymous")==0 ){
1417
- /* Cookies of the form "HASH/TIME:IPADDR/anonymous". The TIME must
1418
- ** not be too old and the sha1 hash of TIME:IPADDR/SECRET must match
1419
- ** HASH. SECRET is the "captcha-secret" value in the repository.
1424
+ /* Cookies of the form "HASH/TIME/anonymous". The TIME must
1425
+ ** not be more than ANONYMOUS_COOKIE_LIFESPAN seconds ago and
1426
+ ** the sha1 hash of TIME/IPADDR/SECRET must match HASH. IPADDR
1427
+ ** is the remote address of the client and SECRET is the
1428
+ ** "captcha-secret" value in the repository. See tag-20250817a
1429
+ ** for the code the creates this cookie.
14201430
*/
14211431
double rTime = atof(zArg);
1422
- const char *zCookieIP;
14231432
Blob b;
14241433
char *zSecret;
14251434
int n = 0;
14261435
1427
- zCookieIP = strchr(zArg,':');
1428
- if( zCookieIP && strcmp(zCookieIP+1,zIpAddr)!=0 ) zCookieIP = 0;
14291436
do{
1430
- if( zCookieIP==0 ) break;
14311437
blob_zero(&b);
14321438
zSecret = captcha_secret(n++);
14331439
if( zSecret==0 ) break;
1434
- blob_appendf(&b, "%s/%s", zArg, zSecret);
1440
+ blob_appendf(&b, "%s/%s/%s", zArg, zIpAddr, zSecret);
14351441
sha1sum_blob(&b, &b);
14361442
if( fossil_strcmp(zHash, blob_str(&b))==0 ){
14371443
uid = db_int(0,
14381444
"SELECT uid FROM user WHERE login='anonymous'"
14391445
" AND octet_length(cap)>0"
14401446
" AND octet_length(pw)>0"
1441
- " AND %.17g+0.0416667>julianday('now')",
1442
- rTime
1447
+ " AND %.17g>julianday('now')",
1448
+ rTime+ANONYMOUS_COOKIE_LIFESPAN/86400.0
14431449
);
14441450
}
14451451
}while( uid==0 );
14461452
blob_reset(&b);
14471453
}else{
14481454
--- src/login.c
+++ src/login.c
@@ -339,37 +339,44 @@
339 }else{
340 free(zCookie);
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{
@@ -1412,36 +1419,35 @@
1412 }
1413 }
1414 if( zUser==0 ){
1415 /* Invalid cookie */
1416 }else if( fossil_strcmp(zUser, "anonymous")==0 ){
1417 /* Cookies of the form "HASH/TIME:IPADDR/anonymous". The TIME must
1418 ** not be too old and the sha1 hash of TIME:IPADDR/SECRET must match
1419 ** HASH. SECRET is the "captcha-secret" value in the repository.
 
 
 
1420 */
1421 double rTime = atof(zArg);
1422 const char *zCookieIP;
1423 Blob b;
1424 char *zSecret;
1425 int n = 0;
1426
1427 zCookieIP = strchr(zArg,':');
1428 if( zCookieIP && strcmp(zCookieIP+1,zIpAddr)!=0 ) zCookieIP = 0;
1429 do{
1430 if( zCookieIP==0 ) break;
1431 blob_zero(&b);
1432 zSecret = captcha_secret(n++);
1433 if( zSecret==0 ) break;
1434 blob_appendf(&b, "%s/%s", zArg, zSecret);
1435 sha1sum_blob(&b, &b);
1436 if( fossil_strcmp(zHash, blob_str(&b))==0 ){
1437 uid = db_int(0,
1438 "SELECT uid FROM user WHERE login='anonymous'"
1439 " AND octet_length(cap)>0"
1440 " AND octet_length(pw)>0"
1441 " AND %.17g+0.0416667>julianday('now')",
1442 rTime
1443 );
1444 }
1445 }while( uid==0 );
1446 blob_reset(&b);
1447 }else{
1448
--- src/login.c
+++ src/login.c
@@ -339,37 +339,44 @@
339 }else{
340 free(zCookie);
341 }
342 }
343
344 /*
345 ** Lifetime of an anoymous cookie, in seconds.
346 */
347 #define ANONYMOUS_COOKIE_LIFESPAN 28800 /* 28800 seconds == 8 hours */
348
349 /* Sets a cookie for an anonymous user login, which looks like this:
350 **
351 ** HASH/TIME/anonymous
352 **
353 ** Where HASH is the sha1sum of TIME/IPADDR/SECRET, in which SECRET
354 ** is captcha-secret.
355 **
356 ** If zCookieDest is not NULL then the generated cookie is assigned to
357 ** *zCookieDest and the caller must eventually free() it.
358 **
359 ** If bSessionCookie is true, the cookie will be a session cookie.
360 **
361 ** Search for tag-20250817a to find the code that recognizes this cookie.
362 */
363 void login_set_anon_cookie(char **zCookieDest, int bSessionCookie){
364 char *zNow; /* Current time (julian day number) */
365 char *zCookie; /* The login cookie */
366 const char *zIpAddr; /* IP Address */
367 const char *zCookieName; /* Name of the login cookie */
368 Blob b; /* Blob used during cookie construction */
369 int expires = bSessionCookie ? 0 : ANONYMOUS_COOKIE_LIFESPAN;
370 zCookieName = login_cookie_name();
371 zNow = db_text("0", "SELECT julianday('now')");
372 assert( zCookieName && zNow );
373 blob_init(&b, zNow, -1);
374 zIpAddr = PD("REMOTE_ADDR","nil");
375 blob_appendf(&b, "/%s/%z", zIpAddr, captcha_secret(0));
376 sha1sum_blob(&b, &b);
377 zCookie = mprintf("%s/%s/anonymous", blob_buffer(&b), zNow);
378 blob_reset(&b);
379 cgi_set_cookie(zCookieName, zCookie, login_cookie_path(), expires);
380 if( zCookieDest ){
381 *zCookieDest = zCookie;
382 }else{
@@ -1412,36 +1419,35 @@
1419 }
1420 }
1421 if( zUser==0 ){
1422 /* Invalid cookie */
1423 }else if( fossil_strcmp(zUser, "anonymous")==0 ){
1424 /* Cookies of the form "HASH/TIME/anonymous". The TIME must
1425 ** not be more than ANONYMOUS_COOKIE_LIFESPAN seconds ago and
1426 ** the sha1 hash of TIME/IPADDR/SECRET must match HASH. IPADDR
1427 ** is the remote address of the client and SECRET is the
1428 ** "captcha-secret" value in the repository. See tag-20250817a
1429 ** for the code the creates this cookie.
1430 */
1431 double rTime = atof(zArg);
 
1432 Blob b;
1433 char *zSecret;
1434 int n = 0;
1435
 
 
1436 do{
 
1437 blob_zero(&b);
1438 zSecret = captcha_secret(n++);
1439 if( zSecret==0 ) break;
1440 blob_appendf(&b, "%s/%s/%s", zArg, zIpAddr, zSecret);
1441 sha1sum_blob(&b, &b);
1442 if( fossil_strcmp(zHash, blob_str(&b))==0 ){
1443 uid = db_int(0,
1444 "SELECT uid FROM user WHERE login='anonymous'"
1445 " AND octet_length(cap)>0"
1446 " AND octet_length(pw)>0"
1447 " AND %.17g>julianday('now')",
1448 rTime+ANONYMOUS_COOKIE_LIFESPAN/86400.0
1449 );
1450 }
1451 }while( uid==0 );
1452 blob_reset(&b);
1453 }else{
1454

Keyboard Shortcuts

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