Issue #10730: Use crypto_api for generating nonces and improve hashing
[mantis/radio.git] / core / form_api.php
blob510f3013e7a9382e159ff2acc2e1458795fb0e8f
1 <?php
2 # MantisBT - A PHP based bugtracking system
4 # MantisBT is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation, either version 2 of the License, or
7 # (at your option) any later version.
9 # MantisBT is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with MantisBT. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * Form API
20 * Handles form security and validation. Security methods are targeted to
21 * work with both GET and POST form types and should allow multiple
22 * simultaneous edits of the form to be submitted out-of-order.
24 * @package CoreAPI
25 * @subpackage FormAPI
26 * @copyright Copyright (C) 2000 - 2002 Kenzaburo Ito - kenito@300baud.org
27 * @copyright Copyright (C) 2002 - 2010 MantisBT Team - mantisbt-dev@lists.sourceforge.net
28 * @link http://www.mantisbt.org
30 * @uses config_api.php
31 * @uses constant_inc.php
32 * @uses crypto_api.php
33 * @uses gpc_api.php
34 * @uses php_api.php
35 * @uses session_api.php
38 require_api( 'config_api.php' );
39 require_api( 'constant_inc.php' );
40 require_api( 'crypto_api.php' );
41 require_api( 'gpc_api.php' );
42 require_api( 'php_api.php' );
43 require_api( 'session_api.php' );
45 /**
46 * Generate a random security token, prefixed by date, store it in the
47 * user's session, and then return the string to be used as a form element
48 * element with the security token as the value.
49 * @param string Form name
50 * @return string Security token string
52 function form_security_token( $p_form_name ) {
53 if ( PHP_CLI == php_mode() || OFF == config_get_global( 'form_security_validation' ) ) {
54 return '';
57 $t_tokens = session_get( 'form_security_tokens', array() );
59 # Create a new array for the form name if necessary
60 if( !isset( $t_tokens[$p_form_name] ) || !is_array( $t_tokens[$p_form_name] ) ) {
61 $t_tokens[$p_form_name] = array();
64 # Generate a nonce prefixed by date.
65 # With a base64 output encoded nonce length of 32 characters, we are
66 # generating a 192bit nonce.
67 $t_date = date( 'Ymd' );
68 $t_string = $t_date . crypto_generate_uri_safe_nonce( 32 );
70 # Add the token to the user's session
71 if ( !isset( $t_tokens[$p_form_name][$t_date] ) ) {
72 $t_tokens[$p_form_name][$t_date] = array();
75 $t_tokens[$p_form_name][$t_date][$t_string] = true;
76 session_set( 'form_security_tokens', $t_tokens );
78 # The token string
79 return $t_string;
82 /**
83 * Get a hidden form element containing a generated form security token.
84 * @param string Form name
85 * @return string Hidden form element to output
87 function form_security_field( $p_form_name ) {
88 if ( PHP_CLI == php_mode() || OFF == config_get_global( 'form_security_validation' ) ) {
89 return '';
92 $t_string = form_security_token( $p_form_name );
94 # Create the form element HTML string for the security token
95 $t_form_token = $p_form_name . '_token';
96 $t_element = '<input type="hidden" name="%s" value="%s"/>';
97 $t_element = sprintf( $t_element, $t_form_token, $t_string );
99 return $t_element;
103 * Get a URL parameter containing a generated form security token.
104 * @param string Form name
105 * @return string Hidden form element to output
107 function form_security_param( $p_form_name ) {
108 if ( PHP_CLI == php_mode() || OFF == config_get_global( 'form_security_validation' ) ) {
109 return '';
112 $t_string = form_security_token( $p_form_name );
114 # Create the GET parameter to be used in a URL for a secure link
115 $t_form_token = $p_form_name . '_token';
116 $t_param = '&%s=%s';
117 $t_param = sprintf( $t_param, $t_form_token, $t_string );
119 return $t_param;
123 * Validate the security token for the given form name based on tokens
124 * stored in the user's session. While checking stored tokens, any that
125 * are more than 3 days old will be purged.
126 * @param string Form name
127 * @return boolean Form is valid
129 function form_security_validate( $p_form_name ) {
130 if ( PHP_CLI == php_mode() || OFF == config_get_global( 'form_security_validation' ) ) {
131 return true;
134 $t_tokens = session_get( 'form_security_tokens', array() );
136 # Short-circuit if we don't have any tokens for the given form name
137 if( !isset( $t_tokens[$p_form_name] ) || !is_array( $t_tokens[$p_form_name] ) || count( $t_tokens[$p_form_name] ) < 1 ) {
139 trigger_error( ERROR_FORM_TOKEN_INVALID, ERROR );
140 return false;
143 # Get the form input
144 $t_form_token = $p_form_name . '_token';
145 $t_input = gpc_get_string( $t_form_token, '' );
147 # No form input
148 if( '' == $t_input ) {
149 trigger_error( ERROR_FORM_TOKEN_INVALID, ERROR );
150 return false;
153 # Get the date claimed by the token
154 $t_date = utf8_substr( $t_input, 0, 8 );
156 # Check if the token exists
157 if ( isset( $t_tokens[$p_form_name][$t_date][$t_input] ) ) {
158 return true;
161 # Token does not exist
162 trigger_error( ERROR_FORM_TOKEN_INVALID, ERROR );
163 return false;
167 * Purge form security tokens that are older than 3 days, or used
168 * for form validation.
169 * @param string Form name
171 function form_security_purge( $p_form_name ) {
172 if ( PHP_CLI == php_mode() || OFF == config_get_global( 'form_security_validation' ) ) {
173 return;
176 $t_tokens = session_get( 'form_security_tokens', array() );
178 # Short-circuit if we don't have any tokens for the given form name
179 if( !isset( $t_tokens[$p_form_name] ) || !is_array( $t_tokens[$p_form_name] ) || count( $t_tokens[$p_form_name] ) < 1 ) {
180 return;
183 # Get the form input
184 $t_form_token = $p_form_name . '_token';
185 $t_input = gpc_get_string( $t_form_token, '' );
187 # Get the date claimed by the token
188 $t_date = utf8_substr( $t_input, 0, 8 );
190 # Generate a date string of three days ago
191 $t_purge_date = date( 'Ymd', time() - ( 3 * 24 * 60 * 60 ) );
193 # Purge old token data, and the currently-used token
194 unset( $t_tokens[$p_form_name][$t_date][$t_input] );
196 foreach( $t_tokens as $t_form_name => $t_dates ) {
197 foreach( $t_dates as $t_date => $t_date_tokens ) {
198 if ( $t_date < $t_purge_date ) {
199 unset( $t_tokens[$t_form_name][$t_date] );
204 session_set( 'form_security_tokens', $t_tokens );
206 return;