Skip to content

Commit ec27daa

Browse files
authored
Merge pull request #1634 from maggienegm/csrf-fix-forms
CSRF Fixes and Remote Code Execution Prevention
2 parents f249e0a + 9cf84f6 commit ec27daa

70 files changed

Lines changed: 602 additions & 72 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

controllers/C_Document.class.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
require_once(dirname(__FILE__) . "/../library/forms.inc");
1515
require_once(dirname(__FILE__) . "/../library/formatting.inc.php");
1616
require_once(dirname(__FILE__) . "/../library/classes/postmaster.php" );
17+
require_once(dirname(__FILE__) . "/../library/sanitize.inc.php" );
1718

1819
class C_Document extends Controller {
1920

@@ -170,6 +171,8 @@ function upload_action_process() {
170171
if ($_FILES['file']['size'][$key] == 0) {
171172
$error .= "The system does not permit uploading files of with size 0.\n";
172173
}
174+
} elseif (!isSafeFile($_FILES['file']['tmp_name'][$key])) {
175+
$error = xl("The system does not permit uploading files with MIME content type") . " - " . mime_content_type($_FILES['file']['tmp_name'][$key]) . ".\n";
173176
} else {
174177
$tmpfile = fopen($_FILES['file']['tmp_name'][$key], "r");
175178
$filetext = fread($tmpfile, $_FILES['file']['size'][$key]);

interface/billing/edi_history_main.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
require_once("$srcdir/edihistory/ibr_ack_read.php"); //dirname(__FILE__) . "/edihist/ibr_ack_read.php");
7171
require_once("$srcdir/edihistory/ibr_uploads.php"); //dirname(__FILE__) . "/edihist/ibr_uploads.php");
7272
require_once("$srcdir/edihistory/ibr_io.php"); //dirname(__FILE__) . "/edihist/ibr_io.php");
73+
require_once("../../library/CsrfToken.php");
7374
//
7475
// php may output line endings if include files are utf-8
7576
ob_clean();
@@ -100,6 +101,14 @@
100101
*/
101102

102103
if (strtolower($_SERVER['REQUEST_METHOD']) == 'post') {
104+
if (!empty($_POST)) {
105+
if (!isset($_POST['token'])) {
106+
error_log('WARNING: A POST request detected with no csrf token found');
107+
die('Authentication failed.');
108+
} else if (!(CsrfToken::verifyCsrfToken($_POST['token']))) {
109+
die('Authentication failed.');
110+
}
111+
}
103112
//
104113
if ( isset($_POST['NewFiles']) ) {
105114
// process new files button clicked

interface/billing/edih_view.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
<legend><?php echo xlt("Select one or more files to upload"); ?></legend>
7676
<input id="upload_file" type="file" name="fileUplMulti[]" class="cp-positive" multiple />
7777
<input type="submit" name="uplsubmt" class="cp-submit" value="<?php echo xla("Submit"); ?>" />
78+
<input type='hidden' name='token' value="<?php echo $_SESSION['token'];?>" />
7879
</fieldset>
7980
</form>
8081
</td>
@@ -87,6 +88,7 @@
8788
<input type="hidden" name="NewFiles" value="ProcessNew">
8889
<label for="New-Files">Process New Files:</label>
8990
<input id="processfiles" name="Process" class="cp-output" type="button" value="<?php echo xla("Process"); ?>" />
91+
<input type='hidden' name='token' value="<?php echo $_SESSION['token'];?>" />
9092
</fieldset>
9193
</form>
9294
</td>
@@ -159,6 +161,7 @@
159161
-->
160162
<td align='center'>
161163
<input type="hidden" name="csvshowtable" value="gettable">
164+
<input type='hidden' name='token' value="<?php echo $_SESSION['token'];?>" />
162165
<input id="showtable" type="button" class="cp-submit" value="<?php echo xla("Submit"); ?>" />
163166
</td>
164167

@@ -220,6 +223,7 @@
220223
<label for="era_file"><?php echo xlt("Filename"); ?>:</label>
221224
<input id="era_file" type="file" size=20 name="fileUplEra" class="cp-positive" />
222225
<input type="submit" name="fileERA" class="cp-submit" value="<?php echo xla("Submit"); ?>" />
226+
<input type='hidden' name='token' value="<?php echo $_SESSION['token'];?>" />
223227
</fieldset>
224228
</form>
225229
</td>
@@ -236,6 +240,7 @@
236240
<label for="trace835"><?php echo xlt("Check No"); ?>:</label>
237241
<input type="text" size=10 name="trace835" value="" />
238242
<input type="submit" name="subtrace835" class="cp-submit" value="<?php echo xla("Submit"); ?>" />
243+
<input type='hidden' name='token' value="<?php echo $_SESSION['token'];?>" />
239244
</fieldset>
240245
</form>
241246
</td>
@@ -253,6 +258,7 @@
253258
<label for="enctr"><?php echo xlt("Enter Encounter"); ?>:</label>
254259
<input type="text" name="enctrbatch" size=10 value="" />
255260
<input type="submit" name="Batch-enctr" class="cp-submit" value="<?php echo xla("Submit"); ?>" />
261+
<input type='hidden' name='token' value="<?php echo $_SESSION['token'];?>" />
256262
</fieldset>
257263
</form>
258264
</td>
@@ -263,6 +269,7 @@
263269
<label for="enctrERA"><?php echo xlt("Enter Encounter"); ?>:</label>
264270
<input type="text" name="enctrEra" size=10 value="" />
265271
<input type="submit" name="eraText" class="cp-submit" value="<?php echo xla("Submit"); ?>" />
272+
<input type='hidden' name='token' value="<?php echo $_SESSION['token'];?>" />
266273
</fieldset>
267274
</form>
268275
</td>
@@ -275,6 +282,7 @@
275282
<label for="x12file"><?php echo xlt("Choose File"); ?>:</label>
276283
<input id="x12file" type="file" name="fileUplx12" class="cp-positive" />
277284
<input type="submit" name="fileX12" class="cp-submit" value="<?php echo xla("Submit"); ?>" />
285+
<input type='hidden' name='token' value="<?php echo $_SESSION['token'];?>" />
278286
</fieldset>
279287
</form>
280288
</td>
@@ -309,6 +317,7 @@
309317
<input id="savenotes" type="button" class="cp-submit" value="<?php echo xla("Save"); ?>" />
310318
<label for="closenotes"><?php echo xlt("Close"); ?></label>
311319
<input id="closenotes" type="button" class="cp-negative" value="<?php echo xla("Close"); ?>" />
320+
<input type='hidden' name='token' value="<?php echo $_SESSION['token'];?>" />
312321
</fieldset>
313322
</form>
314323
</td>

interface/billing/sl_eob_search.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ function upload_file_to_client_pdf($file_to_send) {
470470
if ($DEBUG) {
471471
$alertmsg = xl("Printing skipped; see test output in") .' '. $STMT_TEMP_FILE;
472472
} else {
473-
exec("$STMT_PRINT_CMD $STMT_TEMP_FILE");
473+
exec(escapeshellcmd($STMT_PRINT_CMD) . " " . escapeshellarg($STMT_TEMP_FILE));
474474
if ($_POST['form_without']) {
475475
$alertmsg = xl('Now printing') .' '. $stmt_count .' '. xl('statements; invoices will not be updated.');
476476
} else {
@@ -665,7 +665,7 @@ function npopup(pid) {
665665
// Handle .zip extension if present. Probably won't work on Windows.
666666
if (strtolower(substr($_FILES['form_erafile']['name'], -4)) == '.zip') {
667667
rename($tmp_name, "$tmp_name.zip");
668-
exec("unzip -p $tmp_name.zip > $tmp_name");
668+
exec("unzip -p " . escapeshellarg($tmp_name . ".zip") . " > " . escapeshellarg($tmp_name));
669669
unlink("$tmp_name.zip");
670670
}
671671

interface/fax/fax_dispatch.php

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
//
6565
function getKittens($catid, $catstring, &$categories) {
6666
$cres = sqlStatement("SELECT id, name FROM categories " .
67-
"WHERE parent = $catid ORDER BY name");
67+
"WHERE parent = ? ORDER BY name", array($catid));
6868
$childcount = 0;
6969
while ($crow = sqlFetchArray($cres)) {
7070
++$childcount;
@@ -88,7 +88,7 @@ function mergeTiffs() {
8888
$inames .= ' ' . escapeshellarg("$inbase.tif");
8989
}
9090
if (!$inames) die(xl("Internal error - no pages were selected!"));
91-
$tmp0 = exec("cd '$faxcache'; tiffcp $inames temp.tif", $tmp1, $tmp2);
91+
$tmp0 = exec("cd " . escapeshellarg($faxcache) . "; tiffcp $inames temp.tif", $tmp1, $tmp2);
9292
if ($tmp2) {
9393
$msg .= "tiffcp returned $tmp2: $tmp0 ";
9494
}
@@ -107,7 +107,7 @@ function mergeTiffs() {
107107
if (!$patient_id) die(xl('Internal error - patient ID was not provided!'));
108108
// Compute the name of the target directory and make sure it exists.
109109
$docdir = $GLOBALS['OE_SITE_DIR'] . "/documents/$patient_id";
110-
exec("mkdir -p '$docdir'");
110+
exec("mkdir -p " . escapeshellarg($docdir));
111111

112112
// If copying to patient documents...
113113
//
@@ -134,7 +134,7 @@ function mergeTiffs() {
134134
$info_msg .= mergeTiffs();
135135
// The -j option here requires that libtiff is configured with libjpeg.
136136
// It could be omitted, but the output PDFs would then be quite large.
137-
$tmp0 = exec("tiff2pdf -j -p letter -o '$target' '$faxcache/temp.tif'", $tmp1, $tmp2);
137+
$tmp0 = exec("tiff2pdf -j -p letter -o " . escapeshellarg($target) . " " . escapeshellarg($faxcache . '/temp.tif'), $tmp1, $tmp2);
138138

139139
if ($tmp2) {
140140
$info_msg .= "tiff2pdf returned $tmp2: $tmp0 ";
@@ -153,10 +153,8 @@ function mergeTiffs() {
153153
sqlStatement($query);
154154
$query = "INSERT INTO categories_to_documents ( " .
155155
"category_id, document_id" .
156-
" ) VALUES ( " .
157-
"'$catid', '$newid' " .
158-
")";
159-
sqlStatement($query);
156+
" ) VALUES (?, ?)";
157+
sqlStatement($query, array($catid, $newid));
160158
} // end not error
161159

162160
// If we are posting a note...
@@ -203,24 +201,22 @@ function mergeTiffs() {
203201
// scanned notes must be installed, and does not natively exist.
204202
$query = "INSERT INTO form_scanned_notes ( " .
205203
"notes " .
206-
") VALUES ( " .
207-
"'" . $_POST['form_copy_sn_comments'] . "' " .
208-
")";
209-
$formid = sqlInsert($query);
204+
") VALUES (?)";
205+
$formid = sqlInsert($query, array($_POST['form_copy_sn_comments']));
210206
addForm($encounter_id, "Scanned Notes", $formid, "scanned_notes",
211207
$patient_id, $userauthorized);
212208
//
213209
$imagedir = $GLOBALS['OE_SITE_DIR'] . "/documents/$patient_id/encounters";
214210
$imagepath = "$imagedir/${encounter_id}_$formid.jpg";
215211
if (! is_dir($imagedir)) {
216-
$tmp0 = exec('mkdir -p "' . $imagedir . '"', $tmp1, $tmp2);
212+
$tmp0 = exec('mkdir -p ' . escapeshellarg($imagedir), $tmp1, $tmp2);
217213
if ($tmp2) die("mkdir returned $tmp2: $tmp0");
218-
exec("touch '$imagedir/index.html'");
214+
exec("touch " . escapeshellarg($imagedir . "/index.html"));
219215
}
220216
if (is_file($imagepath)) unlink($imagepath);
221217
// TBD: There may be a faster way to create this file, given that
222218
// we already have a jpeg for each page in faxcache.
223-
$cmd = "convert -resize 800 -density 96 '$tmp_name' -append '$imagepath'";
219+
$cmd = "convert -resize 800 -density 96 " . escapeshellarg($tmp_name) . " -append " . escapeshellarg($imagepath);
224220
$tmp0 = exec($cmd, $tmp1, $tmp2);
225221
if ($tmp2) die("\"$cmd\" returned $tmp2: $tmp0");
226222
}
@@ -271,17 +267,17 @@ function mergeTiffs() {
271267
$cpstring = str_replace('{MESSAGE}' , $form_message , $cpstring);
272268
fwrite($tmph, $cpstring);
273269
fclose($tmph);
274-
$tmp0 = exec("cd $webserver_root/custom; " . $GLOBALS['hylafax_enscript'] .
275-
" -o $tmpfn2 $tmpfn1", $tmp1, $tmp2);
270+
$tmp0 = exec("cd " . escapeshellarg($webserver_root . '/custom') . "; " . escapeshellcmd($GLOBALS['hylafax_enscript']) .
271+
" -o " . escapeshellarg($tmpfn2) . " " . escapeshellarg($tmpfn1), $tmp1, $tmp2);
276272
if ($tmp2) {
277273
$info_msg .= "enscript returned $tmp2: $tmp0 ";
278274
}
279275
unlink($tmpfn1);
280276

281277
// Send the fax as the cover page followed by the selected pages.
282278
$info_msg .= mergeTiffs();
283-
$tmp0 = exec("sendfax -A -n $form_finemode -d " .
284-
escapeshellarg($form_fax) . " $tmpfn2 '$faxcache/temp.tif'",
279+
$tmp0 = exec("sendfax -A -n " . escapeshellarg($form_finemode) . " -d " .
280+
escapeshellarg($form_fax) . " " . escapeshellarg($tmpfn2) . " " . escapeshellarg($faxcache . '/temp.tif'),
285281
$tmp1, $tmp2);
286282
if ($tmp2) {
287283
$info_msg .= "sendfax returned $tmp2: $tmp0 ";
@@ -356,21 +352,21 @@ function mergeTiffs() {
356352
// This will contain a .tif image as well as a .jpg image for each page.
357353
//
358354
if (! is_dir($faxcache)) {
359-
$tmp0 = exec('mkdir -p "' . $faxcache . '"', $tmp1, $tmp2);
355+
$tmp0 = exec('mkdir -p ' . escapeshellarg($faxcache), $tmp1, $tmp2);
360356
if ($tmp2) die("mkdir returned $tmp2: $tmp0");
361357
if (strtolower($ext) != '.tif') {
362358
// convert's default density for PDF-to-TIFF conversion is 72 dpi which is
363359
// not very good, so we upgrade it to "fine mode" fax quality. It's really
364360
// better and faster if the scanner produces TIFFs instead of PDFs.
365-
$tmp0 = exec("convert -density 203x196 '$filepath' '$faxcache/deleteme.tif'", $tmp1, $tmp2);
361+
$tmp0 = exec("convert -density 203x196 " . escapeshellarg($filepath) . " " . escapeshellarg($faxcache . '/deleteme.tif'), $tmp1, $tmp2);
366362
if ($tmp2) die("convert returned $tmp2: $tmp0");
367-
$tmp0 = exec("cd '$faxcache'; tiffsplit 'deleteme.tif'; rm -f 'deleteme.tif'", $tmp1, $tmp2);
363+
$tmp0 = exec("cd " . escapeshellarg($faxcache) . "; tiffsplit 'deleteme.tif'; rm -f 'deleteme.tif'", $tmp1, $tmp2);
368364
if ($tmp2) die("tiffsplit/rm returned $tmp2: $tmp0");
369365
} else {
370-
$tmp0 = exec("cd '$faxcache'; tiffsplit '$filepath'", $tmp1, $tmp2);
366+
$tmp0 = exec("cd " . escapeshellarg($faxcache) . "; tiffsplit " . escapeshellarg($filepath), $tmp1, $tmp2);
371367
if ($tmp2) die("tiffsplit returned $tmp2: $tmp0");
372368
}
373-
$tmp0 = exec("cd '$faxcache'; mogrify -resize 750x970 -format jpg *.tif", $tmp1, $tmp2);
369+
$tmp0 = exec("cd " . escapeshellarg($faxcache) . "; mogrify -resize 750x970 -format jpg *.tif", $tmp1, $tmp2);
374370
if ($tmp2) die("mogrify returned $tmp2: $tmp0; ext is '$ext'; filepath is '$filepath'");
375371
}
376372

interface/fax/faxq.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
if ($GLOBALS['enable_hylafax']) {
2828
// Get the recvq entries, parse and sort by filename.
2929
$statlines = array();
30-
exec("faxstat -r -l -h " . $GLOBALS['hylafax_server'], $statlines);
30+
exec("faxstat -r -l -h " . escapeshellarg($GLOBALS['hylafax_server']), $statlines);
3131
foreach ($statlines as $line) {
3232
// This gets pagecount, sender, time, filename. We are expecting the
3333
// string to start with "-rw-rw-" so as to exclude faxes not yet fully
@@ -46,7 +46,7 @@
4646
154 124 F nobody 6153551807 0:1 4:12 No carrier detected
4747
*/
4848
$donelines = array();
49-
exec("faxstat -s -d -l -h " . $GLOBALS['hylafax_server'], $donelines);
49+
exec("faxstat -s -d -l -h " . escapeshellarg($GLOBALS['hylafax_server']), $donelines);
5050
foreach ($donelines as $line) {
5151
// This gets jobid, priority, statchar, owner, phone, pages, dials and tts/status.
5252
if (preg_match('/^(\d+)\s+(\d+)\s+(\S)\s+(\S+)\s+(\S+)\s+(\d+:\d+)\s+(\d+:\d+)(.*)$/', $line, $matches)) {

interface/main/main_screen.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
/* Include our required headers */
2525
require_once('../globals.php');
2626
require_once("$srcdir/formdata.inc.php");
27+
require_once("../../library/CsrfToken.php");
2728

2829
// Creates a new session id when load this outer frame
2930
// (allows creations of separate LibreHealth EHR frames to view patients concurrently
@@ -41,6 +42,9 @@
4142
session_regenerate_id(false);
4243
}
4344

45+
//generate csrf token
46+
$_SESSION['token'] = CsrfToken::generateCsrfToken();
47+
4448
$_SESSION["encounter"] = '';
4549

4650
// Fetch the password expiration date

interface/main/tabs/js/tabs_view_model.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ function clearPatient()
249249
$.ajax({
250250
type: "POST",
251251
url: webroot_url+"/library/ajax/unset_session_ajax.php",
252-
data: { func: "unset_pid"},
252+
data: { func: "unset_pid", token: jsCsrfToken},
253253
success:function( msg ) {
254254

255255

interface/main/tabs/main.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@ function isEncounterLocked( encounterId ) {
216216
.',' . json_encode($userQuery['fname'])
217217
.',' . json_encode($userQuery['lname'])
218218
.',' . json_encode($_SESSION['authGroup']); ?>));
219+
// Set the csrf token used in js/tabs_view_model.js script
220+
var jsCsrfToken = <?php echo $_SESSION['token'];?>;
219221
</script>
220222

221223
<style type="text/css">

interface/patient_file/encounter/forms.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@
106106
{ amc_id: "patient_edu_amc",
107107
complete: true,
108108
mode: mode,
109+
token: "<?php echo $_SESSION['token'];?>",
109110
patient_id: <?php echo htmlspecialchars($pid,ENT_NOQUOTES); ?>,
110111
object_category: "form_encounter",
111112
object_id: <?php echo htmlspecialchars($encounter,ENT_NOQUOTES); ?>
@@ -125,6 +126,7 @@
125126
{ amc_id: "provide_sum_pat_amc",
126127
complete: true,
127128
mode: mode,
129+
token: "<?php echo $_SESSION['token'];?>",
128130
patient_id: <?php echo htmlspecialchars($pid,ENT_NOQUOTES); ?>,
129131
object_category: "form_encounter",
130132
object_id: <?php echo htmlspecialchars($encounter,ENT_NOQUOTES); ?>
@@ -149,6 +151,7 @@
149151
{ amc_id: "med_reconc_amc",
150152
complete: false,
151153
mode: mode,
154+
token: "<?php echo $_SESSION['token'];?>",
152155
patient_id: <?php echo htmlspecialchars($pid,ENT_NOQUOTES); ?>,
153156
object_category: "form_encounter",
154157
object_id: <?php echo htmlspecialchars($encounter,ENT_NOQUOTES); ?>
@@ -168,6 +171,7 @@
168171
{ amc_id: "med_reconc_amc",
169172
complete: true,
170173
mode: mode,
174+
token: "<?php echo $_SESSION['token'];?>",
171175
patient_id: <?php echo htmlspecialchars($pid,ENT_NOQUOTES); ?>,
172176
object_category: "form_encounter",
173177
object_id: <?php echo htmlspecialchars($encounter,ENT_NOQUOTES); ?>

0 commit comments

Comments
 (0)