Fossil SCM
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.
Commit
88a402fe2a5641990497eeed13f4848903c94ba37d860997c430da874849d7a8
Parent
8ff63db2e66013a…
16 files changed
+46
-22
+1
-2
+2
-3
+1
-3
+2
-17
+5
-1
+3
-5
+8
-16
+2
-2
+2
-4
+1
+3
-1
+4
-3
+2
-4
+1
-2
+2
-4
+46
-22
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -700,42 +700,66 @@ | ||
| 700 | 700 | nBase = (int)strlen(g.zBaseURL); |
| 701 | 701 | if( fossil_strncmp(g.zBaseURL,zRef,nBase)!=0 ) return 0; |
| 702 | 702 | if( zRef[nBase]!=0 && zRef[nBase]!='/' ) return 0; |
| 703 | 703 | return 1; |
| 704 | 704 | } |
| 705 | + | |
| 706 | +/* | |
| 707 | +** Return true if the current CGI request is a POST request | |
| 708 | +*/ | |
| 709 | +static int cgi_is_post_request(void){ | |
| 710 | + const char *zMethod = P("REQUEST_METHOD"); | |
| 711 | + if( zMethod==0 ) return 0; | |
| 712 | + if( strcmp(zMethod,"POST")!=0 ) return 0; | |
| 713 | + return 1; | |
| 714 | +} | |
| 705 | 715 | |
| 706 | 716 | /* |
| 707 | 717 | ** Return true if the current request appears to be safe from a |
| 708 | -** Cross-Site Request Forgery (CSRF) attack. Conditions that must | |
| 709 | -** be met: | |
| 718 | +** Cross-Site Request Forgery (CSRF) attack. The level of checking | |
| 719 | +** is determined by the parameter. The higher the number, the more | |
| 720 | +** secure we are: | |
| 721 | +** | |
| 722 | +** 0: Request must come from the same origin | |
| 723 | +** 1: Same origin and must be a POST request | |
| 724 | +** 2: All of the above plus must have a valid CSRF token | |
| 725 | +** | |
| 726 | +** Results are cached in the g.okCsrf variable. The g.okCsrf value | |
| 727 | +** has meaning as follows: | |
| 710 | 728 | ** |
| 711 | -** * The HTTP_REFERER must have the same origin | |
| 712 | -** * The REQUEST_METHOD must be POST - or requirePost==0 | |
| 729 | +** -1: Not a secure request | |
| 730 | +** 0: Status unknown | |
| 731 | +** 1: Request comes from the same origin | |
| 732 | +** 2: (1) plus it is a POST request | |
| 733 | +** 3: (2) plus there is a valid "csrf" token in the request | |
| 713 | 734 | */ |
| 714 | -int cgi_csrf_safe(int requirePost){ | |
| 715 | - if( requirePost ){ | |
| 716 | - const char *zMethod = P("REQUEST_METHOD"); | |
| 717 | - if( zMethod==0 ) return 0; | |
| 718 | - if( strcmp(zMethod,"POST")!=0 ) return 0; | |
| 735 | +int cgi_csrf_safe(int securityLevel){ | |
| 736 | + if( g.okCsrf<0 ) return 0; | |
| 737 | + if( g.okCsrf==0 ){ | |
| 738 | + if( !cgi_same_origin() ){ | |
| 739 | + g.okCsrf = -1; | |
| 740 | + }else{ | |
| 741 | + g.okCsrf = 1; | |
| 742 | + if( cgi_is_post_request() ){ | |
| 743 | + g.okCsrf = 2; | |
| 744 | + if( fossil_strcmp(P("csrf"), g.zCsrfToken)==0 ){ | |
| 745 | + g.okCsrf = 3; | |
| 746 | + } | |
| 747 | + } | |
| 748 | + } | |
| 719 | 749 | } |
| 720 | - return cgi_same_origin(); | |
| 750 | + return g.okCsrf >= (securityLevel+1); | |
| 721 | 751 | } |
| 722 | 752 | |
| 723 | 753 | /* |
| 724 | -** If bLoginVerifyCsrf is true, this calls login_verify_csrf() to | |
| 725 | -** verify that the secret injected by login_insert_csrf_secret() is in | |
| 726 | -** the CGI environment and valid. If that fails, it does so | |
| 727 | -** fatally. If that passes and cgi_csrf_safe(1) returns false, this | |
| 728 | -** fails fatally with a message about a cross-site scripting attempt, | |
| 729 | -** else it returns without side effects. | |
| 754 | +** Verify that CSRF defenses are maximal - that the request comes from | |
| 755 | +** the same origin, that it is a POST request, and that there is a valid | |
| 756 | +** "csrf" token. If this is not the case, fail immediately. | |
| 730 | 757 | */ |
| 731 | -void cgi_csrf_verify(int bLoginVerifyCsrf){ | |
| 732 | - if( bLoginVerifyCsrf!=0 ){ | |
| 733 | - login_verify_csrf_secret(); | |
| 734 | - } | |
| 735 | - if( 0==cgi_csrf_safe(1) ){ | |
| 736 | - fossil_fatal("Cross-site request forgery attempt"); | |
| 758 | +void cgi_csrf_verify(void){ | |
| 759 | + if( !cgi_csrf_safe(2) ){ | |
| 760 | + fossil_fatal("Cross-site Request Forgery detected"); | |
| 737 | 761 | } |
| 738 | 762 | } |
| 739 | 763 | |
| 740 | 764 | /* |
| 741 | 765 | ** Information about all query parameters, post parameter, cookies and |
| 742 | 766 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -700,42 +700,66 @@ | |
| 700 | nBase = (int)strlen(g.zBaseURL); |
| 701 | if( fossil_strncmp(g.zBaseURL,zRef,nBase)!=0 ) return 0; |
| 702 | if( zRef[nBase]!=0 && zRef[nBase]!='/' ) return 0; |
| 703 | return 1; |
| 704 | } |
| 705 | |
| 706 | /* |
| 707 | ** Return true if the current request appears to be safe from a |
| 708 | ** Cross-Site Request Forgery (CSRF) attack. Conditions that must |
| 709 | ** be met: |
| 710 | ** |
| 711 | ** * The HTTP_REFERER must have the same origin |
| 712 | ** * The REQUEST_METHOD must be POST - or requirePost==0 |
| 713 | */ |
| 714 | int cgi_csrf_safe(int requirePost){ |
| 715 | if( requirePost ){ |
| 716 | const char *zMethod = P("REQUEST_METHOD"); |
| 717 | if( zMethod==0 ) return 0; |
| 718 | if( strcmp(zMethod,"POST")!=0 ) return 0; |
| 719 | } |
| 720 | return cgi_same_origin(); |
| 721 | } |
| 722 | |
| 723 | /* |
| 724 | ** If bLoginVerifyCsrf is true, this calls login_verify_csrf() to |
| 725 | ** verify that the secret injected by login_insert_csrf_secret() is in |
| 726 | ** the CGI environment and valid. If that fails, it does so |
| 727 | ** fatally. If that passes and cgi_csrf_safe(1) returns false, this |
| 728 | ** fails fatally with a message about a cross-site scripting attempt, |
| 729 | ** else it returns without side effects. |
| 730 | */ |
| 731 | void cgi_csrf_verify(int bLoginVerifyCsrf){ |
| 732 | if( bLoginVerifyCsrf!=0 ){ |
| 733 | login_verify_csrf_secret(); |
| 734 | } |
| 735 | if( 0==cgi_csrf_safe(1) ){ |
| 736 | fossil_fatal("Cross-site request forgery attempt"); |
| 737 | } |
| 738 | } |
| 739 | |
| 740 | /* |
| 741 | ** Information about all query parameters, post parameter, cookies and |
| 742 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -700,42 +700,66 @@ | |
| 700 | nBase = (int)strlen(g.zBaseURL); |
| 701 | if( fossil_strncmp(g.zBaseURL,zRef,nBase)!=0 ) return 0; |
| 702 | if( zRef[nBase]!=0 && zRef[nBase]!='/' ) return 0; |
| 703 | return 1; |
| 704 | } |
| 705 | |
| 706 | /* |
| 707 | ** Return true if the current CGI request is a POST request |
| 708 | */ |
| 709 | static int cgi_is_post_request(void){ |
| 710 | const char *zMethod = P("REQUEST_METHOD"); |
| 711 | if( zMethod==0 ) return 0; |
| 712 | if( strcmp(zMethod,"POST")!=0 ) return 0; |
| 713 | return 1; |
| 714 | } |
| 715 | |
| 716 | /* |
| 717 | ** Return true if the current request appears to be safe from a |
| 718 | ** Cross-Site Request Forgery (CSRF) attack. The level of checking |
| 719 | ** is determined by the parameter. The higher the number, the more |
| 720 | ** secure we are: |
| 721 | ** |
| 722 | ** 0: Request must come from the same origin |
| 723 | ** 1: Same origin and must be a POST request |
| 724 | ** 2: All of the above plus must have a valid CSRF token |
| 725 | ** |
| 726 | ** Results are cached in the g.okCsrf variable. The g.okCsrf value |
| 727 | ** has meaning as follows: |
| 728 | ** |
| 729 | ** -1: Not a secure request |
| 730 | ** 0: Status unknown |
| 731 | ** 1: Request comes from the same origin |
| 732 | ** 2: (1) plus it is a POST request |
| 733 | ** 3: (2) plus there is a valid "csrf" token in the request |
| 734 | */ |
| 735 | int cgi_csrf_safe(int securityLevel){ |
| 736 | if( g.okCsrf<0 ) return 0; |
| 737 | if( g.okCsrf==0 ){ |
| 738 | if( !cgi_same_origin() ){ |
| 739 | g.okCsrf = -1; |
| 740 | }else{ |
| 741 | g.okCsrf = 1; |
| 742 | if( cgi_is_post_request() ){ |
| 743 | g.okCsrf = 2; |
| 744 | if( fossil_strcmp(P("csrf"), g.zCsrfToken)==0 ){ |
| 745 | g.okCsrf = 3; |
| 746 | } |
| 747 | } |
| 748 | } |
| 749 | } |
| 750 | return g.okCsrf >= (securityLevel+1); |
| 751 | } |
| 752 | |
| 753 | /* |
| 754 | ** Verify that CSRF defenses are maximal - that the request comes from |
| 755 | ** the same origin, that it is a POST request, and that there is a valid |
| 756 | ** "csrf" token. If this is not the case, fail immediately. |
| 757 | */ |
| 758 | void cgi_csrf_verify(void){ |
| 759 | if( !cgi_csrf_safe(2) ){ |
| 760 | fossil_fatal("Cross-site Request Forgery detected"); |
| 761 | } |
| 762 | } |
| 763 | |
| 764 | /* |
| 765 | ** Information about all query parameters, post parameter, cookies and |
| 766 |
+1
-2
| --- src/event.c | ||
| +++ src/event.c | ||
| @@ -468,12 +468,11 @@ | ||
| 468 | 468 | rid |
| 469 | 469 | ); |
| 470 | 470 | } |
| 471 | 471 | } |
| 472 | 472 | zETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))", zETime); |
| 473 | - if( P("submit")!=0 && (zBody!=0 && zComment!=0) ){ | |
| 474 | - login_verify_csrf_secret(); | |
| 473 | + if( P("submit")!=0 && (zBody!=0 && zComment!=0) && cgi_csrf_safe(2) ){ | |
| 475 | 474 | if ( !event_commit_common(rid, zId, zBody, zETime, |
| 476 | 475 | zMimetype, zComment, zTags, |
| 477 | 476 | zClrFlag[0] ? zClr : 0) ){ |
| 478 | 477 | style_header("Error"); |
| 479 | 478 | @ Internal error: Fossil tried to make an invalid artifact for |
| 480 | 479 |
| --- src/event.c | |
| +++ src/event.c | |
| @@ -468,12 +468,11 @@ | |
| 468 | rid |
| 469 | ); |
| 470 | } |
| 471 | } |
| 472 | zETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))", zETime); |
| 473 | if( P("submit")!=0 && (zBody!=0 && zComment!=0) ){ |
| 474 | login_verify_csrf_secret(); |
| 475 | if ( !event_commit_common(rid, zId, zBody, zETime, |
| 476 | zMimetype, zComment, zTags, |
| 477 | zClrFlag[0] ? zClr : 0) ){ |
| 478 | style_header("Error"); |
| 479 | @ Internal error: Fossil tried to make an invalid artifact for |
| 480 |
| --- src/event.c | |
| +++ src/event.c | |
| @@ -468,12 +468,11 @@ | |
| 468 | rid |
| 469 | ); |
| 470 | } |
| 471 | } |
| 472 | zETime = db_text(0, "SELECT coalesce(datetime(%Q),datetime('now'))", zETime); |
| 473 | if( P("submit")!=0 && (zBody!=0 && zComment!=0) && cgi_csrf_safe(2) ){ |
| 474 | if ( !event_commit_common(rid, zId, zBody, zETime, |
| 475 | zMimetype, zComment, zTags, |
| 476 | zClrFlag[0] ? zClr : 0) ){ |
| 477 | style_header("Error"); |
| 478 | @ Internal error: Fossil tried to make an invalid artifact for |
| 479 |
+2
-3
| --- src/forum.c | ||
| +++ src/forum.c | ||
| @@ -1423,11 +1423,11 @@ | ||
| 1423 | 1423 | login_check_credentials(); |
| 1424 | 1424 | if( forumpost_may_close()==0 ){ |
| 1425 | 1425 | login_needed(g.anon.Admin); |
| 1426 | 1426 | return; |
| 1427 | 1427 | } |
| 1428 | - cgi_csrf_verify(1); | |
| 1428 | + cgi_csrf_verify(); | |
| 1429 | 1429 | fpid = symbolic_name_to_rid(zFpid, "f"); |
| 1430 | 1430 | if( fpid<=0 ){ |
| 1431 | 1431 | webpage_error("Missing or invalid fpid query parameter"); |
| 1432 | 1432 | } |
| 1433 | 1433 | fClose = sqlite3_strglob("*_close*", g.zPath)==0; |
| @@ -1842,14 +1842,13 @@ | ||
| 1842 | 1842 | } |
| 1843 | 1843 | } |
| 1844 | 1844 | |
| 1845 | 1845 | @ <h2>Settings</h2> |
| 1846 | 1846 | @ <p>Configuration settings specific to the forum.</p> |
| 1847 | - if( P("submit") && cgi_csrf_safe(1) ){ | |
| 1847 | + if( P("submit") && cgi_csrf_safe(2) ){ | |
| 1848 | 1848 | int i = 0; |
| 1849 | 1849 | const char *zSetting; |
| 1850 | - login_verify_csrf_secret(); | |
| 1851 | 1850 | db_begin_transaction(); |
| 1852 | 1851 | while( (zSetting = zSettingsBool[i++]) ){ |
| 1853 | 1852 | const char *z = P(zSetting); |
| 1854 | 1853 | if( !z || !z[0] ) z = "off"; |
| 1855 | 1854 | db_set(zSetting/*works-like:"x"*/, z, 0); |
| 1856 | 1855 |
| --- src/forum.c | |
| +++ src/forum.c | |
| @@ -1423,11 +1423,11 @@ | |
| 1423 | login_check_credentials(); |
| 1424 | if( forumpost_may_close()==0 ){ |
| 1425 | login_needed(g.anon.Admin); |
| 1426 | return; |
| 1427 | } |
| 1428 | cgi_csrf_verify(1); |
| 1429 | fpid = symbolic_name_to_rid(zFpid, "f"); |
| 1430 | if( fpid<=0 ){ |
| 1431 | webpage_error("Missing or invalid fpid query parameter"); |
| 1432 | } |
| 1433 | fClose = sqlite3_strglob("*_close*", g.zPath)==0; |
| @@ -1842,14 +1842,13 @@ | |
| 1842 | } |
| 1843 | } |
| 1844 | |
| 1845 | @ <h2>Settings</h2> |
| 1846 | @ <p>Configuration settings specific to the forum.</p> |
| 1847 | if( P("submit") && cgi_csrf_safe(1) ){ |
| 1848 | int i = 0; |
| 1849 | const char *zSetting; |
| 1850 | login_verify_csrf_secret(); |
| 1851 | db_begin_transaction(); |
| 1852 | while( (zSetting = zSettingsBool[i++]) ){ |
| 1853 | const char *z = P(zSetting); |
| 1854 | if( !z || !z[0] ) z = "off"; |
| 1855 | db_set(zSetting/*works-like:"x"*/, z, 0); |
| 1856 |
| --- src/forum.c | |
| +++ src/forum.c | |
| @@ -1423,11 +1423,11 @@ | |
| 1423 | login_check_credentials(); |
| 1424 | if( forumpost_may_close()==0 ){ |
| 1425 | login_needed(g.anon.Admin); |
| 1426 | return; |
| 1427 | } |
| 1428 | cgi_csrf_verify(); |
| 1429 | fpid = symbolic_name_to_rid(zFpid, "f"); |
| 1430 | if( fpid<=0 ){ |
| 1431 | webpage_error("Missing or invalid fpid query parameter"); |
| 1432 | } |
| 1433 | fClose = sqlite3_strglob("*_close*", g.zPath)==0; |
| @@ -1842,14 +1842,13 @@ | |
| 1842 | } |
| 1843 | } |
| 1844 | |
| 1845 | @ <h2>Settings</h2> |
| 1846 | @ <p>Configuration settings specific to the forum.</p> |
| 1847 | if( P("submit") && cgi_csrf_safe(2) ){ |
| 1848 | int i = 0; |
| 1849 | const char *zSetting; |
| 1850 | db_begin_transaction(); |
| 1851 | while( (zSetting = zSettingsBool[i++]) ){ |
| 1852 | const char *z = P(zSetting); |
| 1853 | if( !z || !z[0] ) z = "off"; |
| 1854 | db_set(zSetting/*works-like:"x"*/, z, 0); |
| 1855 |
+1
-3
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -3213,15 +3213,14 @@ | ||
| 3213 | 3213 | zNewTag = PDT("tagname",""); |
| 3214 | 3214 | zNewBrFlag = P("newbr") ? " checked" : ""; |
| 3215 | 3215 | zNewBranch = PDT("brname",""); |
| 3216 | 3216 | zCloseFlag = P("close") ? " checked" : ""; |
| 3217 | 3217 | zHideFlag = P("hide") ? " checked" : ""; |
| 3218 | - if( P("apply") && cgi_csrf_safe(1) ){ | |
| 3218 | + if( P("apply") && cgi_csrf_safe(2) ){ | |
| 3219 | 3219 | Blob ctrl; |
| 3220 | 3220 | char *zNow; |
| 3221 | 3221 | |
| 3222 | - login_verify_csrf_secret(); | |
| 3223 | 3222 | blob_zero(&ctrl); |
| 3224 | 3223 | zNow = date_in_standard_format(zChngTime ? zChngTime : "now"); |
| 3225 | 3224 | blob_appendf(&ctrl, "D %s\n", zNow); |
| 3226 | 3225 | init_newtags(); |
| 3227 | 3226 | if( zNewColorFlag[0] |
| @@ -3300,11 +3299,10 @@ | ||
| 3300 | 3299 | blob_reset(&suffix); |
| 3301 | 3300 | } |
| 3302 | 3301 | @ <p>Make changes to attributes of check-in |
| 3303 | 3302 | @ [%z(href("%R/ci/%!S",zUuid))%s(zUuid)</a>]:</p> |
| 3304 | 3303 | form_begin(0, "%R/ci_edit"); |
| 3305 | - login_insert_csrf_secret(); | |
| 3306 | 3304 | @ <div><input type="hidden" name="r" value="%s(zUuid)"> |
| 3307 | 3305 | @ <table border="0" cellspacing="10"> |
| 3308 | 3306 | |
| 3309 | 3307 | @ <tr><th align="right" valign="top">User:</th> |
| 3310 | 3308 | @ <td valign="top"> |
| 3311 | 3309 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -3213,15 +3213,14 @@ | |
| 3213 | zNewTag = PDT("tagname",""); |
| 3214 | zNewBrFlag = P("newbr") ? " checked" : ""; |
| 3215 | zNewBranch = PDT("brname",""); |
| 3216 | zCloseFlag = P("close") ? " checked" : ""; |
| 3217 | zHideFlag = P("hide") ? " checked" : ""; |
| 3218 | if( P("apply") && cgi_csrf_safe(1) ){ |
| 3219 | Blob ctrl; |
| 3220 | char *zNow; |
| 3221 | |
| 3222 | login_verify_csrf_secret(); |
| 3223 | blob_zero(&ctrl); |
| 3224 | zNow = date_in_standard_format(zChngTime ? zChngTime : "now"); |
| 3225 | blob_appendf(&ctrl, "D %s\n", zNow); |
| 3226 | init_newtags(); |
| 3227 | if( zNewColorFlag[0] |
| @@ -3300,11 +3299,10 @@ | |
| 3300 | blob_reset(&suffix); |
| 3301 | } |
| 3302 | @ <p>Make changes to attributes of check-in |
| 3303 | @ [%z(href("%R/ci/%!S",zUuid))%s(zUuid)</a>]:</p> |
| 3304 | form_begin(0, "%R/ci_edit"); |
| 3305 | login_insert_csrf_secret(); |
| 3306 | @ <div><input type="hidden" name="r" value="%s(zUuid)"> |
| 3307 | @ <table border="0" cellspacing="10"> |
| 3308 | |
| 3309 | @ <tr><th align="right" valign="top">User:</th> |
| 3310 | @ <td valign="top"> |
| 3311 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -3213,15 +3213,14 @@ | |
| 3213 | zNewTag = PDT("tagname",""); |
| 3214 | zNewBrFlag = P("newbr") ? " checked" : ""; |
| 3215 | zNewBranch = PDT("brname",""); |
| 3216 | zCloseFlag = P("close") ? " checked" : ""; |
| 3217 | zHideFlag = P("hide") ? " checked" : ""; |
| 3218 | if( P("apply") && cgi_csrf_safe(2) ){ |
| 3219 | Blob ctrl; |
| 3220 | char *zNow; |
| 3221 | |
| 3222 | blob_zero(&ctrl); |
| 3223 | zNow = date_in_standard_format(zChngTime ? zChngTime : "now"); |
| 3224 | blob_appendf(&ctrl, "D %s\n", zNow); |
| 3225 | init_newtags(); |
| 3226 | if( zNewColorFlag[0] |
| @@ -3300,11 +3299,10 @@ | |
| 3299 | blob_reset(&suffix); |
| 3300 | } |
| 3301 | @ <p>Make changes to attributes of check-in |
| 3302 | @ [%z(href("%R/ci/%!S",zUuid))%s(zUuid)</a>]:</p> |
| 3303 | form_begin(0, "%R/ci_edit"); |
| 3304 | @ <div><input type="hidden" name="r" value="%s(zUuid)"> |
| 3305 | @ <table border="0" cellspacing="10"> |
| 3306 | |
| 3307 | @ <tr><th align="right" valign="top">User:</th> |
| 3308 | @ <td valign="top"> |
| 3309 |
+2
-17
| --- src/login.c | ||
| +++ src/login.c | ||
| @@ -583,11 +583,11 @@ | ||
| 583 | 583 | constant_time_cmp_function, 0, 0); |
| 584 | 584 | zUsername = P("u"); |
| 585 | 585 | zPasswd = P("p"); |
| 586 | 586 | anonFlag = g.zLogin==0 && PB("anon"); |
| 587 | 587 | /* Handle log-out requests */ |
| 588 | - if( P("out") ){ | |
| 588 | + if( P("out") && cgi_csrf_safe(2) ){ | |
| 589 | 589 | login_clear_login_data(); |
| 590 | 590 | redirect_to_g(); |
| 591 | 591 | return; |
| 592 | 592 | } |
| 593 | 593 | |
| @@ -598,10 +598,11 @@ | ||
| 598 | 598 | } |
| 599 | 599 | |
| 600 | 600 | /* Deal with password-change requests */ |
| 601 | 601 | if( g.perm.Password && zPasswd |
| 602 | 602 | && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 |
| 603 | + && cgi_csrf_safe(2) | |
| 603 | 604 | ){ |
| 604 | 605 | /* If there is not a "real" login, we cannot change any password. */ |
| 605 | 606 | if( g.zLogin ){ |
| 606 | 607 | /* The user requests a password change */ |
| 607 | 608 | zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0); |
| @@ -1805,26 +1806,10 @@ | ||
| 1805 | 1806 | */ |
| 1806 | 1807 | void login_insert_csrf_secret(void){ |
| 1807 | 1808 | @ <input type="hidden" name="csrf" value="%s(g.zCsrfToken)"> |
| 1808 | 1809 | } |
| 1809 | 1810 | |
| 1810 | -/* | |
| 1811 | -** Before using the results of a form, first call this routine to verify | |
| 1812 | -** that this Anti-CSRF token is present and is valid. If the Anti-CSRF token | |
| 1813 | -** is missing or is incorrect, that indicates a cross-site scripting attack. | |
| 1814 | -** If the event of an attack is detected, an error message is generated and | |
| 1815 | -** all further processing is aborted. | |
| 1816 | -*/ | |
| 1817 | -void login_verify_csrf_secret(void){ | |
| 1818 | - if( g.okCsrf ) return; | |
| 1819 | - if( fossil_strcmp(P("csrf"), g.zCsrfToken)==0 ){ | |
| 1820 | - g.okCsrf = 1; | |
| 1821 | - return; | |
| 1822 | - } | |
| 1823 | - fossil_fatal("Cross-site request forgery attempt"); | |
| 1824 | -} | |
| 1825 | - | |
| 1826 | 1811 | /* |
| 1827 | 1812 | ** Check to see if the candidate username zUserID is already used. |
| 1828 | 1813 | ** Return 1 if it is already in use. Return 0 if the name is |
| 1829 | 1814 | ** available for a self-registeration. |
| 1830 | 1815 | */ |
| 1831 | 1816 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -583,11 +583,11 @@ | |
| 583 | constant_time_cmp_function, 0, 0); |
| 584 | zUsername = P("u"); |
| 585 | zPasswd = P("p"); |
| 586 | anonFlag = g.zLogin==0 && PB("anon"); |
| 587 | /* Handle log-out requests */ |
| 588 | if( P("out") ){ |
| 589 | login_clear_login_data(); |
| 590 | redirect_to_g(); |
| 591 | return; |
| 592 | } |
| 593 | |
| @@ -598,10 +598,11 @@ | |
| 598 | } |
| 599 | |
| 600 | /* Deal with password-change requests */ |
| 601 | if( g.perm.Password && zPasswd |
| 602 | && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 |
| 603 | ){ |
| 604 | /* If there is not a "real" login, we cannot change any password. */ |
| 605 | if( g.zLogin ){ |
| 606 | /* The user requests a password change */ |
| 607 | zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0); |
| @@ -1805,26 +1806,10 @@ | |
| 1805 | */ |
| 1806 | void login_insert_csrf_secret(void){ |
| 1807 | @ <input type="hidden" name="csrf" value="%s(g.zCsrfToken)"> |
| 1808 | } |
| 1809 | |
| 1810 | /* |
| 1811 | ** Before using the results of a form, first call this routine to verify |
| 1812 | ** that this Anti-CSRF token is present and is valid. If the Anti-CSRF token |
| 1813 | ** is missing or is incorrect, that indicates a cross-site scripting attack. |
| 1814 | ** If the event of an attack is detected, an error message is generated and |
| 1815 | ** all further processing is aborted. |
| 1816 | */ |
| 1817 | void login_verify_csrf_secret(void){ |
| 1818 | if( g.okCsrf ) return; |
| 1819 | if( fossil_strcmp(P("csrf"), g.zCsrfToken)==0 ){ |
| 1820 | g.okCsrf = 1; |
| 1821 | return; |
| 1822 | } |
| 1823 | fossil_fatal("Cross-site request forgery attempt"); |
| 1824 | } |
| 1825 | |
| 1826 | /* |
| 1827 | ** Check to see if the candidate username zUserID is already used. |
| 1828 | ** Return 1 if it is already in use. Return 0 if the name is |
| 1829 | ** available for a self-registeration. |
| 1830 | */ |
| 1831 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -583,11 +583,11 @@ | |
| 583 | constant_time_cmp_function, 0, 0); |
| 584 | zUsername = P("u"); |
| 585 | zPasswd = P("p"); |
| 586 | anonFlag = g.zLogin==0 && PB("anon"); |
| 587 | /* Handle log-out requests */ |
| 588 | if( P("out") && cgi_csrf_safe(2) ){ |
| 589 | login_clear_login_data(); |
| 590 | redirect_to_g(); |
| 591 | return; |
| 592 | } |
| 593 | |
| @@ -598,10 +598,11 @@ | |
| 598 | } |
| 599 | |
| 600 | /* Deal with password-change requests */ |
| 601 | if( g.perm.Password && zPasswd |
| 602 | && (zNew1 = P("n1"))!=0 && (zNew2 = P("n2"))!=0 |
| 603 | && cgi_csrf_safe(2) |
| 604 | ){ |
| 605 | /* If there is not a "real" login, we cannot change any password. */ |
| 606 | if( g.zLogin ){ |
| 607 | /* The user requests a password change */ |
| 608 | zSha1Pw = sha1_shared_secret(zPasswd, g.zLogin, 0); |
| @@ -1805,26 +1806,10 @@ | |
| 1806 | */ |
| 1807 | void login_insert_csrf_secret(void){ |
| 1808 | @ <input type="hidden" name="csrf" value="%s(g.zCsrfToken)"> |
| 1809 | } |
| 1810 | |
| 1811 | /* |
| 1812 | ** Check to see if the candidate username zUserID is already used. |
| 1813 | ** Return 1 if it is already in use. Return 0 if the name is |
| 1814 | ** available for a self-registeration. |
| 1815 | */ |
| 1816 |
+5
-1
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -257,11 +257,15 @@ | ||
| 257 | 257 | struct TclContext tcl; |
| 258 | 258 | #endif |
| 259 | 259 | |
| 260 | 260 | /* For defense against Cross-site Request Forgery attacks */ |
| 261 | 261 | char zCsrfToken[12]; /* Value of the anti-CSRF token */ |
| 262 | - int okCsrf; /* Anti-CSRF token is present and valid */ | |
| 262 | + int okCsrf; /* -1: unsafe | |
| 263 | + ** 0: unknown | |
| 264 | + ** 1: same origin | |
| 265 | + ** 2: same origin + is POST | |
| 266 | + ** 3: same origin, POST, valid csrf token */ | |
| 263 | 267 | |
| 264 | 268 | int parseCnt[10]; /* Counts of artifacts parsed */ |
| 265 | 269 | FILE *fDebug; /* Write debug information here, if the file exists */ |
| 266 | 270 | #ifdef FOSSIL_ENABLE_TH1_HOOKS |
| 267 | 271 | int fNoThHook; /* Disable all TH1 command/webpage hooks */ |
| 268 | 272 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -257,11 +257,15 @@ | |
| 257 | struct TclContext tcl; |
| 258 | #endif |
| 259 | |
| 260 | /* For defense against Cross-site Request Forgery attacks */ |
| 261 | char zCsrfToken[12]; /* Value of the anti-CSRF token */ |
| 262 | int okCsrf; /* Anti-CSRF token is present and valid */ |
| 263 | |
| 264 | int parseCnt[10]; /* Counts of artifacts parsed */ |
| 265 | FILE *fDebug; /* Write debug information here, if the file exists */ |
| 266 | #ifdef FOSSIL_ENABLE_TH1_HOOKS |
| 267 | int fNoThHook; /* Disable all TH1 command/webpage hooks */ |
| 268 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -257,11 +257,15 @@ | |
| 257 | struct TclContext tcl; |
| 258 | #endif |
| 259 | |
| 260 | /* For defense against Cross-site Request Forgery attacks */ |
| 261 | char zCsrfToken[12]; /* Value of the anti-CSRF token */ |
| 262 | int okCsrf; /* -1: unsafe |
| 263 | ** 0: unknown |
| 264 | ** 1: same origin |
| 265 | ** 2: same origin + is POST |
| 266 | ** 3: same origin, POST, valid csrf token */ |
| 267 | |
| 268 | int parseCnt[10]; /* Counts of artifacts parsed */ |
| 269 | FILE *fDebug; /* Write debug information here, if the file exists */ |
| 270 | #ifdef FOSSIL_ENABLE_TH1_HOOKS |
| 271 | int fNoThHook; /* Disable all TH1 command/webpage hooks */ |
| 272 |
+3
-5
| --- src/report.c | ||
| +++ src/report.c | ||
| @@ -471,16 +471,15 @@ | ||
| 471 | 471 | zClrKey = trim_string(PD("k","")); |
| 472 | 472 | zDesc = trim_string(PD("d","")); |
| 473 | 473 | zMimetype = P("m"); |
| 474 | 474 | zTag = P("x"); |
| 475 | 475 | report_update_reportfmt_table(); |
| 476 | - if( rn>0 && P("del2") ){ | |
| 477 | - login_verify_csrf_secret(); | |
| 476 | + if( rn>0 && P("del2") && cgi_csrf_safe(2) ){ | |
| 478 | 477 | db_multi_exec("DELETE FROM reportfmt WHERE rn=%d", rn); |
| 479 | 478 | cgi_redirect("reportlist"); |
| 480 | 479 | return; |
| 481 | - }else if( rn>0 && P("del1") ){ | |
| 480 | + }else if( rn>0 && P("del1") && cgi_csrf_safe(2) ){ | |
| 482 | 481 | zTitle = db_text(0, "SELECT title FROM reportfmt " |
| 483 | 482 | "WHERE rn=%d", rn); |
| 484 | 483 | if( zTitle==0 ) cgi_redirect("reportlist"); |
| 485 | 484 | |
| 486 | 485 | style_header("Are You Sure?"); |
| @@ -514,12 +513,11 @@ | ||
| 514 | 513 | && db_exists("SELECT 1 FROM reportfmt WHERE title=%Q and rn<>%d", |
| 515 | 514 | zTitle, rn) |
| 516 | 515 | ){ |
| 517 | 516 | zErr = mprintf("There is already another report named \"%h\"", zTitle); |
| 518 | 517 | } |
| 519 | - if( zErr==0 ){ | |
| 520 | - login_verify_csrf_secret(); | |
| 518 | + if( zErr==0 && cgi_csrf_safe(2) ){ | |
| 521 | 519 | if( zTag && zTag[0]==0 ) zTag = 0; |
| 522 | 520 | if( zDesc && zDesc[0]==0 ){ zDesc = 0; zMimetype = 0; } |
| 523 | 521 | if( zMimetype && zMimetype[0]==0 ){ zDesc = 0; zMimetype = 0; } |
| 524 | 522 | if( rn>0 ){ |
| 525 | 523 | db_multi_exec( |
| 526 | 524 |
| --- src/report.c | |
| +++ src/report.c | |
| @@ -471,16 +471,15 @@ | |
| 471 | zClrKey = trim_string(PD("k","")); |
| 472 | zDesc = trim_string(PD("d","")); |
| 473 | zMimetype = P("m"); |
| 474 | zTag = P("x"); |
| 475 | report_update_reportfmt_table(); |
| 476 | if( rn>0 && P("del2") ){ |
| 477 | login_verify_csrf_secret(); |
| 478 | db_multi_exec("DELETE FROM reportfmt WHERE rn=%d", rn); |
| 479 | cgi_redirect("reportlist"); |
| 480 | return; |
| 481 | }else if( rn>0 && P("del1") ){ |
| 482 | zTitle = db_text(0, "SELECT title FROM reportfmt " |
| 483 | "WHERE rn=%d", rn); |
| 484 | if( zTitle==0 ) cgi_redirect("reportlist"); |
| 485 | |
| 486 | style_header("Are You Sure?"); |
| @@ -514,12 +513,11 @@ | |
| 514 | && db_exists("SELECT 1 FROM reportfmt WHERE title=%Q and rn<>%d", |
| 515 | zTitle, rn) |
| 516 | ){ |
| 517 | zErr = mprintf("There is already another report named \"%h\"", zTitle); |
| 518 | } |
| 519 | if( zErr==0 ){ |
| 520 | login_verify_csrf_secret(); |
| 521 | if( zTag && zTag[0]==0 ) zTag = 0; |
| 522 | if( zDesc && zDesc[0]==0 ){ zDesc = 0; zMimetype = 0; } |
| 523 | if( zMimetype && zMimetype[0]==0 ){ zDesc = 0; zMimetype = 0; } |
| 524 | if( rn>0 ){ |
| 525 | db_multi_exec( |
| 526 |
| --- src/report.c | |
| +++ src/report.c | |
| @@ -471,16 +471,15 @@ | |
| 471 | zClrKey = trim_string(PD("k","")); |
| 472 | zDesc = trim_string(PD("d","")); |
| 473 | zMimetype = P("m"); |
| 474 | zTag = P("x"); |
| 475 | report_update_reportfmt_table(); |
| 476 | if( rn>0 && P("del2") && cgi_csrf_safe(2) ){ |
| 477 | db_multi_exec("DELETE FROM reportfmt WHERE rn=%d", rn); |
| 478 | cgi_redirect("reportlist"); |
| 479 | return; |
| 480 | }else if( rn>0 && P("del1") && cgi_csrf_safe(2) ){ |
| 481 | zTitle = db_text(0, "SELECT title FROM reportfmt " |
| 482 | "WHERE rn=%d", rn); |
| 483 | if( zTitle==0 ) cgi_redirect("reportlist"); |
| 484 | |
| 485 | style_header("Are You Sure?"); |
| @@ -514,12 +513,11 @@ | |
| 513 | && db_exists("SELECT 1 FROM reportfmt WHERE title=%Q and rn<>%d", |
| 514 | zTitle, rn) |
| 515 | ){ |
| 516 | zErr = mprintf("There is already another report named \"%h\"", zTitle); |
| 517 | } |
| 518 | if( zErr==0 && cgi_csrf_safe(2) ){ |
| 519 | if( zTag && zTag[0]==0 ) zTag = 0; |
| 520 | if( zDesc && zDesc[0]==0 ){ zDesc = 0; zMimetype = 0; } |
| 521 | if( zMimetype && zMimetype[0]==0 ){ zDesc = 0; zMimetype = 0; } |
| 522 | if( rn>0 ){ |
| 523 | db_multi_exec( |
| 524 |
+8
-16
| --- src/setup.c | ||
| +++ src/setup.c | ||
| @@ -202,12 +202,11 @@ | ||
| 202 | 202 | if( zQ==0 && !disabled && P("submit") ){ |
| 203 | 203 | zQ = "off"; |
| 204 | 204 | } |
| 205 | 205 | if( zQ ){ |
| 206 | 206 | int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ); |
| 207 | - if( iQ!=iVal ){ | |
| 208 | - login_verify_csrf_secret(); | |
| 207 | + if( iQ!=iVal && cgi_csrf_safe(2) ){ | |
| 209 | 208 | db_protect_only(PROTECT_NONE); |
| 210 | 209 | db_set(zVar/*works-like:"x"*/, iQ ? "1" : "0", 0); |
| 211 | 210 | db_protect_pop(); |
| 212 | 211 | setup_incr_cfgcnt(); |
| 213 | 212 | admin_log("Set option [%q] to [%q].", |
| @@ -237,13 +236,12 @@ | ||
| 237 | 236 | const char *zDflt, /* Default value if CONFIG table entry does not exist */ |
| 238 | 237 | int disabled /* 1 if disabled */ |
| 239 | 238 | ){ |
| 240 | 239 | const char *zVal = db_get(zVar, zDflt); |
| 241 | 240 | const char *zQ = P(zQParm); |
| 242 | - if( zQ && fossil_strcmp(zQ,zVal)!=0 ){ | |
| 241 | + if( zQ && fossil_strcmp(zQ,zVal)!=0 && cgi_csrf_safe(2) ){ | |
| 243 | 242 | const int nZQ = (int)strlen(zQ); |
| 244 | - login_verify_csrf_secret(); | |
| 245 | 243 | setup_incr_cfgcnt(); |
| 246 | 244 | db_protect_only(PROTECT_NONE); |
| 247 | 245 | db_set(zVar/*works-like:"x"*/, zQ, 0); |
| 248 | 246 | db_protect_pop(); |
| 249 | 247 | admin_log("Set entry_attribute %Q to: %.*s%s", |
| @@ -270,13 +268,12 @@ | ||
| 270 | 268 | const char *zDflt, /* Default value if CONFIG table entry does not exist */ |
| 271 | 269 | int disabled /* 1 if the textarea should not be editable */ |
| 272 | 270 | ){ |
| 273 | 271 | const char *z = db_get(zVar, zDflt); |
| 274 | 272 | const char *zQ = P(zQP); |
| 275 | - if( zQ && !disabled && fossil_strcmp(zQ,z)!=0){ | |
| 273 | + if( zQ && !disabled && fossil_strcmp(zQ,z)!=0 && cgi_csrf_safe(2) ){ | |
| 276 | 274 | const int nZQ = (int)strlen(zQ); |
| 277 | - login_verify_csrf_secret(); | |
| 278 | 275 | db_protect_only(PROTECT_NONE); |
| 279 | 276 | db_set(zVar/*works-like:"x"*/, zQ, 0); |
| 280 | 277 | db_protect_pop(); |
| 281 | 278 | setup_incr_cfgcnt(); |
| 282 | 279 | admin_log("Set textarea_attribute %Q to: %.*s%s", |
| @@ -309,13 +306,12 @@ | ||
| 309 | 306 | const char *const *azChoice /* Choices in pairs (VAR value, Display) */ |
| 310 | 307 | ){ |
| 311 | 308 | const char *z = db_get(zVar, zDflt); |
| 312 | 309 | const char *zQ = P(zQP); |
| 313 | 310 | int i; |
| 314 | - if( zQ && fossil_strcmp(zQ,z)!=0){ | |
| 311 | + if( zQ && fossil_strcmp(zQ,z)!=0 && cgi_csrf_safe(2) ){ | |
| 315 | 312 | const int nZQ = (int)strlen(zQ); |
| 316 | - login_verify_csrf_secret(); | |
| 317 | 313 | db_unprotect(PROTECT_ALL); |
| 318 | 314 | db_set(zVar/*works-like:"x"*/, zQ, 0); |
| 319 | 315 | setup_incr_cfgcnt(); |
| 320 | 316 | db_protect_pop(); |
| 321 | 317 | admin_log("Set multiple_choice_attribute %Q to: %.*s%s", |
| @@ -1822,19 +1818,18 @@ | ||
| 1822 | 1818 | go = 1; |
| 1823 | 1819 | }else if( P("tablelist") ){ |
| 1824 | 1820 | zQ = sqlite3_mprintf("SELECT*FROM pragma_table_list ORDER BY schema, name"); |
| 1825 | 1821 | go = 1; |
| 1826 | 1822 | } |
| 1827 | - if( go ){ | |
| 1823 | + if( go && cgi_csrf_safe(2) ){ | |
| 1828 | 1824 | sqlite3_stmt *pStmt; |
| 1829 | 1825 | int rc; |
| 1830 | 1826 | const char *zTail; |
| 1831 | 1827 | int nCol; |
| 1832 | 1828 | int nRow = 0; |
| 1833 | 1829 | int i; |
| 1834 | 1830 | @ <hr> |
| 1835 | - login_verify_csrf_secret(); | |
| 1836 | 1831 | sqlite3_set_authorizer(g.db, raw_sql_query_authorizer, 0); |
| 1837 | 1832 | search_sql_setup(g.db); |
| 1838 | 1833 | rc = sqlite3_prepare_v2(g.db, zQ, -1, &pStmt, &zTail); |
| 1839 | 1834 | if( rc!=SQLITE_OK ){ |
| 1840 | 1835 | @ <div class="generalError">%h(sqlite3_errmsg(g.db))</div> |
| @@ -1913,22 +1908,20 @@ | ||
| 1913 | 1908 | style_header("Raw TH1 Commands"); |
| 1914 | 1909 | @ <p><b>Caution:</b> There are no restrictions on the TH1 that can be |
| 1915 | 1910 | @ run by this page. If Tcl integration was enabled at compile-time and |
| 1916 | 1911 | @ the "tcl" setting is enabled, Tcl commands may be run as well.</p> |
| 1917 | 1912 | @ |
| 1918 | - @ <form method="post" action="%R/admin_th1"> | |
| 1919 | - login_insert_csrf_secret(); | |
| 1913 | + form_begin(0, "%R/admin_th1"); | |
| 1920 | 1914 | @ TH1:<br> |
| 1921 | 1915 | @ <textarea name="q" rows="5" cols="80">%h(zQ)</textarea><br> |
| 1922 | 1916 | @ <input type="submit" name="go" value="Run TH1"> |
| 1923 | 1917 | @ </form> |
| 1924 | - if( go ){ | |
| 1918 | + if( go && cgi_csrf_safe(2) ){ | |
| 1925 | 1919 | const char *zR; |
| 1926 | 1920 | int rc; |
| 1927 | 1921 | int n; |
| 1928 | 1922 | @ <hr> |
| 1929 | - login_verify_csrf_secret(); | |
| 1930 | 1923 | rc = Th_Eval(g.interp, 0, zQ, -1); |
| 1931 | 1924 | zR = Th_GetResult(g.interp, &n); |
| 1932 | 1925 | if( rc==TH_OK ){ |
| 1933 | 1926 | @ <pre class="th1result">%h(zR)</pre> |
| 1934 | 1927 | }else{ |
| @@ -2173,17 +2166,16 @@ | ||
| 2173 | 2166 | login_needed(0); |
| 2174 | 2167 | return; |
| 2175 | 2168 | } |
| 2176 | 2169 | style_set_current_feature("setup"); |
| 2177 | 2170 | style_header("URL Alias Configuration"); |
| 2178 | - if( P("submit")!=0 ){ | |
| 2171 | + if( P("submit")!=0 && cgi_csrf_safe(2) ){ | |
| 2179 | 2172 | Blob token; |
| 2180 | 2173 | Blob sql; |
| 2181 | 2174 | const char *zNewName; |
| 2182 | 2175 | const char *zValue; |
| 2183 | 2176 | char zCnt[10]; |
| 2184 | - login_verify_csrf_secret(); | |
| 2185 | 2177 | blob_init(&namelist, PD("namelist",""), -1); |
| 2186 | 2178 | blob_init(&sql, 0, 0); |
| 2187 | 2179 | while( blob_token(&namelist, &token) ){ |
| 2188 | 2180 | const char *zOldName = blob_str(&token); |
| 2189 | 2181 | sqlite3_snprintf(sizeof(zCnt), zCnt, "n%d", cnt); |
| 2190 | 2182 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -202,12 +202,11 @@ | |
| 202 | if( zQ==0 && !disabled && P("submit") ){ |
| 203 | zQ = "off"; |
| 204 | } |
| 205 | if( zQ ){ |
| 206 | int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ); |
| 207 | if( iQ!=iVal ){ |
| 208 | login_verify_csrf_secret(); |
| 209 | db_protect_only(PROTECT_NONE); |
| 210 | db_set(zVar/*works-like:"x"*/, iQ ? "1" : "0", 0); |
| 211 | db_protect_pop(); |
| 212 | setup_incr_cfgcnt(); |
| 213 | admin_log("Set option [%q] to [%q].", |
| @@ -237,13 +236,12 @@ | |
| 237 | const char *zDflt, /* Default value if CONFIG table entry does not exist */ |
| 238 | int disabled /* 1 if disabled */ |
| 239 | ){ |
| 240 | const char *zVal = db_get(zVar, zDflt); |
| 241 | const char *zQ = P(zQParm); |
| 242 | if( zQ && fossil_strcmp(zQ,zVal)!=0 ){ |
| 243 | const int nZQ = (int)strlen(zQ); |
| 244 | login_verify_csrf_secret(); |
| 245 | setup_incr_cfgcnt(); |
| 246 | db_protect_only(PROTECT_NONE); |
| 247 | db_set(zVar/*works-like:"x"*/, zQ, 0); |
| 248 | db_protect_pop(); |
| 249 | admin_log("Set entry_attribute %Q to: %.*s%s", |
| @@ -270,13 +268,12 @@ | |
| 270 | const char *zDflt, /* Default value if CONFIG table entry does not exist */ |
| 271 | int disabled /* 1 if the textarea should not be editable */ |
| 272 | ){ |
| 273 | const char *z = db_get(zVar, zDflt); |
| 274 | const char *zQ = P(zQP); |
| 275 | if( zQ && !disabled && fossil_strcmp(zQ,z)!=0){ |
| 276 | const int nZQ = (int)strlen(zQ); |
| 277 | login_verify_csrf_secret(); |
| 278 | db_protect_only(PROTECT_NONE); |
| 279 | db_set(zVar/*works-like:"x"*/, zQ, 0); |
| 280 | db_protect_pop(); |
| 281 | setup_incr_cfgcnt(); |
| 282 | admin_log("Set textarea_attribute %Q to: %.*s%s", |
| @@ -309,13 +306,12 @@ | |
| 309 | const char *const *azChoice /* Choices in pairs (VAR value, Display) */ |
| 310 | ){ |
| 311 | const char *z = db_get(zVar, zDflt); |
| 312 | const char *zQ = P(zQP); |
| 313 | int i; |
| 314 | if( zQ && fossil_strcmp(zQ,z)!=0){ |
| 315 | const int nZQ = (int)strlen(zQ); |
| 316 | login_verify_csrf_secret(); |
| 317 | db_unprotect(PROTECT_ALL); |
| 318 | db_set(zVar/*works-like:"x"*/, zQ, 0); |
| 319 | setup_incr_cfgcnt(); |
| 320 | db_protect_pop(); |
| 321 | admin_log("Set multiple_choice_attribute %Q to: %.*s%s", |
| @@ -1822,19 +1818,18 @@ | |
| 1822 | go = 1; |
| 1823 | }else if( P("tablelist") ){ |
| 1824 | zQ = sqlite3_mprintf("SELECT*FROM pragma_table_list ORDER BY schema, name"); |
| 1825 | go = 1; |
| 1826 | } |
| 1827 | if( go ){ |
| 1828 | sqlite3_stmt *pStmt; |
| 1829 | int rc; |
| 1830 | const char *zTail; |
| 1831 | int nCol; |
| 1832 | int nRow = 0; |
| 1833 | int i; |
| 1834 | @ <hr> |
| 1835 | login_verify_csrf_secret(); |
| 1836 | sqlite3_set_authorizer(g.db, raw_sql_query_authorizer, 0); |
| 1837 | search_sql_setup(g.db); |
| 1838 | rc = sqlite3_prepare_v2(g.db, zQ, -1, &pStmt, &zTail); |
| 1839 | if( rc!=SQLITE_OK ){ |
| 1840 | @ <div class="generalError">%h(sqlite3_errmsg(g.db))</div> |
| @@ -1913,22 +1908,20 @@ | |
| 1913 | style_header("Raw TH1 Commands"); |
| 1914 | @ <p><b>Caution:</b> There are no restrictions on the TH1 that can be |
| 1915 | @ run by this page. If Tcl integration was enabled at compile-time and |
| 1916 | @ the "tcl" setting is enabled, Tcl commands may be run as well.</p> |
| 1917 | @ |
| 1918 | @ <form method="post" action="%R/admin_th1"> |
| 1919 | login_insert_csrf_secret(); |
| 1920 | @ TH1:<br> |
| 1921 | @ <textarea name="q" rows="5" cols="80">%h(zQ)</textarea><br> |
| 1922 | @ <input type="submit" name="go" value="Run TH1"> |
| 1923 | @ </form> |
| 1924 | if( go ){ |
| 1925 | const char *zR; |
| 1926 | int rc; |
| 1927 | int n; |
| 1928 | @ <hr> |
| 1929 | login_verify_csrf_secret(); |
| 1930 | rc = Th_Eval(g.interp, 0, zQ, -1); |
| 1931 | zR = Th_GetResult(g.interp, &n); |
| 1932 | if( rc==TH_OK ){ |
| 1933 | @ <pre class="th1result">%h(zR)</pre> |
| 1934 | }else{ |
| @@ -2173,17 +2166,16 @@ | |
| 2173 | login_needed(0); |
| 2174 | return; |
| 2175 | } |
| 2176 | style_set_current_feature("setup"); |
| 2177 | style_header("URL Alias Configuration"); |
| 2178 | if( P("submit")!=0 ){ |
| 2179 | Blob token; |
| 2180 | Blob sql; |
| 2181 | const char *zNewName; |
| 2182 | const char *zValue; |
| 2183 | char zCnt[10]; |
| 2184 | login_verify_csrf_secret(); |
| 2185 | blob_init(&namelist, PD("namelist",""), -1); |
| 2186 | blob_init(&sql, 0, 0); |
| 2187 | while( blob_token(&namelist, &token) ){ |
| 2188 | const char *zOldName = blob_str(&token); |
| 2189 | sqlite3_snprintf(sizeof(zCnt), zCnt, "n%d", cnt); |
| 2190 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -202,12 +202,11 @@ | |
| 202 | if( zQ==0 && !disabled && P("submit") ){ |
| 203 | zQ = "off"; |
| 204 | } |
| 205 | if( zQ ){ |
| 206 | int iQ = fossil_strcmp(zQ,"on")==0 || atoi(zQ); |
| 207 | if( iQ!=iVal && cgi_csrf_safe(2) ){ |
| 208 | db_protect_only(PROTECT_NONE); |
| 209 | db_set(zVar/*works-like:"x"*/, iQ ? "1" : "0", 0); |
| 210 | db_protect_pop(); |
| 211 | setup_incr_cfgcnt(); |
| 212 | admin_log("Set option [%q] to [%q].", |
| @@ -237,13 +236,12 @@ | |
| 236 | const char *zDflt, /* Default value if CONFIG table entry does not exist */ |
| 237 | int disabled /* 1 if disabled */ |
| 238 | ){ |
| 239 | const char *zVal = db_get(zVar, zDflt); |
| 240 | const char *zQ = P(zQParm); |
| 241 | if( zQ && fossil_strcmp(zQ,zVal)!=0 && cgi_csrf_safe(2) ){ |
| 242 | const int nZQ = (int)strlen(zQ); |
| 243 | setup_incr_cfgcnt(); |
| 244 | db_protect_only(PROTECT_NONE); |
| 245 | db_set(zVar/*works-like:"x"*/, zQ, 0); |
| 246 | db_protect_pop(); |
| 247 | admin_log("Set entry_attribute %Q to: %.*s%s", |
| @@ -270,13 +268,12 @@ | |
| 268 | const char *zDflt, /* Default value if CONFIG table entry does not exist */ |
| 269 | int disabled /* 1 if the textarea should not be editable */ |
| 270 | ){ |
| 271 | const char *z = db_get(zVar, zDflt); |
| 272 | const char *zQ = P(zQP); |
| 273 | if( zQ && !disabled && fossil_strcmp(zQ,z)!=0 && cgi_csrf_safe(2) ){ |
| 274 | const int nZQ = (int)strlen(zQ); |
| 275 | db_protect_only(PROTECT_NONE); |
| 276 | db_set(zVar/*works-like:"x"*/, zQ, 0); |
| 277 | db_protect_pop(); |
| 278 | setup_incr_cfgcnt(); |
| 279 | admin_log("Set textarea_attribute %Q to: %.*s%s", |
| @@ -309,13 +306,12 @@ | |
| 306 | const char *const *azChoice /* Choices in pairs (VAR value, Display) */ |
| 307 | ){ |
| 308 | const char *z = db_get(zVar, zDflt); |
| 309 | const char *zQ = P(zQP); |
| 310 | int i; |
| 311 | if( zQ && fossil_strcmp(zQ,z)!=0 && cgi_csrf_safe(2) ){ |
| 312 | const int nZQ = (int)strlen(zQ); |
| 313 | db_unprotect(PROTECT_ALL); |
| 314 | db_set(zVar/*works-like:"x"*/, zQ, 0); |
| 315 | setup_incr_cfgcnt(); |
| 316 | db_protect_pop(); |
| 317 | admin_log("Set multiple_choice_attribute %Q to: %.*s%s", |
| @@ -1822,19 +1818,18 @@ | |
| 1818 | go = 1; |
| 1819 | }else if( P("tablelist") ){ |
| 1820 | zQ = sqlite3_mprintf("SELECT*FROM pragma_table_list ORDER BY schema, name"); |
| 1821 | go = 1; |
| 1822 | } |
| 1823 | if( go && cgi_csrf_safe(2) ){ |
| 1824 | sqlite3_stmt *pStmt; |
| 1825 | int rc; |
| 1826 | const char *zTail; |
| 1827 | int nCol; |
| 1828 | int nRow = 0; |
| 1829 | int i; |
| 1830 | @ <hr> |
| 1831 | sqlite3_set_authorizer(g.db, raw_sql_query_authorizer, 0); |
| 1832 | search_sql_setup(g.db); |
| 1833 | rc = sqlite3_prepare_v2(g.db, zQ, -1, &pStmt, &zTail); |
| 1834 | if( rc!=SQLITE_OK ){ |
| 1835 | @ <div class="generalError">%h(sqlite3_errmsg(g.db))</div> |
| @@ -1913,22 +1908,20 @@ | |
| 1908 | style_header("Raw TH1 Commands"); |
| 1909 | @ <p><b>Caution:</b> There are no restrictions on the TH1 that can be |
| 1910 | @ run by this page. If Tcl integration was enabled at compile-time and |
| 1911 | @ the "tcl" setting is enabled, Tcl commands may be run as well.</p> |
| 1912 | @ |
| 1913 | form_begin(0, "%R/admin_th1"); |
| 1914 | @ TH1:<br> |
| 1915 | @ <textarea name="q" rows="5" cols="80">%h(zQ)</textarea><br> |
| 1916 | @ <input type="submit" name="go" value="Run TH1"> |
| 1917 | @ </form> |
| 1918 | if( go && cgi_csrf_safe(2) ){ |
| 1919 | const char *zR; |
| 1920 | int rc; |
| 1921 | int n; |
| 1922 | @ <hr> |
| 1923 | rc = Th_Eval(g.interp, 0, zQ, -1); |
| 1924 | zR = Th_GetResult(g.interp, &n); |
| 1925 | if( rc==TH_OK ){ |
| 1926 | @ <pre class="th1result">%h(zR)</pre> |
| 1927 | }else{ |
| @@ -2173,17 +2166,16 @@ | |
| 2166 | login_needed(0); |
| 2167 | return; |
| 2168 | } |
| 2169 | style_set_current_feature("setup"); |
| 2170 | style_header("URL Alias Configuration"); |
| 2171 | if( P("submit")!=0 && cgi_csrf_safe(2) ){ |
| 2172 | Blob token; |
| 2173 | Blob sql; |
| 2174 | const char *zNewName; |
| 2175 | const char *zValue; |
| 2176 | char zCnt[10]; |
| 2177 | blob_init(&namelist, PD("namelist",""), -1); |
| 2178 | blob_init(&sql, 0, 0); |
| 2179 | while( blob_token(&namelist, &token) ){ |
| 2180 | const char *zOldName = blob_str(&token); |
| 2181 | sqlite3_snprintf(sizeof(zCnt), zCnt, "n%d", cnt); |
| 2182 |
+2
-2
| --- src/setupuser.c | ||
| +++ src/setupuser.c | ||
| @@ -386,11 +386,11 @@ | ||
| 386 | 386 | ** more are missing, no-op */ |
| 387 | 387 | }else if( higherUser ){ |
| 388 | 388 | /* An Admin (a) user cannot edit a Superuser (s) */ |
| 389 | 389 | }else if( zDeleteVerify!=0 ){ |
| 390 | 390 | /* Need to verify a delete request */ |
| 391 | - }else if( !cgi_csrf_safe(1) ){ | |
| 391 | + }else if( !cgi_csrf_safe(2) ){ | |
| 392 | 392 | /* This might be a cross-site request forgery, so ignore it */ |
| 393 | 393 | }else{ |
| 394 | 394 | /* We have all the information we need to make the change to the user */ |
| 395 | 395 | char c; |
| 396 | 396 | char zCap[70], zNm[4]; |
| @@ -440,11 +440,11 @@ | ||
| 440 | 440 | @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)"> |
| 441 | 441 | @ [Bummer]</a></p> |
| 442 | 442 | style_finish_page(); |
| 443 | 443 | return; |
| 444 | 444 | } |
| 445 | - login_verify_csrf_secret(); | |
| 445 | + cgi_csrf_verify(); | |
| 446 | 446 | db_unprotect(PROTECT_USER); |
| 447 | 447 | db_multi_exec( |
| 448 | 448 | "REPLACE INTO user(uid,login,info,pw,cap,mtime) " |
| 449 | 449 | "VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now())", |
| 450 | 450 | uid, zLogin, P("info"), zPw, zCap |
| 451 | 451 |
| --- src/setupuser.c | |
| +++ src/setupuser.c | |
| @@ -386,11 +386,11 @@ | |
| 386 | ** more are missing, no-op */ |
| 387 | }else if( higherUser ){ |
| 388 | /* An Admin (a) user cannot edit a Superuser (s) */ |
| 389 | }else if( zDeleteVerify!=0 ){ |
| 390 | /* Need to verify a delete request */ |
| 391 | }else if( !cgi_csrf_safe(1) ){ |
| 392 | /* This might be a cross-site request forgery, so ignore it */ |
| 393 | }else{ |
| 394 | /* We have all the information we need to make the change to the user */ |
| 395 | char c; |
| 396 | char zCap[70], zNm[4]; |
| @@ -440,11 +440,11 @@ | |
| 440 | @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)"> |
| 441 | @ [Bummer]</a></p> |
| 442 | style_finish_page(); |
| 443 | return; |
| 444 | } |
| 445 | login_verify_csrf_secret(); |
| 446 | db_unprotect(PROTECT_USER); |
| 447 | db_multi_exec( |
| 448 | "REPLACE INTO user(uid,login,info,pw,cap,mtime) " |
| 449 | "VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now())", |
| 450 | uid, zLogin, P("info"), zPw, zCap |
| 451 |
| --- src/setupuser.c | |
| +++ src/setupuser.c | |
| @@ -386,11 +386,11 @@ | |
| 386 | ** more are missing, no-op */ |
| 387 | }else if( higherUser ){ |
| 388 | /* An Admin (a) user cannot edit a Superuser (s) */ |
| 389 | }else if( zDeleteVerify!=0 ){ |
| 390 | /* Need to verify a delete request */ |
| 391 | }else if( !cgi_csrf_safe(2) ){ |
| 392 | /* This might be a cross-site request forgery, so ignore it */ |
| 393 | }else{ |
| 394 | /* We have all the information we need to make the change to the user */ |
| 395 | char c; |
| 396 | char zCap[70], zNm[4]; |
| @@ -440,11 +440,11 @@ | |
| 440 | @ <p><a href="setup_uedit?id=%d(uid)&referer=%T(zRef)"> |
| 441 | @ [Bummer]</a></p> |
| 442 | style_finish_page(); |
| 443 | return; |
| 444 | } |
| 445 | cgi_csrf_verify(); |
| 446 | db_unprotect(PROTECT_USER); |
| 447 | db_multi_exec( |
| 448 | "REPLACE INTO user(uid,login,info,pw,cap,mtime) " |
| 449 | "VALUES(nullif(%d,0),%Q,%Q,%Q,%Q,now())", |
| 450 | uid, zLogin, P("info"), zPw, zCap |
| 451 |
+2
-4
| --- src/shun.c | ||
| +++ src/shun.c | ||
| @@ -98,14 +98,13 @@ | ||
| 98 | 98 | } |
| 99 | 99 | } |
| 100 | 100 | zUuid = zCanonical; |
| 101 | 101 | } |
| 102 | 102 | style_header("Shunned Artifacts"); |
| 103 | - if( zUuid && P("sub") ){ | |
| 103 | + if( zUuid && P("sub") && cgi_csrf_safe(2) ){ | |
| 104 | 104 | const char *p = zUuid; |
| 105 | 105 | int allExist = 1; |
| 106 | - login_verify_csrf_secret(); | |
| 107 | 106 | while( *p ){ |
| 108 | 107 | db_multi_exec("DELETE FROM shun WHERE uuid=%Q", p); |
| 109 | 108 | if( !db_exists("SELECT 1 FROM blob WHERE uuid=%Q", p) ){ |
| 110 | 109 | allExist = 0; |
| 111 | 110 | } |
| @@ -127,14 +126,13 @@ | ||
| 127 | 126 | @ It may be necessary to rebuild the repository using the |
| 128 | 127 | @ <b>fossil rebuild</b> command-line before the artifact content |
| 129 | 128 | @ can pulled in from other repositories.</p> |
| 130 | 129 | } |
| 131 | 130 | } |
| 132 | - if( zUuid && P("add") ){ | |
| 131 | + if( zUuid && P("add") && cgi_csrf_safe(2) ){ | |
| 133 | 132 | const char *p = zUuid; |
| 134 | 133 | int rid, tagid; |
| 135 | - login_verify_csrf_secret(); | |
| 136 | 134 | while( *p ){ |
| 137 | 135 | db_multi_exec( |
| 138 | 136 | "INSERT OR IGNORE INTO shun(uuid,mtime)" |
| 139 | 137 | " VALUES(%Q, now())", p); |
| 140 | 138 | db_multi_exec("DELETE FROM attachment WHERE src=%Q", p); |
| 141 | 139 |
| --- src/shun.c | |
| +++ src/shun.c | |
| @@ -98,14 +98,13 @@ | |
| 98 | } |
| 99 | } |
| 100 | zUuid = zCanonical; |
| 101 | } |
| 102 | style_header("Shunned Artifacts"); |
| 103 | if( zUuid && P("sub") ){ |
| 104 | const char *p = zUuid; |
| 105 | int allExist = 1; |
| 106 | login_verify_csrf_secret(); |
| 107 | while( *p ){ |
| 108 | db_multi_exec("DELETE FROM shun WHERE uuid=%Q", p); |
| 109 | if( !db_exists("SELECT 1 FROM blob WHERE uuid=%Q", p) ){ |
| 110 | allExist = 0; |
| 111 | } |
| @@ -127,14 +126,13 @@ | |
| 127 | @ It may be necessary to rebuild the repository using the |
| 128 | @ <b>fossil rebuild</b> command-line before the artifact content |
| 129 | @ can pulled in from other repositories.</p> |
| 130 | } |
| 131 | } |
| 132 | if( zUuid && P("add") ){ |
| 133 | const char *p = zUuid; |
| 134 | int rid, tagid; |
| 135 | login_verify_csrf_secret(); |
| 136 | while( *p ){ |
| 137 | db_multi_exec( |
| 138 | "INSERT OR IGNORE INTO shun(uuid,mtime)" |
| 139 | " VALUES(%Q, now())", p); |
| 140 | db_multi_exec("DELETE FROM attachment WHERE src=%Q", p); |
| 141 |
| --- src/shun.c | |
| +++ src/shun.c | |
| @@ -98,14 +98,13 @@ | |
| 98 | } |
| 99 | } |
| 100 | zUuid = zCanonical; |
| 101 | } |
| 102 | style_header("Shunned Artifacts"); |
| 103 | if( zUuid && P("sub") && cgi_csrf_safe(2) ){ |
| 104 | const char *p = zUuid; |
| 105 | int allExist = 1; |
| 106 | while( *p ){ |
| 107 | db_multi_exec("DELETE FROM shun WHERE uuid=%Q", p); |
| 108 | if( !db_exists("SELECT 1 FROM blob WHERE uuid=%Q", p) ){ |
| 109 | allExist = 0; |
| 110 | } |
| @@ -127,14 +126,13 @@ | |
| 126 | @ It may be necessary to rebuild the repository using the |
| 127 | @ <b>fossil rebuild</b> command-line before the artifact content |
| 128 | @ can pulled in from other repositories.</p> |
| 129 | } |
| 130 | } |
| 131 | if( zUuid && P("add") && cgi_csrf_safe(2) ){ |
| 132 | const char *p = zUuid; |
| 133 | int rid, tagid; |
| 134 | while( *p ){ |
| 135 | db_multi_exec( |
| 136 | "INSERT OR IGNORE INTO shun(uuid,mtime)" |
| 137 | " VALUES(%Q, now())", p); |
| 138 | db_multi_exec("DELETE FROM attachment WHERE src=%Q", p); |
| 139 |
+1
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -259,10 +259,11 @@ | ||
| 259 | 259 | }else{ |
| 260 | 260 | needHrefJs = 1; |
| 261 | 261 | @ <form method="POST" data-action='%s(zLink)' action='%R/login' \ |
| 262 | 262 | @ %s(zOtherArgs)> |
| 263 | 263 | } |
| 264 | + login_insert_csrf_secret(); | |
| 264 | 265 | } |
| 265 | 266 | |
| 266 | 267 | /* |
| 267 | 268 | ** Add a new element to the submenu |
| 268 | 269 | */ |
| 269 | 270 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -259,10 +259,11 @@ | |
| 259 | }else{ |
| 260 | needHrefJs = 1; |
| 261 | @ <form method="POST" data-action='%s(zLink)' action='%R/login' \ |
| 262 | @ %s(zOtherArgs)> |
| 263 | } |
| 264 | } |
| 265 | |
| 266 | /* |
| 267 | ** Add a new element to the submenu |
| 268 | */ |
| 269 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -259,10 +259,11 @@ | |
| 259 | }else{ |
| 260 | needHrefJs = 1; |
| 261 | @ <form method="POST" data-action='%s(zLink)' action='%R/login' \ |
| 262 | @ %s(zOtherArgs)> |
| 263 | } |
| 264 | login_insert_csrf_secret(); |
| 265 | } |
| 266 | |
| 267 | /* |
| 268 | ** Add a new element to the submenu |
| 269 | */ |
| 270 |
+3
-1
| --- src/th_main.c | ||
| +++ src/th_main.c | ||
| @@ -605,11 +605,13 @@ | ||
| 605 | 605 | int *argl |
| 606 | 606 | ){ |
| 607 | 607 | if( argc!=1 ){ |
| 608 | 608 | return Th_WrongNumArgs(interp, "verifyCsrf"); |
| 609 | 609 | } |
| 610 | - login_verify_csrf_secret(); | |
| 610 | + if( !cgi_csrf_safe(2) ){ | |
| 611 | + fossil_fatal("possible CSRF attack"); | |
| 612 | + } | |
| 611 | 613 | return TH_OK; |
| 612 | 614 | } |
| 613 | 615 | |
| 614 | 616 | /* |
| 615 | 617 | ** TH1 command: verifyLogin |
| 616 | 618 |
| --- src/th_main.c | |
| +++ src/th_main.c | |
| @@ -605,11 +605,13 @@ | |
| 605 | int *argl |
| 606 | ){ |
| 607 | if( argc!=1 ){ |
| 608 | return Th_WrongNumArgs(interp, "verifyCsrf"); |
| 609 | } |
| 610 | login_verify_csrf_secret(); |
| 611 | return TH_OK; |
| 612 | } |
| 613 | |
| 614 | /* |
| 615 | ** TH1 command: verifyLogin |
| 616 |
| --- src/th_main.c | |
| +++ src/th_main.c | |
| @@ -605,11 +605,13 @@ | |
| 605 | int *argl |
| 606 | ){ |
| 607 | if( argc!=1 ){ |
| 608 | return Th_WrongNumArgs(interp, "verifyCsrf"); |
| 609 | } |
| 610 | if( !cgi_csrf_safe(2) ){ |
| 611 | fossil_fatal("possible CSRF attack"); |
| 612 | } |
| 613 | return TH_OK; |
| 614 | } |
| 615 | |
| 616 | /* |
| 617 | ** TH1 command: verifyLogin |
| 618 |
+4
-3
| --- src/tkt.c | ||
| +++ src/tkt.c | ||
| @@ -900,11 +900,14 @@ | ||
| 900 | 900 | int i; |
| 901 | 901 | int nJ = 0, rc = TH_OK; |
| 902 | 902 | Blob tktchng, cksum; |
| 903 | 903 | int needMod; |
| 904 | 904 | |
| 905 | - login_verify_csrf_secret(); | |
| 905 | + if( !cgi_csrf_safe(2) ){ | |
| 906 | + @ <p class="generalError">Error: Invalid CSRF token.</p> | |
| 907 | + return TH_OK; | |
| 908 | + } | |
| 906 | 909 | if( !captcha_is_correct(0) ){ |
| 907 | 910 | @ <p class="generalError">Error: Incorrect security code.</p> |
| 908 | 911 | return TH_OK; |
| 909 | 912 | } |
| 910 | 913 | zUuid = (const char *)pUuid; |
| @@ -1015,11 +1018,10 @@ | ||
| 1015 | 1018 | initializeVariablesFromCGI(); |
| 1016 | 1019 | getAllTicketFields(); |
| 1017 | 1020 | initializeVariablesFromDb(); |
| 1018 | 1021 | if( g.zPath[0]=='d' ) showAllFields(); |
| 1019 | 1022 | form_begin(0, "%R/%s", g.zPath); |
| 1020 | - login_insert_csrf_secret(); | |
| 1021 | 1023 | if( P("date_override") && g.perm.Setup ){ |
| 1022 | 1024 | @ <input type="hidden" name="date_override" value="%h(P("date_override"))"> |
| 1023 | 1025 | } |
| 1024 | 1026 | zScript = ticket_newpage_code(); |
| 1025 | 1027 | if( g.zLogin && g.zLogin[0] ){ |
| @@ -1105,11 +1107,10 @@ | ||
| 1105 | 1107 | initializeVariablesFromCGI(); |
| 1106 | 1108 | initializeVariablesFromDb(); |
| 1107 | 1109 | if( g.zPath[0]=='d' ) showAllFields(); |
| 1108 | 1110 | form_begin(0, "%R/%s", g.zPath); |
| 1109 | 1111 | @ <input type="hidden" name="name" value="%s(zName)"> |
| 1110 | - login_insert_csrf_secret(); | |
| 1111 | 1112 | zScript = ticket_editpage_code(); |
| 1112 | 1113 | Th_Store("login", login_name()); |
| 1113 | 1114 | Th_Store("date", db_text(0, "SELECT datetime('now')")); |
| 1114 | 1115 | Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0); |
| 1115 | 1116 | Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0); |
| 1116 | 1117 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -900,11 +900,14 @@ | |
| 900 | int i; |
| 901 | int nJ = 0, rc = TH_OK; |
| 902 | Blob tktchng, cksum; |
| 903 | int needMod; |
| 904 | |
| 905 | login_verify_csrf_secret(); |
| 906 | if( !captcha_is_correct(0) ){ |
| 907 | @ <p class="generalError">Error: Incorrect security code.</p> |
| 908 | return TH_OK; |
| 909 | } |
| 910 | zUuid = (const char *)pUuid; |
| @@ -1015,11 +1018,10 @@ | |
| 1015 | initializeVariablesFromCGI(); |
| 1016 | getAllTicketFields(); |
| 1017 | initializeVariablesFromDb(); |
| 1018 | if( g.zPath[0]=='d' ) showAllFields(); |
| 1019 | form_begin(0, "%R/%s", g.zPath); |
| 1020 | login_insert_csrf_secret(); |
| 1021 | if( P("date_override") && g.perm.Setup ){ |
| 1022 | @ <input type="hidden" name="date_override" value="%h(P("date_override"))"> |
| 1023 | } |
| 1024 | zScript = ticket_newpage_code(); |
| 1025 | if( g.zLogin && g.zLogin[0] ){ |
| @@ -1105,11 +1107,10 @@ | |
| 1105 | initializeVariablesFromCGI(); |
| 1106 | initializeVariablesFromDb(); |
| 1107 | if( g.zPath[0]=='d' ) showAllFields(); |
| 1108 | form_begin(0, "%R/%s", g.zPath); |
| 1109 | @ <input type="hidden" name="name" value="%s(zName)"> |
| 1110 | login_insert_csrf_secret(); |
| 1111 | zScript = ticket_editpage_code(); |
| 1112 | Th_Store("login", login_name()); |
| 1113 | Th_Store("date", db_text(0, "SELECT datetime('now')")); |
| 1114 | Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0); |
| 1115 | Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0); |
| 1116 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -900,11 +900,14 @@ | |
| 900 | int i; |
| 901 | int nJ = 0, rc = TH_OK; |
| 902 | Blob tktchng, cksum; |
| 903 | int needMod; |
| 904 | |
| 905 | if( !cgi_csrf_safe(2) ){ |
| 906 | @ <p class="generalError">Error: Invalid CSRF token.</p> |
| 907 | return TH_OK; |
| 908 | } |
| 909 | if( !captcha_is_correct(0) ){ |
| 910 | @ <p class="generalError">Error: Incorrect security code.</p> |
| 911 | return TH_OK; |
| 912 | } |
| 913 | zUuid = (const char *)pUuid; |
| @@ -1015,11 +1018,10 @@ | |
| 1018 | initializeVariablesFromCGI(); |
| 1019 | getAllTicketFields(); |
| 1020 | initializeVariablesFromDb(); |
| 1021 | if( g.zPath[0]=='d' ) showAllFields(); |
| 1022 | form_begin(0, "%R/%s", g.zPath); |
| 1023 | if( P("date_override") && g.perm.Setup ){ |
| 1024 | @ <input type="hidden" name="date_override" value="%h(P("date_override"))"> |
| 1025 | } |
| 1026 | zScript = ticket_newpage_code(); |
| 1027 | if( g.zLogin && g.zLogin[0] ){ |
| @@ -1105,11 +1107,10 @@ | |
| 1107 | initializeVariablesFromCGI(); |
| 1108 | initializeVariablesFromDb(); |
| 1109 | if( g.zPath[0]=='d' ) showAllFields(); |
| 1110 | form_begin(0, "%R/%s", g.zPath); |
| 1111 | @ <input type="hidden" name="name" value="%s(zName)"> |
| 1112 | zScript = ticket_editpage_code(); |
| 1113 | Th_Store("login", login_name()); |
| 1114 | Th_Store("date", db_text(0, "SELECT datetime('now')")); |
| 1115 | Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0); |
| 1116 | Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0); |
| 1117 |
+2
-4
| --- src/tktsetup.c | ||
| +++ src/tktsetup.c | ||
| @@ -135,18 +135,16 @@ | ||
| 135 | 135 | if( z==0 ){ |
| 136 | 136 | z = db_get(zDbField, zDfltValue); |
| 137 | 137 | } |
| 138 | 138 | style_set_current_feature("tktsetup"); |
| 139 | 139 | style_header("Edit %s", zTitle); |
| 140 | - if( P("clear")!=0 ){ | |
| 141 | - login_verify_csrf_secret(); | |
| 140 | + if( P("clear")!=0 && cgi_csrf_safe(2) ){ | |
| 142 | 141 | db_unset(zDbField/*works-like:"x"*/, 0); |
| 143 | 142 | if( xRebuild ) xRebuild(); |
| 144 | 143 | cgi_redirect("tktsetup"); |
| 145 | - }else if( isSubmit ){ | |
| 144 | + }else if( isSubmit && cgi_csrf_safe(2) ){ | |
| 146 | 145 | char *zErr = 0; |
| 147 | - login_verify_csrf_secret(); | |
| 148 | 146 | if( xText && (zErr = xText(z))!=0 ){ |
| 149 | 147 | @ <p class="tktsetupError">ERROR: %h(zErr)</p> |
| 150 | 148 | }else{ |
| 151 | 149 | db_set(zDbField/*works-like:"x"*/, z, 0); |
| 152 | 150 | if( xRebuild ) xRebuild(); |
| 153 | 151 |
| --- src/tktsetup.c | |
| +++ src/tktsetup.c | |
| @@ -135,18 +135,16 @@ | |
| 135 | if( z==0 ){ |
| 136 | z = db_get(zDbField, zDfltValue); |
| 137 | } |
| 138 | style_set_current_feature("tktsetup"); |
| 139 | style_header("Edit %s", zTitle); |
| 140 | if( P("clear")!=0 ){ |
| 141 | login_verify_csrf_secret(); |
| 142 | db_unset(zDbField/*works-like:"x"*/, 0); |
| 143 | if( xRebuild ) xRebuild(); |
| 144 | cgi_redirect("tktsetup"); |
| 145 | }else if( isSubmit ){ |
| 146 | char *zErr = 0; |
| 147 | login_verify_csrf_secret(); |
| 148 | if( xText && (zErr = xText(z))!=0 ){ |
| 149 | @ <p class="tktsetupError">ERROR: %h(zErr)</p> |
| 150 | }else{ |
| 151 | db_set(zDbField/*works-like:"x"*/, z, 0); |
| 152 | if( xRebuild ) xRebuild(); |
| 153 |
| --- src/tktsetup.c | |
| +++ src/tktsetup.c | |
| @@ -135,18 +135,16 @@ | |
| 135 | if( z==0 ){ |
| 136 | z = db_get(zDbField, zDfltValue); |
| 137 | } |
| 138 | style_set_current_feature("tktsetup"); |
| 139 | style_header("Edit %s", zTitle); |
| 140 | if( P("clear")!=0 && cgi_csrf_safe(2) ){ |
| 141 | db_unset(zDbField/*works-like:"x"*/, 0); |
| 142 | if( xRebuild ) xRebuild(); |
| 143 | cgi_redirect("tktsetup"); |
| 144 | }else if( isSubmit && cgi_csrf_safe(2) ){ |
| 145 | char *zErr = 0; |
| 146 | if( xText && (zErr = xText(z))!=0 ){ |
| 147 | @ <p class="tktsetupError">ERROR: %h(zErr)</p> |
| 148 | }else{ |
| 149 | db_set(zDbField/*works-like:"x"*/, z, 0); |
| 150 | if( xRebuild ) xRebuild(); |
| 151 |
+1
-2
| --- src/wiki.c | ||
| +++ src/wiki.c | ||
| @@ -1632,18 +1632,18 @@ | ||
| 1632 | 1632 | zMimetype = wiki_filter_mimetypes(pWiki->zMimetype) |
| 1633 | 1633 | /* see https://fossil-scm.org/forum/forumpost/0acfdaac80 */; |
| 1634 | 1634 | } |
| 1635 | 1635 | if( !isSandbox && P("submit")!=0 && P("r")!=0 && P("u")!=0 |
| 1636 | 1636 | && (goodCaptcha = captcha_is_correct(0)) |
| 1637 | + && cgi_csrf_safe(2) | |
| 1637 | 1638 | ){ |
| 1638 | 1639 | char *zDate; |
| 1639 | 1640 | Blob cksum; |
| 1640 | 1641 | Blob body; |
| 1641 | 1642 | Blob wiki; |
| 1642 | 1643 | |
| 1643 | 1644 | blob_zero(&body); |
| 1644 | - login_verify_csrf_secret(); | |
| 1645 | 1645 | blob_append(&body, pWiki->zWiki, -1); |
| 1646 | 1646 | blob_zero(&wiki); |
| 1647 | 1647 | db_begin_transaction(); |
| 1648 | 1648 | zDate = date_in_standard_format("now"); |
| 1649 | 1649 | blob_appendf(&wiki, "D %s\n", zDate); |
| @@ -1695,11 +1695,10 @@ | ||
| 1695 | 1695 | @ <hr> |
| 1696 | 1696 | blob_reset(&preview); |
| 1697 | 1697 | } |
| 1698 | 1698 | zUser = PD("u", g.zLogin); |
| 1699 | 1699 | form_begin(0, "%R/wikiappend"); |
| 1700 | - login_insert_csrf_secret(); | |
| 1701 | 1700 | @ <input type="hidden" name="name" value="%h(zPageName)"> |
| 1702 | 1701 | @ <input type="hidden" name="mimetype" value="%h(zMimetype)"> |
| 1703 | 1702 | @ Your Name: |
| 1704 | 1703 | @ <input type="text" name="u" size="20" value="%h(zUser)"><br> |
| 1705 | 1704 | zFormat = mimetype_common_name(zMimetype); |
| 1706 | 1705 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -1632,18 +1632,18 @@ | |
| 1632 | zMimetype = wiki_filter_mimetypes(pWiki->zMimetype) |
| 1633 | /* see https://fossil-scm.org/forum/forumpost/0acfdaac80 */; |
| 1634 | } |
| 1635 | if( !isSandbox && P("submit")!=0 && P("r")!=0 && P("u")!=0 |
| 1636 | && (goodCaptcha = captcha_is_correct(0)) |
| 1637 | ){ |
| 1638 | char *zDate; |
| 1639 | Blob cksum; |
| 1640 | Blob body; |
| 1641 | Blob wiki; |
| 1642 | |
| 1643 | blob_zero(&body); |
| 1644 | login_verify_csrf_secret(); |
| 1645 | blob_append(&body, pWiki->zWiki, -1); |
| 1646 | blob_zero(&wiki); |
| 1647 | db_begin_transaction(); |
| 1648 | zDate = date_in_standard_format("now"); |
| 1649 | blob_appendf(&wiki, "D %s\n", zDate); |
| @@ -1695,11 +1695,10 @@ | |
| 1695 | @ <hr> |
| 1696 | blob_reset(&preview); |
| 1697 | } |
| 1698 | zUser = PD("u", g.zLogin); |
| 1699 | form_begin(0, "%R/wikiappend"); |
| 1700 | login_insert_csrf_secret(); |
| 1701 | @ <input type="hidden" name="name" value="%h(zPageName)"> |
| 1702 | @ <input type="hidden" name="mimetype" value="%h(zMimetype)"> |
| 1703 | @ Your Name: |
| 1704 | @ <input type="text" name="u" size="20" value="%h(zUser)"><br> |
| 1705 | zFormat = mimetype_common_name(zMimetype); |
| 1706 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -1632,18 +1632,18 @@ | |
| 1632 | zMimetype = wiki_filter_mimetypes(pWiki->zMimetype) |
| 1633 | /* see https://fossil-scm.org/forum/forumpost/0acfdaac80 */; |
| 1634 | } |
| 1635 | if( !isSandbox && P("submit")!=0 && P("r")!=0 && P("u")!=0 |
| 1636 | && (goodCaptcha = captcha_is_correct(0)) |
| 1637 | && cgi_csrf_safe(2) |
| 1638 | ){ |
| 1639 | char *zDate; |
| 1640 | Blob cksum; |
| 1641 | Blob body; |
| 1642 | Blob wiki; |
| 1643 | |
| 1644 | blob_zero(&body); |
| 1645 | blob_append(&body, pWiki->zWiki, -1); |
| 1646 | blob_zero(&wiki); |
| 1647 | db_begin_transaction(); |
| 1648 | zDate = date_in_standard_format("now"); |
| 1649 | blob_appendf(&wiki, "D %s\n", zDate); |
| @@ -1695,11 +1695,10 @@ | |
| 1695 | @ <hr> |
| 1696 | blob_reset(&preview); |
| 1697 | } |
| 1698 | zUser = PD("u", g.zLogin); |
| 1699 | form_begin(0, "%R/wikiappend"); |
| 1700 | @ <input type="hidden" name="name" value="%h(zPageName)"> |
| 1701 | @ <input type="hidden" name="mimetype" value="%h(zMimetype)"> |
| 1702 | @ Your Name: |
| 1703 | @ <input type="text" name="u" size="20" value="%h(zUser)"><br> |
| 1704 | zFormat = mimetype_common_name(zMimetype); |
| 1705 |
+2
-4
| --- src/xfersetup.c | ||
| +++ src/xfersetup.c | ||
| @@ -118,18 +118,16 @@ | ||
| 118 | 118 | if( z==0 ){ |
| 119 | 119 | z = db_get(zDbField, zDfltValue); |
| 120 | 120 | } |
| 121 | 121 | style_set_current_feature("xfersetup"); |
| 122 | 122 | style_header("Edit %s", zTitle); |
| 123 | - if( P("clear")!=0 ){ | |
| 124 | - login_verify_csrf_secret(); | |
| 123 | + if( P("clear")!=0 && cgi_csrf_safe(2) ){ | |
| 125 | 124 | db_unset(zDbField/*works-like:"x"*/, 0); |
| 126 | 125 | if( xRebuild ) xRebuild(); |
| 127 | 126 | z = zDfltValue; |
| 128 | - }else if( isSubmit ){ | |
| 127 | + }else if( isSubmit && cgi_csrf_safe(2) ){ | |
| 129 | 128 | char *zErr = 0; |
| 130 | - login_verify_csrf_secret(); | |
| 131 | 129 | if( xText && (zErr = xText(z))!=0 ){ |
| 132 | 130 | @ <p class="xfersetupError">ERROR: %h(zErr)</p> |
| 133 | 131 | }else{ |
| 134 | 132 | db_set(zDbField/*works-like:"x"*/, z, 0); |
| 135 | 133 | if( xRebuild ) xRebuild(); |
| 136 | 134 |
| --- src/xfersetup.c | |
| +++ src/xfersetup.c | |
| @@ -118,18 +118,16 @@ | |
| 118 | if( z==0 ){ |
| 119 | z = db_get(zDbField, zDfltValue); |
| 120 | } |
| 121 | style_set_current_feature("xfersetup"); |
| 122 | style_header("Edit %s", zTitle); |
| 123 | if( P("clear")!=0 ){ |
| 124 | login_verify_csrf_secret(); |
| 125 | db_unset(zDbField/*works-like:"x"*/, 0); |
| 126 | if( xRebuild ) xRebuild(); |
| 127 | z = zDfltValue; |
| 128 | }else if( isSubmit ){ |
| 129 | char *zErr = 0; |
| 130 | login_verify_csrf_secret(); |
| 131 | if( xText && (zErr = xText(z))!=0 ){ |
| 132 | @ <p class="xfersetupError">ERROR: %h(zErr)</p> |
| 133 | }else{ |
| 134 | db_set(zDbField/*works-like:"x"*/, z, 0); |
| 135 | if( xRebuild ) xRebuild(); |
| 136 |
| --- src/xfersetup.c | |
| +++ src/xfersetup.c | |
| @@ -118,18 +118,16 @@ | |
| 118 | if( z==0 ){ |
| 119 | z = db_get(zDbField, zDfltValue); |
| 120 | } |
| 121 | style_set_current_feature("xfersetup"); |
| 122 | style_header("Edit %s", zTitle); |
| 123 | if( P("clear")!=0 && cgi_csrf_safe(2) ){ |
| 124 | db_unset(zDbField/*works-like:"x"*/, 0); |
| 125 | if( xRebuild ) xRebuild(); |
| 126 | z = zDfltValue; |
| 127 | }else if( isSubmit && cgi_csrf_safe(2) ){ |
| 128 | char *zErr = 0; |
| 129 | if( xText && (zErr = xText(z))!=0 ){ |
| 130 | @ <p class="xfersetupError">ERROR: %h(zErr)</p> |
| 131 | }else{ |
| 132 | db_set(zDbField/*works-like:"x"*/, z, 0); |
| 133 | if( xRebuild ) xRebuild(); |
| 134 |