User: |
@
Index: src/interwiki.c
==================================================================
--- src/interwiki.c
+++ src/interwiki.c
@@ -314,11 +314,11 @@
login_check_credentials();
if( !g.perm.Read && !g.perm.RdWiki && ~g.perm.RdTkt ){
login_needed(0);
return;
}
- if( g.perm.Setup && P("submit")!=0 && cgi_csrf_safe(1) ){
+ if( g.perm.Setup && P("submit")!=0 && cgi_csrf_safe(2) ){
zTag = PT("tag");
zBase = PT("base");
zHash = PT("hash");
zWiki = PT("wiki");
if( zTag==0 || zTag[0]==0 || !interwiki_valid_name(zTag) ){
Index: src/login.c
==================================================================
--- src/login.c
+++ src/login.c
@@ -49,10 +49,25 @@
# define sleep Sleep /* windows does not have sleep, but Sleep */
# endif
#endif
#include
+/*
+** 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
}
-/*
-** Before using the results of a form, first call this routine to verify
-** that this Anti-CSRF token is present and is valid. If the Anti-CSRF token
-** is missing or is incorrect, that indicates a cross-site scripting attack.
-** If the event of an attack is detected, an error message is generated and
-** all further processing is aborted.
-*/
-void login_verify_csrf_secret(void){
- if( g.okCsrf ) return;
- if( fossil_strcmp(P("csrf"), g.zCsrfToken)==0 ){
- g.okCsrf = 1;
- return;
- }
- fossil_fatal("Cross-site request forgery attempt");
-}
-
/*
** Check to see if the candidate username zUserID is already used.
** Return 1 if it is already in use. Return 0 if the name is
** available for a self-registeration.
*/
@@ -1978,11 +1982,11 @@
zConfirm = PDT("cp","");
zEAddr = PDT("ea","");
zDName = PDT("dn","");
/* Verify user imputs */
- if( P("new")==0 || !cgi_csrf_safe(1) ){
+ if( P("new")==0 || !cgi_csrf_safe(2) ){
/* This is not a valid form submission. Fall through into
** the form display */
}else if( (captchaIsCorrect = captcha_is_correct(1))==0 ){
iErrLine = 6;
zErr = "Incorrect CAPTCHA";
@@ -2256,11 +2260,11 @@
return;
}
zEAddr = PDT("ea","");
/* Verify user imputs */
- if( !cgi_csrf_safe(1) || P("reqpwreset")==0 ){
+ if( !cgi_csrf_safe(2) || P("reqpwreset")==0 ){
/* This is the initial display of the form. No processing or error
** checking is to be done. Fall through into the form display
*/
}else if( (captchaIsCorrect = captcha_is_correct(1))==0 ){
iErrLine = 2;
Index: src/main.c
==================================================================
--- src/main.c
+++ src/main.c
@@ -256,12 +256,16 @@
/* all Tcl related context necessary for integration */
struct TclContext tcl;
#endif
/* For defense against Cross-site Request Forgery attacks */
- char zCsrfToken[12]; /* Value of the anti-CSRF token */
- int okCsrf; /* Anti-CSRF token is present and valid */
+ 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 */
FILE *fDebug; /* Write debug information here, if the file exists */
#ifdef FOSSIL_ENABLE_TH1_HOOKS
int fNoThHook; /* Disable all TH1 command/webpage hooks */
Index: src/report.c
==================================================================
--- src/report.c
+++ src/report.c
@@ -471,16 +471,15 @@
zClrKey = trim_string(PD("k",""));
zDesc = trim_string(PD("d",""));
zMimetype = P("m");
zTag = P("x");
report_update_reportfmt_table();
- if( rn>0 && P("del2") ){
- login_verify_csrf_secret();
+ if( rn>0 && P("del2") && cgi_csrf_safe(2) ){
db_multi_exec("DELETE FROM reportfmt WHERE rn=%d", rn);
cgi_redirect("reportlist");
return;
- }else if( rn>0 && P("del1") ){
+ }else if( rn>0 && P("del1") && cgi_csrf_safe(2) ){
zTitle = db_text(0, "SELECT title FROM reportfmt "
"WHERE rn=%d", rn);
if( zTitle==0 ) cgi_redirect("reportlist");
style_header("Are You Sure?");
@@ -514,12 +513,11 @@
&& db_exists("SELECT 1 FROM reportfmt WHERE title=%Q and rn<>%d",
zTitle, rn)
){
zErr = mprintf("There is already another report named \"%h\"", zTitle);
}
- if( zErr==0 ){
- login_verify_csrf_secret();
+ if( zErr==0 && cgi_csrf_safe(2) ){
if( zTag && zTag[0]==0 ) zTag = 0;
if( zDesc && zDesc[0]==0 ){ zDesc = 0; zMimetype = 0; }
if( zMimetype && zMimetype[0]==0 ){ zDesc = 0; zMimetype = 0; }
if( rn>0 ){
db_multi_exec(
Index: src/security_audit.c
==================================================================
--- src/security_audit.c
+++ src/security_audit.c
@@ -795,11 +795,11 @@
@ command.
@
style_finish_page();
return;
}
- if( P("truncate1") && cgi_csrf_safe(1) ){
+ if( P("truncate1") && cgi_csrf_safe(2) ){
fclose(fopen(g.zErrlog,"w"));
}
if( P("download") ){
Blob log;
blob_read_from_file(&log, g.zErrlog, ExtFILE);
@@ -808,10 +808,11 @@
return;
}
szFile = file_size(g.zErrlog, ExtFILE);
if( P("truncate") ){
@
style_finish_page();
Index: src/setup.c
==================================================================
--- src/setup.c
+++ src/setup.c
@@ -202,12 +202,11 @@
if( zQ==0 && !disabled && P("submit") ){
zQ = "off";
}
if( zQ ){
int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ);
- if( iQ!=iVal ){
- login_verify_csrf_secret();
+ if( iQ!=iVal && cgi_csrf_safe(2) ){
db_protect_only(PROTECT_NONE);
db_set(zVar/*works-like:"x"*/, iQ ? "1" : "0", 0);
db_protect_pop();
setup_incr_cfgcnt();
admin_log("Set option [%q] to [%q].",
@@ -237,13 +236,12 @@
const char *zDflt, /* Default value if CONFIG table entry does not exist */
int disabled /* 1 if disabled */
){
const char *zVal = db_get(zVar, zDflt);
const char *zQ = P(zQParm);
- if( zQ && fossil_strcmp(zQ,zVal)!=0 ){
+ if( zQ && fossil_strcmp(zQ,zVal)!=0 && cgi_csrf_safe(2) ){
const int nZQ = (int)strlen(zQ);
- login_verify_csrf_secret();
setup_incr_cfgcnt();
db_protect_only(PROTECT_NONE);
db_set(zVar/*works-like:"x"*/, zQ, 0);
db_protect_pop();
admin_log("Set entry_attribute %Q to: %.*s%s",
@@ -270,13 +268,12 @@
const char *zDflt, /* Default value if CONFIG table entry does not exist */
int disabled /* 1 if the textarea should not be editable */
){
const char *z = db_get(zVar, zDflt);
const char *zQ = P(zQP);
- if( zQ && !disabled && fossil_strcmp(zQ,z)!=0){
+ if( zQ && !disabled && fossil_strcmp(zQ,z)!=0 && cgi_csrf_safe(2) ){
const int nZQ = (int)strlen(zQ);
- login_verify_csrf_secret();
db_protect_only(PROTECT_NONE);
db_set(zVar/*works-like:"x"*/, zQ, 0);
db_protect_pop();
setup_incr_cfgcnt();
admin_log("Set textarea_attribute %Q to: %.*s%s",
@@ -309,13 +306,12 @@
const char *const *azChoice /* Choices in pairs (VAR value, Display) */
){
const char *z = db_get(zVar, zDflt);
const char *zQ = P(zQP);
int i;
- if( zQ && fossil_strcmp(zQ,z)!=0){
+ if( zQ && fossil_strcmp(zQ,z)!=0 && cgi_csrf_safe(2) ){
const int nZQ = (int)strlen(zQ);
- login_verify_csrf_secret();
db_unprotect(PROTECT_ALL);
db_set(zVar/*works-like:"x"*/, zQ, 0);
setup_incr_cfgcnt();
db_protect_pop();
admin_log("Set multiple_choice_attribute %Q to: %.*s%s",
@@ -1458,11 +1454,11 @@
if( !g.perm.Admin ){
login_needed(0);
return;
}
db_begin_transaction();
- if( P("clear")!=0 && cgi_csrf_safe(1) ){
+ if( P("clear")!=0 && cgi_csrf_safe(2) ){
db_unprotect(PROTECT_CONFIG);
db_multi_exec("DELETE FROM config WHERE name GLOB 'adunit*'");
db_protect_pop();
cgi_replace_parameter("adunit","");
cgi_replace_parameter("adright","");
@@ -1560,11 +1556,11 @@
if( !g.perm.Admin ){
login_needed(0);
return;
}
db_begin_transaction();
- if( !cgi_csrf_safe(1) ){
+ if( !cgi_csrf_safe(2) ){
/* Allow no state changes if not safe from CSRF */
}else if( P("setlogo")!=0 && zLogoMime && zLogoMime[0] && szLogoImg>0 ){
Blob img;
Stmt ins;
blob_init(&img, aLogoImg, szLogoImg);
@@ -1769,11 +1765,11 @@
if( !g.perm.Setup ){
login_needed(0);
return;
}
add_content_sql_commands(g.db);
- zQ = cgi_csrf_safe(1) ? P("q") : 0;
+ zQ = cgi_csrf_safe(2) ? P("q") : 0;
style_set_current_feature("setup");
style_header("Raw SQL Commands");
@ Caution: There are no restrictions on the SQL that can be
@ run by this page. You can do serious and irrepairable damage to the
@ repository. Proceed with extreme caution.
@@ -1822,19 +1818,18 @@
go = 1;
}else if( P("tablelist") ){
zQ = sqlite3_mprintf("SELECT*FROM pragma_table_list ORDER BY schema, name");
go = 1;
}
- if( go ){
+ if( go && cgi_csrf_safe(2) ){
sqlite3_stmt *pStmt;
int rc;
const char *zTail;
int nCol;
int nRow = 0;
int i;
@
- login_verify_csrf_secret();
sqlite3_set_authorizer(g.db, raw_sql_query_authorizer, 0);
search_sql_setup(g.db);
rc = sqlite3_prepare_v2(g.db, zQ, -1, &pStmt, &zTail);
if( rc!=SQLITE_OK ){
@ %h(sqlite3_errmsg(g.db))
@@ -1913,22 +1908,20 @@
style_header("Raw TH1 Commands");
@ Caution: There are no restrictions on the TH1 that can be
@ run by this page. If Tcl integration was enabled at compile-time and
@ the "tcl" setting is enabled, Tcl commands may be run as well.
@
- @
- if( go ){
+ if( go && cgi_csrf_safe(2) ){
const char *zR;
int rc;
int n;
@
- login_verify_csrf_secret();
rc = Th_Eval(g.interp, 0, zQ, -1);
zR = Th_GetResult(g.interp, &n);
if( rc==TH_OK ){
@ %h(zR)
}else{
@@ -2129,11 +2122,11 @@
Blob *pSql,
const char *zOldName,
const char *zNewName,
const char *zValue
){
- if( !cgi_csrf_safe(1) ) return;
+ if( !cgi_csrf_safe(2) ) return;
if( zNewName[0]==0 || zValue[0]==0 ){
if( zOldName[0] ){
blob_append_sql(pSql,
"DELETE FROM config WHERE name='walias:%q';\n",
zOldName);
@@ -2173,17 +2166,16 @@
login_needed(0);
return;
}
style_set_current_feature("setup");
style_header("URL Alias Configuration");
- if( P("submit")!=0 ){
+ if( P("submit")!=0 && cgi_csrf_safe(2) ){
Blob token;
Blob sql;
const char *zNewName;
const char *zValue;
char zCnt[10];
- login_verify_csrf_secret();
blob_init(&namelist, PD("namelist",""), -1);
blob_init(&sql, 0, 0);
while( blob_token(&namelist, &token) ){
const char *zOldName = blob_str(&token);
sqlite3_snprintf(sizeof(zCnt), zCnt, "n%d", cnt);
Index: src/setupuser.c
==================================================================
--- src/setupuser.c
+++ src/setupuser.c
@@ -342,11 +342,11 @@
cgi_redirect(cgi_referer("setup_ulist"));
return;
}
/* Check for requests to delete the user */
- if( P("delete") && cgi_csrf_safe(1) ){
+ if( P("delete") && cgi_csrf_safe(2) ){
int n;
if( P("verifydelete") ){
/* Verified delete user request */
db_unprotect(PROTECT_USER);
if( alert_tables_exist() ){
@@ -386,11 +386,11 @@
** more are missing, no-op */
}else if( higherUser ){
/* An Admin (a) user cannot edit a Superuser (s) */
}else if( zDeleteVerify!=0 ){
/* Need to verify a delete request */
- }else if( !cgi_csrf_safe(1) ){
+ }else if( !cgi_csrf_safe(2) ){
/* This might be a cross-site request forgery, so ignore it */
}else{
/* We have all the information we need to make the change to the user */
char c;
char zCap[70], zNm[4];
@@ -440,11 +440,11 @@
@
@ [Bummer]
style_finish_page();
return;
}
- login_verify_csrf_secret();
+ cgi_csrf_verify();
db_unprotect(PROTECT_USER);
db_multi_exec(
"REPLACE INTO user(uid,login,info,pw,cap,mtime) "
"VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now())",
uid, zLogin, P("info"), zPw, zCap
Index: src/sha1.c
==================================================================
--- src/sha1.c
+++ src/sha1.c
@@ -392,10 +392,23 @@
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().
*/
Index: src/shun.c
==================================================================
--- src/shun.c
+++ src/shun.c
@@ -98,14 +98,13 @@
}
}
zUuid = zCanonical;
}
style_header("Shunned Artifacts");
- if( zUuid && P("sub") ){
+ if( zUuid && P("sub") && cgi_csrf_safe(2) ){
const char *p = zUuid;
int allExist = 1;
- login_verify_csrf_secret();
while( *p ){
db_multi_exec("DELETE FROM shun WHERE uuid=%Q", p);
if( !db_exists("SELECT 1 FROM blob WHERE uuid=%Q", p) ){
allExist = 0;
}
@@ -127,14 +126,13 @@
@ It may be necessary to rebuild the repository using the
@ fossil rebuild command-line before the artifact content
@ can pulled in from other repositories.
}
}
- if( zUuid && P("add") ){
+ if( zUuid && P("add") && cgi_csrf_safe(2) ){
const char *p = zUuid;
int rid, tagid;
- login_verify_csrf_secret();
while( *p ){
db_multi_exec(
"INSERT OR IGNORE INTO shun(uuid,mtime)"
" VALUES(%Q, now())", p);
db_multi_exec("DELETE FROM attachment WHERE src=%Q", p);
Index: src/skins.c
==================================================================
--- src/skins.c
+++ src/skins.c
@@ -531,11 +531,11 @@
aBuiltinSkin[i].zSQL = getSkin(aBuiltinSkin[i].zLabel);
}
style_set_current_feature("skins");
- if( cgi_csrf_safe(1) ){
+ if( cgi_csrf_safe(2) ){
/* Process requests to delete a user-defined skin */
if( P("del1") && (zName = skinVarName(P("sn"), 1))!=0 ){
style_header("Confirm Custom Skin Delete");
@ |
---|