Skip to content

Commit cf9da6f

Browse files
Adress security issues
1 parent 351a6cf commit cf9da6f

5 files changed

Lines changed: 57 additions & 7 deletions

File tree

src/_server/ajaxServer.php

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -318,12 +318,40 @@
318318
if (!$c["pass"]) { $allPass = false; break; }
319319
}
320320

321-
$return["status"] = $allPass ? "success" : "fail";
322-
$return["checks"] = $checks;
321+
$_SESSION["setup_csrf"] = bin2hex(random_bytes(16));
322+
$return["status"] = $allPass ? "success" : "fail";
323+
$return["checks"] = $checks;
323324
$return["alreadySetup"] = false;
325+
$return["csrf"] = $_SESSION["setup_csrf"];
324326
break;
325327

326328
case "setupInit":
329+
// Guard: reject if setup has already been completed
330+
$alreadySetup = file_exists($conf["dir"]["data"]."/users.json")
331+
&& file_exists($conf["dir"]["data"]."/config.json")
332+
&& file_exists($conf["dir"]["data"]."/tagdefinitions.json");
333+
if ($alreadySetup) {
334+
$return["status"] = "fail";
335+
$return["code"] = 0;
336+
$return["string"] = "Already installed";
337+
break;
338+
}
339+
// CSRF validation — token was issued by setupCheckDetailed and stored in session
340+
if (empty($_SESSION["setup_csrf"]) || $_REQUEST["csrf"] !== $_SESSION["setup_csrf"]) {
341+
$return["status"] = "fail";
342+
$return["code"] = 0;
343+
$return["string"] = "Invalid request";
344+
break;
345+
}
346+
unset($_SESSION["setup_csrf"]); // one-time token — consume immediately
347+
// Input length limits
348+
if (strlen(isset($_REQUEST["passwd"]) ? $_REQUEST["passwd"] : '') > 1024
349+
|| strlen(isset($_REQUEST["name"]) ? $_REQUEST["name"] : '') > 200) {
350+
$return["status"] = "fail";
351+
$return["code"] = 2;
352+
$return["string"] = "Input too long";
353+
break;
354+
}
327355
$errorCnt = 0;
328356
if (!file_exists($conf["dir"]["data"]) && !is_dir($conf["dir"]["data"])) {
329357
if (!mkdir($conf["dir"]["data"])) {
@@ -372,6 +400,8 @@
372400
$val = $_REQUEST[$key];
373401
if ($val === "true") $val = true;
374402
if ($val === "false") $val = false;
403+
// Sanitize theme: allow only safe identifier characters
404+
if ($key === "theme") { $val = preg_replace('/[^a-z0-9_-]/', '', strtolower((string)$val)); }
375405
$tmpConf[$key] = $val;
376406
}
377407
}

src/_server/config.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
<?php
22
error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING);
33

