Sicherheit: Passkey-Registrierung nur mit Freigabe durch Superadmin
authServer.php nahm getCreateArgs/processCreate ohne jede Pruefung an und uebernahm die Benutzer-id aus der URL. Jeder konnte damit aus dem Internet einen Passkey fuer ein beliebiges Konto (auch Superadmin) registrieren und sich anschliessend anmelden. - sites/userkeys.php loest den addKey ein und legt eine Freigabe in der Session ab (5 Minuten, ein Benutzer, einmalig); der addKey wird geloescht - authServer.php verlangt fuer getCreateArgs/processCreate Login, Superadmin-Recht und diese Freigabe; die Benutzer-id kommt aus der Freigabe, nicht aus der URL - queryFidoMetaDataService nur fuer Superadmins - Passkey-Login verweigert gesperrte Benutzer und meldet keinen Erfolg mehr, wenn der Benutzer fehlt - addKey.php verlangt wie userkeys.php das Superadmin-Recht - session_regenerate_id() nach Passwort- und Passkey-Login - userkeys.php/addKey.php: $_GET["id"] als int statt ungequotet in SQL Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+4
-3
@@ -16,7 +16,8 @@ if($settings == "valid")
|
|||||||
if(!@mysqli_select_db($dbconn,$mysql_db))
|
if(!@mysqli_select_db($dbconn,$mysql_db))
|
||||||
$err = error("Datenbank nicht gefunden!! ($mysql_db)");
|
$err = error("Datenbank nicht gefunden!! ($mysql_db)");
|
||||||
}
|
}
|
||||||
if($_SESSION["login"] == "valid" && isset($_GET["id"])){
|
// Wie sites/userkeys.php: nur Superadmins dürfen Passkeys vergeben
|
||||||
|
if($_SESSION["login"] == "valid" && isset($_GET["id"]) && ((int)substr($_SESSION["rights"], RIGHTS_SUPERADMIN, 1) & RIGHTS_CHANGE)){
|
||||||
if(!mysqli_query($dbconn,"DELETE FROM addKey WHERE datetime < DATE_SUB(NOW(), INTERVAL 1 MINUTE);")){
|
if(!mysqli_query($dbconn,"DELETE FROM addKey WHERE datetime < DATE_SUB(NOW(), INTERVAL 1 MINUTE);")){
|
||||||
echo mysqli_error($dbconn);
|
echo mysqli_error($dbconn);
|
||||||
}
|
}
|
||||||
@@ -25,8 +26,8 @@ if($_SESSION["login"] == "valid" && isset($_GET["id"])){
|
|||||||
if(!mysqli_query($dbconn,"INSERT INTO addKey SET accesskey=".$accessKey.", datetime=NOW();")){
|
if(!mysqli_query($dbconn,"INSERT INTO addKey SET accesskey=".$accessKey.", datetime=NOW();")){
|
||||||
echo mysqli_error($dbconn);
|
echo mysqli_error($dbconn);
|
||||||
}
|
}
|
||||||
header('Location: https://wm.el-wa.org/kunden?action=userkeys&id='.$_GET["id"].'&addKey='.$accessKey);
|
header('Location: https://wm.el-wa.org/kunden?action=userkeys&id='.(int)$_GET["id"].'&addKey='.$accessKey);
|
||||||
echo 'https://wm.el-wa.org/kunden?action=userkeys&id='.$_GET["id"].'&addKey='.$accessKey;
|
echo 'https://wm.el-wa.org/kunden?action=userkeys&id='.(int)$_GET["id"].'&addKey='.$accessKey;
|
||||||
}else{
|
}else{
|
||||||
echo "Keine Berechtigung.";
|
echo "Keine Berechtigung.";
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-3
@@ -107,6 +107,24 @@ try {
|
|||||||
// request for create arguments
|
// request for create arguments
|
||||||
// ------------------------------------
|
// ------------------------------------
|
||||||
|
|
||||||
|
// Passkeys anlegen darf nur ein angemeldeter Superadmin, der vorher in
|
||||||
|
// sites/userkeys.php eine gültige Einmal-Freigabe (addKey) eingelöst hat.
|
||||||
|
// Die Freigabe liegt in der Session und legt fest, für welchen Benutzer
|
||||||
|
// der Schlüssel gilt - die id aus der URL zählt nicht.
|
||||||
|
$passkeyFreigabe = null;
|
||||||
|
if (isset($_SESSION["passkey_freigabe"]) && $_SESSION["passkey_freigabe"]["bis"] >= time()
|
||||||
|
&& ($_SESSION["login"] ?? "") == "valid"
|
||||||
|
&& ((int)substr($_SESSION["rights"] ?? "", RIGHTS_SUPERADMIN, 1) & RIGHTS_CHANGE)) {
|
||||||
|
$passkeyFreigabe = $_SESSION["passkey_freigabe"];
|
||||||
|
}
|
||||||
|
if (($fn === 'getCreateArgs' || $fn === 'processCreate') && $passkeyFreigabe === null) {
|
||||||
|
throw new Exception('Keine Berechtigung, Passkeys anzulegen.');
|
||||||
|
}
|
||||||
|
if ($fn === 'queryFidoMetaDataService'
|
||||||
|
&& !(($_SESSION["login"] ?? "") == "valid" && ((int)substr($_SESSION["rights"] ?? "", RIGHTS_SUPERADMIN, 1) & RIGHTS_CHANGE))) {
|
||||||
|
throw new Exception('Keine Berechtigung.');
|
||||||
|
}
|
||||||
|
|
||||||
if ($fn === 'getCreateArgs') {
|
if ($fn === 'getCreateArgs') {
|
||||||
$createArgs = $WebAuthn->getCreateArgs(\hex2bin($userId), $userName, $userDisplayName, 60*4, $requireResidentKey, $userVerification, $crossPlatformAttachment);
|
$createArgs = $WebAuthn->getCreateArgs(\hex2bin($userId), $userName, $userDisplayName, 60*4, $requireResidentKey, $userVerification, $crossPlatformAttachment);
|
||||||
|
|
||||||
@@ -181,10 +199,12 @@ try {
|
|||||||
if (!isset($_SESSION['registrations']) || !array_key_exists('registrations', $_SESSION) || !is_array($_SESSION['registrations'])) {
|
if (!isset($_SESSION['registrations']) || !array_key_exists('registrations', $_SESSION) || !is_array($_SESSION['registrations'])) {
|
||||||
$_SESSION['registrations'] = [];
|
$_SESSION['registrations'] = [];
|
||||||
}*/
|
}*/
|
||||||
if(!mysqli_query($dbconn,"INSERT INTO passkeys SET credentialId = '".base64_encode($data->credentialId)."', credentialPublicKey = '".base64_encode($data->credentialPublicKey)."', signatureCounter = '".base64_encode($data->signatureCounter)."', name = '".mysqli_real_escape_string($mysql,filter_input(INPUT_GET, 'name'))."', userId = '".mysqli_real_escape_string($mysql,filter_input(INPUT_GET, 'id'))."';")){
|
if(!mysqli_query($dbconn,"INSERT INTO passkeys SET credentialId = '".base64_encode($data->credentialId)."', credentialPublicKey = '".base64_encode($data->credentialPublicKey)."', signatureCounter = '".base64_encode($data->signatureCounter)."', name = '".mysqli_real_escape_string($mysql,filter_input(INPUT_GET, 'name'))."', userId = '".(int)$passkeyFreigabe["user"]."';")){
|
||||||
$msg = "Error:<br>".mysqli_error($dbconn)."<br />";
|
$msg = "Error:<br>".mysqli_error($dbconn)."<br />";
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
// Freigabe gilt für genau einen Schlüssel
|
||||||
|
unset($_SESSION["passkey_freigabe"]);
|
||||||
if ($data->rootValid === false) {
|
if ($data->rootValid === false) {
|
||||||
$msg = 'registration ok, but certificate does not match any of the selected root ca. NO PROBLEM FOR THIS APP';
|
$msg = 'registration ok, but certificate does not match any of the selected root ca. NO PROBLEM FOR THIS APP';
|
||||||
}
|
}
|
||||||
@@ -253,10 +273,16 @@ try {
|
|||||||
|
|
||||||
$authKey = strval(random_int(0,99999999));
|
$authKey = strval(random_int(0,99999999));
|
||||||
$result = mysqli_query($dbconn,"UPDATE passkeys SET authKey=".$authKey.", lastAuth=NOW() WHERE credentialId = '".base64_encode($id)."';");
|
$result = mysqli_query($dbconn,"UPDATE passkeys SET authKey=".$authKey.", lastAuth=NOW() WHERE credentialId = '".base64_encode($id)."';");
|
||||||
$qry= mysqli_query($dbconn, "SELECT * FROM user WHERE id = '".mysqli_real_escape_string($dbconn,$userId)."'");
|
// Gesperrte Benutzer bleiben gesperrt, auch mit gültigem Passkey
|
||||||
if(mysqli_num_rows($qry) == 1)
|
$qry= mysqli_query($dbconn, "SELECT * FROM user WHERE id = '".mysqli_real_escape_string($dbconn,$userId)."' AND blocked = 0");
|
||||||
|
if(!$qry || mysqli_num_rows($qry) != 1)
|
||||||
|
{
|
||||||
|
throw new Exception('Benutzer nicht gefunden oder gesperrt.');
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
$udata = mysqli_fetch_assoc($qry);
|
$udata = mysqli_fetch_assoc($qry);
|
||||||
|
session_regenerate_id(true);
|
||||||
$_SESSION["login"] = "valid";
|
$_SESSION["login"] = "valid";
|
||||||
$_SESSION["logedout"] = $udata["logedout"];
|
$_SESSION["logedout"] = $udata["logedout"];
|
||||||
$_SESSION["user"] = $udata["id"];
|
$_SESSION["user"] = $udata["id"];
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ if(isset($_GET["formsent"]) && $_SESSION["login"] != "valid" && isLocal())
|
|||||||
if(mysqli_num_rows($qry) == 1)
|
if(mysqli_num_rows($qry) == 1)
|
||||||
{
|
{
|
||||||
$udata = mysqli_fetch_assoc($qry);
|
$udata = mysqli_fetch_assoc($qry);
|
||||||
|
// neue Session-ID nach dem Login, sonst ist Session-Fixation möglich
|
||||||
|
session_regenerate_id(true);
|
||||||
$_SESSION["login"] = "valid";
|
$_SESSION["login"] = "valid";
|
||||||
$_SESSION["logedout"] = $udata["logedout"];
|
$_SESSION["logedout"] = $udata["logedout"];
|
||||||
$_SESSION["user"] = $udata["id"];
|
$_SESSION["user"] = $udata["id"];
|
||||||
|
|||||||
+8
-3
@@ -2,7 +2,12 @@
|
|||||||
|
|
||||||
|
|
||||||
if(isset($_GET["id"]) && isset($_GET["addKey"])){
|
if(isset($_GET["id"]) && isset($_GET["addKey"])){
|
||||||
if (checkAdduser($_GET["addUser"])) {
|
if (checkAdduser()) {
|
||||||
|
// Freigabe einlösen: gilt 5 Minuten, nur für diesen Benutzer und nur
|
||||||
|
// in dieser Session (geprüft in authServer.php). Der addKey ist damit
|
||||||
|
// verbraucht.
|
||||||
|
$_SESSION["passkey_freigabe"] = array("user" => (int)$_GET["id"], "bis" => time() + 300);
|
||||||
|
mysqli_query($mysql, "DELETE FROM addKey WHERE accesskey = '".mysqli_real_escape_string($mysql, $_GET["addKey"])."'");
|
||||||
echo <<<ENDE
|
echo <<<ENDE
|
||||||
<html>
|
<html>
|
||||||
<head></head>
|
<head></head>
|
||||||
@@ -73,11 +78,11 @@ if(isset($_GET["id"]) && isset($_GET["addKey"])){
|
|||||||
$smarty->assign("heading","Passkeys für externen Zugang verwalten");
|
$smarty->assign("heading","Passkeys für externen Zugang verwalten");
|
||||||
$smarty->display("heading.tpl");
|
$smarty->display("heading.tpl");
|
||||||
|
|
||||||
$qry = mysqli_query($_SESSION["dbconn"],"SELECT id, vname, nname FROM user WHERE blocked = 0 AND user.id = ".mysqli_real_escape_string($_SESSION["dbconn"],$_GET["id"])) or die("Datenbank fehler: ".mysqli_error($_SESSION["dbconn"]));
|
$qry = mysqli_query($_SESSION["dbconn"],"SELECT id, vname, nname FROM user WHERE blocked = 0 AND user.id = ".(int)$_GET["id"]) or die("Datenbank fehler: ".mysqli_error($_SESSION["dbconn"]));
|
||||||
$row=mysqli_fetch_array($qry);
|
$row=mysqli_fetch_array($qry);
|
||||||
$smarty->assign("user",$row);
|
$smarty->assign("user",$row);
|
||||||
|
|
||||||
$qry = mysqli_query($_SESSION["dbconn"],"SELECT passkeys.id , passkeys.name FROM user JOIN passkeys ON user.id = passkeys.userId WHERE blocked = 0 AND user.id = ".mysqli_real_escape_string($_SESSION["dbconn"],$_GET["id"])) or die("Datenbank fehler: ".mysqli_error($_SESSION["dbconn"]));
|
$qry = mysqli_query($_SESSION["dbconn"],"SELECT passkeys.id , passkeys.name FROM user JOIN passkeys ON user.id = passkeys.userId WHERE blocked = 0 AND user.id = ".(int)$_GET["id"]) or die("Datenbank fehler: ".mysqli_error($_SESSION["dbconn"]));
|
||||||
$keys = array();
|
$keys = array();
|
||||||
while($row=mysqli_fetch_array($qry)){
|
while($row=mysqli_fetch_array($qry)){
|
||||||
$keys[] = $row;
|
$keys[] = $row;
|
||||||
|
|||||||
Reference in New Issue
Block a user