@@ -414,6 +414,30 @@ function getHTML($record, $tab, $action = 'NEW') {
414414 if (!is_array ($ this ->formDef )) $ app ->error ("No form definition found. " );
415415 if (!is_array ($ this ->formDef ['tabs ' ][$ tab ])) $ app ->error ("The tab is empty or does not exist (TAB: $ tab). " );
416416
417+ /* CSRF PROTECTION */
418+ // generate csrf protection id and key
419+ $ _csrf_id = uniqid ($ this ->formDef ['name ' ] . '_ ' );
420+ $ _csrf_value = sha1 (uniqid (microtime (true ), true ));
421+ if (!isset ($ _SESSION ['_csrf ' ])) $ _SESSION ['_csrf ' ] = array ();
422+ if (!isset ($ _SESSION ['_csrf_timeout ' ])) $ _SESSION ['_csrf_timeout ' ] = array ();
423+ $ _SESSION ['_csrf ' ][$ _csrf_id ] = $ _csrf_value ;
424+ $ _SESSION ['_csrf_timeout ' ][$ _csrf_id ] = time () + 3600 ; // timeout hash in 1 hour
425+ $ this ->formDef ['tabs ' ][$ tab ]['fields ' ]['_csrf_id ' ] = array (
426+ 'datatype ' => 'VARCHAR ' ,
427+ 'formtype ' => 'TEXT ' ,
428+ 'default ' => $ _csrf_id ,
429+ 'value ' => $ _csrf_id
430+ );
431+ $ this ->formDef ['tabs ' ][$ tab ]['fields ' ]['_csrf_key ' ] = array (
432+ 'datatype ' => 'VARCHAR ' ,
433+ 'formtype ' => 'TEXT ' ,
434+ 'default ' => $ _csrf_value ,
435+ 'value ' => $ _csrf_value
436+ );
437+ $ record ['_csrf_id ' ] = $ _csrf_id ;
438+ $ record ['_csrf_key ' ] = $ _csrf_value ;
439+ /* CSRF PROTECTION */
440+
417441 $ new_record = array ();
418442 if ($ action == 'EDIT ' ) {
419443 $ record = $ this ->decode ($ record , $ tab );
@@ -669,8 +693,50 @@ function getHTML($record, $tab, $action = 'NEW') {
669693 */
670694 protected function _encode ($ record , $ tab , $ dbencode = true , $ api = false ) {
671695 global $ app ;
672- if ($ api == true ) $ fields = &$ this ->formDef ['fields ' ];
673- else $ fields = &$ this ->formDef ['tabs ' ][$ tab ]['fields ' ];
696+ if ($ api == true ) {
697+ $ fields = &$ this ->formDef ['fields ' ];
698+ } else {
699+ $ fields = &$ this ->formDef ['tabs ' ][$ tab ]['fields ' ];
700+ /* CSRF PROTECTION */
701+ if (isset ($ _POST ) && is_array ($ _POST )) {
702+ $ _csrf_valid = false ;
703+ if (isset ($ _POST ['_csrf_id ' ]) && isset ($ _POST ['_csrf_key ' ])) {
704+ $ _csrf_id = trim ($ _POST ['_csrf_id ' ]);
705+ $ _csrf_key = trim ($ _POST ['_csrf_key ' ]);
706+ if (isset ($ _SESSION ['_csrf ' ]) && isset ($ _SESSION ['_csrf ' ][$ _csrf_id ]) && isset ($ _SESSION ['_csrf_timeout ' ]) && isset ($ _SESSION ['_csrf_timeout ' ][$ _csrf_id ])) {
707+ if ($ _SESSION ['_csrf ' ][$ _csrf_id ] === $ _csrf_key && $ _SESSION ['_csrf_timeout ' ] >= time ()) $ _csrf_valid = true ;
708+ }
709+ }
710+ if ($ _csrf_valid !== true ) {
711+ $ app ->log ('CSRF attempt blocked. Referer: ' . (isset ($ _SERVER ['HTTP_REFERER ' ]) ? $ _SERVER ['HTTP_REFERER ' ] : 'unknown ' ), LOGLEVEL_WARN );
712+ $ errmsg = 'err_csrf_attempt_blocked ' ;
713+ $ this ->errorMessage .= ($ api == true ? $ errmsg : $ this ->wordbook [$ errmsg ]."<br /> " ) . "\r\n" ;
714+ unset($ _POST );
715+ unset($ record );
716+ }
717+ $ _SESSION ['_csrf ' ][$ _csrf_id ] = null ;
718+ $ _SESSION ['_csrf_timeout ' ][$ _csrf_id ] = null ;
719+ unset($ _SESSION ['_csrf ' ][$ _csrf_id ]);
720+ unset($ _SESSION ['_csrf_timeout ' ][$ _csrf_id ]);
721+
722+ if (isset ($ _SESSION ['_csrf_timeout ' ]) && is_array ($ _SESSION ['_csrf_timeout ' ])) {
723+ $ to_unset = array ();
724+ foreach ($ _SESSION ['_csrf_timeout ' ] as $ _csrf_id => $ timeout ) {
725+ if ($ timeout < time ()) $ to_unset [] = $ _csrf_id ;
726+ }
727+ foreach ($ to_unset as $ _csrf_id ) {
728+ $ _SESSION ['_csrf ' ][$ _csrf_id ] = null ;
729+ $ _SESSION ['_csrf_timeout ' ][$ _csrf_id ] = null ;
730+ unset($ _SESSION ['_csrf ' ][$ _csrf_id ]);
731+ unset($ _SESSION ['_csrf_timeout ' ][$ _csrf_id ]);
732+ }
733+ unset($ to_unset );
734+ }
735+ }
736+ /* CSRF PROTECTION */
737+ }
738+
739+ $ new_record = array ();
674740 if (is_array ($ record )) {
675741 foreach ($ fields as $ key => $ field ) {
676742
0 commit comments