4+
$_isHttps = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
5+
|| (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https');
6+
session_set_cookie_params([
7+
'lifetime' => 0,
8+
'path' => '/',
9+
'httponly' => true,
10+
'samesite' => 'Lax',
11+
'secure' => $_isHttps,
12+
]);
413
session_start();
514

615
//DIR

src/_server/user.php

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,15 @@
99
function userGet($userID) {
1010
global $conf;
1111

12-
$json = file_get_contents($conf["dir"]["data"]."/users.json");
12+
$userFile = $conf["dir"]["data"]."/users.json";
13+
if (!file_exists($userFile)) {
14+
$return["status"] = "fail";
15+
$return["code"] = 4;
16+
$return["string"] = "Could not find user database";
17+
return $return;
18+
}
19+
20+
$json = file_get_contents($userFile);
1321

1422
$uDB = json_decode($json,true);
1523
//if ($_SESSION["ohv"]["projects"][$projectID]["user"]["role"] != "admin") {
@@ -81,7 +89,7 @@ function userRegister($name, $mail, $passwd) {
8189
$user["user"][$user["user-increment"]]["name"] = $name;
8290
$user["user"][$user["user-increment"]]["mail"] = strtolower($mail);
8391
$user["user"][$user["user-increment"]]["registrationDate"] = time();
84-
$user["user"][$user["user-increment"]]["passwd"] = hash("sha256",$passwd.$user["user"][$user["user-increment"]]["registrationDate"]);
92+
$user["user"][$user["user-increment"]]["passwd"] = password_hash($passwd, PASSWORD_DEFAULT);
8593
$user["user"][$user["user-increment"]]["role"] = (($tmpFirstUser) ? "admin" : $configDB["defaultUserRole"]);
8694
$user["user"][$user["user-increment"]]["active"] = (($tmpFirstUser) ? 1 : (($configDB["userNeedsConfirmation"]) ? 0 : 1));
8795
$user["user"][$user["user-increment"]]["lastLogin"] = "";
@@ -155,7 +163,7 @@ function userLogin($mail, $passwd) {
155163
$file->close();
156164
return $return;
157165
}
158-
if ($user["passwd"] != hash("sha256",$passwd.$user["registrationDate"])) {
166+
if (!password_verify($passwd, $user["passwd"])) {
159167
$return["status"] = "fail";
160168
$return["code"] = 3;
161169
$return["string"] = "Wrong password!";
@@ -328,7 +336,7 @@ function userChange($userID,$mail,$name,$passwd,$color,$role,$active) {
328336
$userdb["user"][$userID]["mail"] = $mail;
329337
$userdb["user"][$userID]["color"] = $color;
330338
$userdb["user"][$userID]["active"] = ((($active==="1" || $active==="0") && (($_SESSION["ohv"]["user"]["role"] == "admin"))) ? $active*1 : $userdb["user"][$userID]["active"]*1);
331-
$userdb["user"][$userID]["passwd"] = ($passwd) ? hash("sha256",$passwd.$userdb["user"][$userID]["registrationDate"]) : $userdb["user"][$userID]["passwd"];
339+
$userdb["user"][$userID]["passwd"] = ($passwd) ? password_hash($passwd, PASSWORD_DEFAULT) : $userdb["user"][$userID]["passwd"];
332340
$file->write(json_encode($userdb, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
333341
$return["status"] = "success";
334342
$return["string"] = "userdata updated";

src/_shared/modules/UserManagement/module.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ FrameTrail.defineModule('UserManagement', function(FrameTrail){
221221
data: "a=userGet",
222222
success: function(data) {
223223

224-
if (!data.response) {
224+
if (!data || !data.response) {
225225
console.error(labels['ErrorNoUserFile']);
226226
return;
227227
}

src/setup.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,7 @@ <h2 style="text-align:center">You&#8217;re all set!</h2>
663663

664664
var currentStep = 1;
665665
var preflightOk = false;
666+
var csrfToken = '';
666667

667668
var btnBack = document.getElementById('btn-back');
668669
var btnNext = document.getElementById('btn-next');
@@ -828,6 +829,7 @@ <h2 style="text-align:center">You&#8217;re all set!</h2>
828829
setCheckState(key, c.pass ? 'pass' : 'fail', c.detail);
829830
if (!c.pass) allPass = false;
830831
});
832+
csrfToken = data.csrf || '';
831833
preflightOk = allPass;
832834
btnNext.disabled = !allPass;
833835
if (!allPass) document.getElementById('recheck-btn').style.display = '';
@@ -937,6 +939,7 @@ <h2 style="text-align:center">You&#8217;re all set!</h2>
937939

938940
var params = new URLSearchParams();
939941
params.set('a', 'setupInit');
942+
params.set('csrf', csrfToken);
940943
params.set('mail', document.getElementById('field-email').value.trim());
941944
params.set('name', document.getElementById('field-name').value.trim());
942945
params.set('passwd', document.getElementById('field-password').value);

0 commit comments

Comments
 (0)