Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Stronger CSRF token based on a SHA1 hash of the login cookie. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | csrf-defense-enhancement |
| Files: | files | file ages | folders |
| SHA3-256: |
ff3746c4c214a50e74328463604d9ae1 |
| User & Date: | drh 2023-09-18 14:13:38.976 |
Context
|
2023-09-18
| ||
| 14:29 | Cleanup forms on the skin editor page. ... (check-in: 5feae3fd75 user: drh tags: csrf-defense-enhancement) | |
| 14:13 | Stronger CSRF token based on a SHA1 hash of the login cookie. ... (check-in: ff3746c4c2 user: drh tags: csrf-defense-enhancement) | |
| 13:18 | Try to simplify and rationalize the defenses against cross-site request forgery attacks. A hodgepodge of techniques have been used in the past. This changes attempts to make everything work more alike and to centralize CSRF defenses for easier auditing. ... (check-in: 88a402fe2a user: drh tags: csrf-defense-enhancement) | |
Changes
Changes to src/builtin.c.
| ︙ | ︙ | |||
664 665 666 667 668 669 670 |
CX("};\n"/* fossil.config */);
CX("window.fossil.user = {");
CX("name: %!j,", (g.zLogin&&*g.zLogin) ? g.zLogin : "guest");
CX("isAdmin: %s", (g.perm.Admin || g.perm.Setup) ? "true" : "false");
CX("};\n"/*fossil.user*/);
CX("if(fossil.config.skin.isDark) "
"document.body.classList.add('fossil-dark-style');\n");
| < < < < < < < < | 664 665 666 667 668 669 670 671 672 673 674 675 676 677 |
CX("};\n"/* fossil.config */);
CX("window.fossil.user = {");
CX("name: %!j,", (g.zLogin&&*g.zLogin) ? g.zLogin : "guest");
CX("isAdmin: %s", (g.perm.Admin || g.perm.Setup) ? "true" : "false");
CX("};\n"/*fossil.user*/);
CX("if(fossil.config.skin.isDark) "
"document.body.classList.add('fossil-dark-style');\n");
/*
** fossil.page holds info about the current page. This is also
** where the current page "should" store any of its own
** page-specific state, and it is reserved for that purpose.
*/
CX("window.fossil.page = {"
"name:\"%T\""
|
| ︙ | ︙ |
Changes to src/login.c.
| ︙ | ︙ | |||
47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# include <windows.h> /* for Sleep */
# if defined(__MINGW32__) || defined(_MSC_VER)
# define sleep Sleep /* windows does not have sleep, but Sleep */
# endif
#endif
#include <time.h>
/*
** Return the login-group name. Or return 0 if this repository is
** not a member of a login-group.
*/
const char *login_group_name(void){
static const char *zGroup = 0;
| > > > > > > > > > > > > > > > | 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# include <windows.h> /* for Sleep */
# if defined(__MINGW32__) || defined(_MSC_VER)
# define sleep Sleep /* windows does not have sleep, but Sleep */
# endif
#endif
#include <time.h>
/*
** Compute an appropriate Anti-CSRF token into g.zCsrfToken[].
*/
static void login_create_csrf_secret(const char *zSeed){
unsigned char zResult[20];
int i;
sha1sum_binary(zSeed, zResult);
for(i=0; i<sizeof(g.zCsrfToken)-1; i++){
g.zCsrfToken[i] = "abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789-/"[zResult[i]%64];
}
g.zCsrfToken[i] = 0;
}
/*
** Return the login-group name. Or return 0 if this repository is
** not a member of a login-group.
*/
const char *login_group_name(void){
static const char *zGroup = 0;
|
| ︙ | ︙ | |||
1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 |
zIpAddr = PD("REMOTE_ADDR","nil");
if( ( cgi_is_loopback(zIpAddr)
|| (g.fSshClient & CGI_SSH_CLIENT)!=0 )
&& g.useLocalauth
&& db_get_int("localauth",0)==0
&& P("HTTPS")==0
){
if( g.localOpen ) zLogin = db_lget("default-user",0);
if( zLogin!=0 ){
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
}else{
uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
}
g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid);
zCap = "sxy";
g.noPswd = 1;
g.isHuman = 1;
| > | > > > | 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 |
zIpAddr = PD("REMOTE_ADDR","nil");
if( ( cgi_is_loopback(zIpAddr)
|| (g.fSshClient & CGI_SSH_CLIENT)!=0 )
&& g.useLocalauth
&& db_get_int("localauth",0)==0
&& P("HTTPS")==0
){
char *zSeed;
if( g.localOpen ) zLogin = db_lget("default-user",0);
if( zLogin!=0 ){
uid = db_int(0, "SELECT uid FROM user WHERE login=%Q", zLogin);
}else{
uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'");
}
g.zLogin = db_text("?", "SELECT login FROM user WHERE uid=%d", uid);
zCap = "sxy";
g.noPswd = 1;
g.isHuman = 1;
zSeed = db_text("??", "SELECT uid||quote(login)||quote(pw)||quote(cookie)"
" FROM user WHERE uid=%d", uid);
login_create_csrf_secret(zSeed);
fossil_free(zSeed);
}
/* Check the login cookie to see if it matches a known valid user.
*/
if( uid==0 && (zCookie = P(login_cookie_name()))!=0 ){
/* Parse the cookie value up into HASH/ARG/USER */
char *zHash = fossil_strdup(zCookie);
|
| ︙ | ︙ | |||
1352 1353 1354 1355 1356 1357 1358 |
*/
uid = login_find_user(zUser, zHash);
if( uid==0 && login_transfer_credentials(zUser,zArg,zHash) ){
uid = login_find_user(zUser, zHash);
if( uid ) record_login_attempt(zUser, zIpAddr, 1);
}
}
| | | 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 |
*/
uid = login_find_user(zUser, zHash);
if( uid==0 && login_transfer_credentials(zUser,zArg,zHash) ){
uid = login_find_user(zUser, zHash);
if( uid ) record_login_attempt(zUser, zIpAddr, 1);
}
}
login_create_csrf_secret(zHash);
}
/* If no user found and the REMOTE_USER environment variable is set,
** then accept the value of REMOTE_USER as the user.
*/
if( uid==0 ){
const char *zRemoteUser = P("REMOTE_USER");
|
| ︙ | ︙ | |||
1402 1403 1404 1405 1406 1407 1408 |
if( uid==0 ){
uid = db_int(0, "SELECT uid FROM user WHERE login='nobody'");
if( uid==0 ){
/* If there is no user "nobody", then make one up - with no privileges */
uid = -1;
zCap = "";
}
| | | 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 |
if( uid==0 ){
uid = db_int(0, "SELECT uid FROM user WHERE login='nobody'");
if( uid==0 ){
/* If there is no user "nobody", then make one up - with no privileges */
uid = -1;
zCap = "";
}
login_create_csrf_secret("none");
}
login_set_uid(uid, zCap);
}
/*
** Set the current logged in user to be uid. zCap is precomputed
|
| ︙ | ︙ |
Changes to src/main.c.
| ︙ | ︙ | |||
254 255 256 257 258 259 260 | #ifdef FOSSIL_ENABLE_TCL /* all Tcl related context necessary for integration */ struct TclContext tcl; #endif /* For defense against Cross-site Request Forgery attacks */ | | | 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
#ifdef FOSSIL_ENABLE_TCL
/* all Tcl related context necessary for integration */
struct TclContext tcl;
#endif
/* For defense against Cross-site Request Forgery attacks */
char zCsrfToken[16]; /* Value of the anti-CSRF token */
int okCsrf; /* -1: unsafe
** 0: unknown
** 1: same origin
** 2: same origin + is POST
** 3: same origin, POST, valid csrf token */
int parseCnt[10]; /* Counts of artifacts parsed */
|
| ︙ | ︙ |
Changes to src/sha1.c.
| ︙ | ︙ | |||
390 391 392 393 394 395 396 397 398 399 400 401 402 403 |
blob_zero(pCksum);
}
blob_resize(pCksum, 40);
SHA1Final(zResult, &ctx);
DigestToBase16(zResult, blob_buffer(pCksum));
return 0;
}
/*
** Compute the SHA1 checksum of a zero-terminated string. The
** result is held in memory obtained from mprintf().
*/
char *sha1sum(const char *zIn){
SHA1Context ctx;
| > > > > > > > > > > > > > | 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
blob_zero(pCksum);
}
blob_resize(pCksum, 40);
SHA1Final(zResult, &ctx);
DigestToBase16(zResult, blob_buffer(pCksum));
return 0;
}
/*
** Compute a binary SHA1 checksum of a zero-terminated string. The
** result is stored in zOut, which is a buffer that must be at least
** 20 bytes in size.
*/
void sha1sum_binary(const char *zIn, unsigned char *zOut){
SHA1Context ctx;
SHA1Init(&ctx);
SHA1Update(&ctx, (unsigned const char*)zIn, strlen(zIn));
SHA1Final(zOut, &ctx);
}
/*
** Compute the SHA1 checksum of a zero-terminated string. The
** result is held in memory obtained from mprintf().
*/
char *sha1sum(const char *zIn){
SHA1Context ctx;
|
| ︙ | ︙ |