Fossil SCM

Add the cgi_csrf_safe() routine as a supplimental defense against cross-site request forgery attacks.

drh 2018-02-10 16:24 trunk
Commit 047802a3c3c55037bb0b897fcbc47100bf9387d56b426131ab25d543870edca4
+23
--- src/cgi.c
+++ src/cgi.c
@@ -456,10 +456,33 @@
456456
zRef = P("HTTP_REFERER");
457457
if( zRef==0 ) zRef = zDefault;
458458
}
459459
return zRef;
460460
}
461
+
462
+/*
463
+** Return true if the current request appears to be safe from a
464
+** Cross-Site Request Forgery (CSRF) attack. Conditions that must
465
+** be met:
466
+**
467
+** * The HTTP_REFERER must have the same origin
468
+** * The REQUEST_METHOD must be POST - or requirePost==0
469
+*/
470
+int cgi_csrf_safe(int requirePost){
471
+ const char *zRef = P("HTTP_REFERER");
472
+ int nBase;
473
+ if( zRef==0 ) return 0;
474
+ if( requirePost ){
475
+ const char *zMethod = P("REQUEST_METHOD");
476
+ if( zMethod==0 ) return 0;
477
+ if( strcmp(zMethod,"POST")!=0 ) return 0;
478
+ }
479
+ nBase = (int)strlen(g.zBaseURL);
480
+ if( strncmp(g.zBaseURL,zRef,nBase)!=0 ) return 0;
481
+ if( zRef[nBase]!=0 && zRef[nBase]!='/' ) return 0;
482
+ return 1;
483
+}
461484
462485
/*
463486
** Information about all query parameters and cookies are stored
464487
** in these variables.
465488
*/
466489
--- src/cgi.c
+++ src/cgi.c
@@ -456,10 +456,33 @@
456 zRef = P("HTTP_REFERER");
457 if( zRef==0 ) zRef = zDefault;
458 }
459 return zRef;
460 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
461
462 /*
463 ** Information about all query parameters and cookies are stored
464 ** in these variables.
465 */
466
--- src/cgi.c
+++ src/cgi.c
@@ -456,10 +456,33 @@
456 zRef = P("HTTP_REFERER");
457 if( zRef==0 ) zRef = zDefault;
458 }
459 return zRef;
460 }
461
462 /*
463 ** Return true if the current request appears to be safe from a
464 ** Cross-Site Request Forgery (CSRF) attack. Conditions that must
465 ** be met:
466 **
467 ** * The HTTP_REFERER must have the same origin
468 ** * The REQUEST_METHOD must be POST - or requirePost==0
469 */
470 int cgi_csrf_safe(int requirePost){
471 const char *zRef = P("HTTP_REFERER");
472 int nBase;
473 if( zRef==0 ) return 0;
474 if( requirePost ){
475 const char *zMethod = P("REQUEST_METHOD");
476 if( zMethod==0 ) return 0;
477 if( strcmp(zMethod,"POST")!=0 ) return 0;
478 }
479 nBase = (int)strlen(g.zBaseURL);
480 if( strncmp(g.zBaseURL,zRef,nBase)!=0 ) return 0;
481 if( zRef[nBase]!=0 && zRef[nBase]!='/' ) return 0;
482 return 1;
483 }
484
485 /*
486 ** Information about all query parameters and cookies are stored
487 ** in these variables.
488 */
489
+8 -4
--- src/setup.c
+++ src/setup.c
@@ -450,11 +450,11 @@
450450
451451
/* If we have all the necessary information, write the new or
452452
** modified user record. After writing the user record, redirect
453453
** to the page that displays a list of users.
454454
*/
455
- doWrite = cgi_all("login","info","pw") && !higherUser;
455
+ doWrite = cgi_all("login","info","pw") && !higherUser && cgi_csrf_safe(1);
456456
if( doWrite ){
457457
char c;
458458
char zCap[50], zNm[4];
459459
zNm[0] = 'a';
460460
zNm[2] = 0;
@@ -1716,11 +1716,11 @@
17161716
if( !g.perm.Setup ){
17171717
login_needed(0);
17181718
return;
17191719
}
17201720
db_begin_transaction();
1721
- if( P("clear")!=0 ){
1721
+ if( P("clear")!=0 && cgi_csrf_safe(1) ){
17221722
db_multi_exec("DELETE FROM config WHERE name GLOB 'adunit*'");
17231723
cgi_replace_parameter("adunit","");
17241724
}
17251725
17261726
style_header("Edit Ad Unit");
@@ -1805,11 +1805,13 @@
18051805
if( !g.perm.Setup ){
18061806
login_needed(0);
18071807
return;
18081808
}
18091809
db_begin_transaction();
1810
- if( P("setlogo")!=0 && zLogoMime && zLogoMime[0] && szLogoImg>0 ){
1810
+ if( !cgi_csrf_safe(1) ){
1811
+ /* Allow no state changes if not safe from CSRF */
1812
+ }else if( P("setlogo")!=0 && zLogoMime && zLogoMime[0] && szLogoImg>0 ){
18111813
Blob img;
18121814
Stmt ins;
18131815
blob_init(&img, aLogoImg, szLogoImg);
18141816
db_prepare(&ins,
18151817
"REPLACE INTO config(name,value,mtime)"
@@ -1940,19 +1942,20 @@
19401942
**
19411943
** Run raw SQL commands against the database file using the web interface.
19421944
** Requires Admin privileges.
19431945
*/
19441946
void sql_page(void){
1945
- const char *zQ = P("q");
1947
+ const char *zQ;
19461948
int go = P("go")!=0;
19471949
login_check_credentials();
19481950
if( !g.perm.Setup ){
19491951
login_needed(0);
19501952
return;
19511953
}
19521954
add_content_sql_commands(g.db);
19531955
db_begin_transaction();
1956
+ zQ = cgi_csrf_safe(1) ? P("q") : 0;
19541957
style_header("Raw SQL Commands");
19551958
@ <p><b>Caution:</b> There are no restrictions on the SQL that can be
19561959
@ run by this page. You can do serious and irrepairable damage to the
19571960
@ repository. Proceed with extreme caution.</p>
19581961
@
@@ -2270,10 +2273,11 @@
22702273
Blob *pSql,
22712274
const char *zOldName,
22722275
const char *zNewName,
22732276
const char *zValue
22742277
){
2278
+ if( !cgi_csrf_safe(1) ) return;
22752279
if( zNewName[0]==0 || zValue[0]==0 ){
22762280
if( zOldName[0] ){
22772281
blob_append_sql(pSql,
22782282
"DELETE FROM config WHERE name='walias:%q';\n",
22792283
zOldName);
22802284
--- src/setup.c
+++ src/setup.c
@@ -450,11 +450,11 @@
450
451 /* If we have all the necessary information, write the new or
452 ** modified user record. After writing the user record, redirect
453 ** to the page that displays a list of users.
454 */
455 doWrite = cgi_all("login","info","pw") && !higherUser;
456 if( doWrite ){
457 char c;
458 char zCap[50], zNm[4];
459 zNm[0] = 'a';
460 zNm[2] = 0;
@@ -1716,11 +1716,11 @@
1716 if( !g.perm.Setup ){
1717 login_needed(0);
1718 return;
1719 }
1720 db_begin_transaction();
1721 if( P("clear")!=0 ){
1722 db_multi_exec("DELETE FROM config WHERE name GLOB 'adunit*'");
1723 cgi_replace_parameter("adunit","");
1724 }
1725
1726 style_header("Edit Ad Unit");
@@ -1805,11 +1805,13 @@
1805 if( !g.perm.Setup ){
1806 login_needed(0);
1807 return;
1808 }
1809 db_begin_transaction();
1810 if( P("setlogo")!=0 && zLogoMime && zLogoMime[0] && szLogoImg>0 ){
 
 
1811 Blob img;
1812 Stmt ins;
1813 blob_init(&img, aLogoImg, szLogoImg);
1814 db_prepare(&ins,
1815 "REPLACE INTO config(name,value,mtime)"
@@ -1940,19 +1942,20 @@
1940 **
1941 ** Run raw SQL commands against the database file using the web interface.
1942 ** Requires Admin privileges.
1943 */
1944 void sql_page(void){
1945 const char *zQ = P("q");
1946 int go = P("go")!=0;
1947 login_check_credentials();
1948 if( !g.perm.Setup ){
1949 login_needed(0);
1950 return;
1951 }
1952 add_content_sql_commands(g.db);
1953 db_begin_transaction();
 
1954 style_header("Raw SQL Commands");
1955 @ <p><b>Caution:</b> There are no restrictions on the SQL that can be
1956 @ run by this page. You can do serious and irrepairable damage to the
1957 @ repository. Proceed with extreme caution.</p>
1958 @
@@ -2270,10 +2273,11 @@
2270 Blob *pSql,
2271 const char *zOldName,
2272 const char *zNewName,
2273 const char *zValue
2274 ){
 
2275 if( zNewName[0]==0 || zValue[0]==0 ){
2276 if( zOldName[0] ){
2277 blob_append_sql(pSql,
2278 "DELETE FROM config WHERE name='walias:%q';\n",
2279 zOldName);
2280
--- src/setup.c
+++ src/setup.c
@@ -450,11 +450,11 @@
450
451 /* If we have all the necessary information, write the new or
452 ** modified user record. After writing the user record, redirect
453 ** to the page that displays a list of users.
454 */
455 doWrite = cgi_all("login","info","pw") && !higherUser && cgi_csrf_safe(1);
456 if( doWrite ){
457 char c;
458 char zCap[50], zNm[4];
459 zNm[0] = 'a';
460 zNm[2] = 0;
@@ -1716,11 +1716,11 @@
1716 if( !g.perm.Setup ){
1717 login_needed(0);
1718 return;
1719 }
1720 db_begin_transaction();
1721 if( P("clear")!=0 && cgi_csrf_safe(1) ){
1722 db_multi_exec("DELETE FROM config WHERE name GLOB 'adunit*'");
1723 cgi_replace_parameter("adunit","");
1724 }
1725
1726 style_header("Edit Ad Unit");
@@ -1805,11 +1805,13 @@
1805 if( !g.perm.Setup ){
1806 login_needed(0);
1807 return;
1808 }
1809 db_begin_transaction();
1810 if( !cgi_csrf_safe(1) ){
1811 /* Allow no state changes if not safe from CSRF */
1812 }else if( P("setlogo")!=0 && zLogoMime && zLogoMime[0] && szLogoImg>0 ){
1813 Blob img;
1814 Stmt ins;
1815 blob_init(&img, aLogoImg, szLogoImg);
1816 db_prepare(&ins,
1817 "REPLACE INTO config(name,value,mtime)"
@@ -1940,19 +1942,20 @@
1942 **
1943 ** Run raw SQL commands against the database file using the web interface.
1944 ** Requires Admin privileges.
1945 */
1946 void sql_page(void){
1947 const char *zQ;
1948 int go = P("go")!=0;
1949 login_check_credentials();
1950 if( !g.perm.Setup ){
1951 login_needed(0);
1952 return;
1953 }
1954 add_content_sql_commands(g.db);
1955 db_begin_transaction();
1956 zQ = cgi_csrf_safe(1) ? P("q") : 0;
1957 style_header("Raw SQL Commands");
1958 @ <p><b>Caution:</b> There are no restrictions on the SQL that can be
1959 @ run by this page. You can do serious and irrepairable damage to the
1960 @ repository. Proceed with extreme caution.</p>
1961 @
@@ -2270,10 +2273,11 @@
2273 Blob *pSql,
2274 const char *zOldName,
2275 const char *zNewName,
2276 const char *zValue
2277 ){
2278 if( !cgi_csrf_safe(1) ) return;
2279 if( zNewName[0]==0 || zValue[0]==0 ){
2280 if( zOldName[0] ){
2281 blob_append_sql(pSql,
2282 "DELETE FROM config WHERE name='walias:%q';\n",
2283 zOldName);
2284
--- src/style.c
+++ src/style.c
@@ -925,10 +925,11 @@
925925
if( i>0 ){
926926
@ anonymous-adds = %s(zCap)<br />
927927
}
928928
@ g.zRepositoryName = %h(g.zRepositoryName)<br />
929929
@ load_average() = %f(load_average())<br />
930
+ @ cgi_csrf_safe(0) = %d(cgi_csrf_safe(0))<br />
930931
@ <hr />
931932
P("HTTP_USER_AGENT");
932933
cgi_print_all(showAll);
933934
if( showAll && blob_size(&g.httpHeader)>0 ){
934935
@ <hr />
935936
--- src/style.c
+++ src/style.c
@@ -925,10 +925,11 @@
925 if( i>0 ){
926 @ anonymous-adds = %s(zCap)<br />
927 }
928 @ g.zRepositoryName = %h(g.zRepositoryName)<br />
929 @ load_average() = %f(load_average())<br />
 
930 @ <hr />
931 P("HTTP_USER_AGENT");
932 cgi_print_all(showAll);
933 if( showAll && blob_size(&g.httpHeader)>0 ){
934 @ <hr />
935
--- src/style.c
+++ src/style.c
@@ -925,10 +925,11 @@
925 if( i>0 ){
926 @ anonymous-adds = %s(zCap)<br />
927 }
928 @ g.zRepositoryName = %h(g.zRepositoryName)<br />
929 @ load_average() = %f(load_average())<br />
930 @ cgi_csrf_safe(0) = %d(cgi_csrf_safe(0))<br />
931 @ <hr />
932 P("HTTP_USER_AGENT");
933 cgi_print_all(showAll);
934 if( showAll && blob_size(&g.httpHeader)>0 ){
935 @ <hr />
936

Keyboard Shortcuts

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