App/lib/10_login.php
2020-11-25 17:28:45 +01:00

254 lines
8.8 KiB
PHP

<?php #lib/10_login.php
/********************************************************************************
* Content: Login related functions *
* Author: Nils Otterpohl *
* Last modification: 24.06.2019 *
* Version: alpha (incomplete, tested, commented) *
********************************************************************************/
function lgnGenHash($password, $salt, $iterations, $length = 32, $algo = "sha256") {
return hash_pbkdf2($algo, $password, $salt, $iterations, $length*2);
}
function lgnGenSalt($length = 16) {
return bin2hex(random_bytes($length));
}
function lgnTransformPassword($password = "") {
$salt = lgnGenSalt();
if ($password=="")
$password = lgnGenSalt(8);
return array(
"password" => $password,
"iterations" => DESIRED_ITERATIONS,
"salt" => $salt,
"hash" => lgnGenHash($password, $salt, DESIRED_ITERATIONS)
);
}
function lgnSecSessionStart() {
// Copied and adjusted after https://de.wikihow.com/Ein-sicheres-Login-Skript-mit-PHP-und-MySQL-erstellen
// Zwingt die Sessions nur Cookies zu benutzen.
if (ini_set("session.use_only_cookies", 1) === FALSE) {
exit();
}
// Holt Cookie-Parameter.
$cookieParams = session_get_cookie_params();
// Erstes true = Nur https Zugriff, Zweites true = Blockt JavaScript Zugriff
session_set_cookie_params($cookieParams["lifetime"], $cookieParams["path"], $cookieParams["domain"], true, true);
$sessionName = "SessionOfHigherSecureness";
session_name($sessionName);
session_start(); // Startet die PHP-Sitzung
session_regenerate_id(); // Erneuert die Session, löscht die alte.
}
function lgnRegenerateToken() {
if (isset($_SESSION["secTokenUse"])) {
$_SESSION["secTokenVerify"] = $_SESSION["secTokenUse"];
} else {
$_SESSION["secTokenVerify"] = "";
}
$_SESSION["secTokenUse"] = lgnGenSalt(16);
}
function lgnLogin($mysqli, $login, $password) {
// Copied and adjusted after https://de.wikihow.com/Ein-sicheres-Login-Skript-mit-PHP-und-MySQL-erstellen
// and https://github.com/nextcloud/user_external/blob/master/lib/webdavauth.php
// Das Benutzen vorbereiteter Statements verhindert SQL-Injektion.
$login = strtolower($login);
$login = str_replace("@feuerwehr-bs.net", "", $login);
if ($stmt = $mysqli->prepare("SELECT p.ID, p.login FROM Personal p WHERE p.login = ? LIMIT 1")) {
$stmt->bind_param("s", $login); // Bind "$login" to parameter.
$stmt->execute(); // Führe die vorbereitete Anfrage aus.
$stmt->store_result();
// hole Variablen von result.
$stmt->bind_result($userID, $userLogin);
$stmt->fetch();
if ($stmt->num_rows == 1) {
$url= 'https://'.urlencode($userLogin).':'.urlencode($password).'@feuerwehr-bs.net/webdav';
$headers = get_headers($url);
if($headers === false) {
addError("loginFailed", 'ERROR: Not possible to connect to WebDAV Url: "https://feuerwehr-bs.net/webdav"');
return false;
}
$returnCode= substr($headers[0], 9, 3);
if(substr($returnCode, 0, 1) === '2') {
// Passwort ist korrekt!
// Hole den user-agent string des Benutzers.
$userBrowser = $_SERVER["HTTP_USER_AGENT"];
// XSS-Schutz, denn eventuell wird der Wert gedruckt
$userID = preg_replace("/[^0-9]+/", "", $userID);
$_SESSION["userID"] = $userID;
// XSS-Schutz, denn eventuell wird der Wert gedruckt
$userLogin = preg_replace("/[^a-zA-Z0-9_\-]+/", "", $userLogin);
$_SESSION["userLogin"] = $userLogin;
// Generiere einen Hash aus dem Passwort mit zufälligem Salt und speichere ihn in der Datenbank
$hash = lgnGenHash($password, lgnGenSalt(), DESIRED_ITERATIONS);
$_SESSION["loginString"] = lgnGenHash($hash, $userBrowser, 10, 64, "sha512");
$mysqli->query("REPLACE INTO sys_iservhashes(ID, Hash) VALUES ('".$userID."', '".$hash."')");
// Login erfolgreich.
return true;
} else {
// Passwort ist nicht korrekt
addError("loginFailed", " Passwort nicht korrekt. Fehlercode (bitte an Nils senden): ".$returnCode);
}
} else {
addError("loginFailed", "Benutzername inkorrekt ".$login);
}
}
if ($mysqli->error!="") {
addError("mysql", $mysqli->error);
}
return false;
}
function lgnLogout() {
// Setze alle Session-Werte zurück
$_SESSION = array();
// hole Session-Parameter
$params = session_get_cookie_params();
// Lösche das aktuelle Cookie.
setcookie(
session_name(),
'',
time() - 42000,
$params["path"],
$params["domain"],
$params["secure"],
$params["httponly"]
);
// Vernichte die Session
session_destroy();
header('Location: index.php');
}
function lgnChangePass($mysqli, $userID, $passOld, $passNew, $passRepeat) {
$ret = false;
if ($passOld==$passNew) {
addError("passChangeFail", "Neues und altes Passwort sind nicht unterschiedlich?");
} else if (strlen($passNew)<12) {
addError("passChangeFail", "Passwort muss mindestens 12 Zeichen haben!");
} else if ($passNew!=$passRepeat) {
addError("passChangeFail", "Passwortwiederholung falsch!");
} else {
if ($stmt = $mysqli->prepare("SELECT iterations, salt, hash FROM users WHERE ID = ? LIMIT 1")) {
$stmt->bind_param("i", $_SESSION["userID"]);
$stmt->execute();
$stmt->store_result();
$stmt->bind_result($passIterations, $passSalt, $passHash);
$stmt->fetch();
if ($stmt->num_rows == 1) {
if (lgnGenHash($passOld, $passSalt, $passIterations)!=$passHash) {
addError("passChangeFail", "Altes Passwort inkorrekt!");
} else {
$newSalt = lgnGenSalt();
$newHash = lgnGenHash($passNew, $newSalt, DESIRED_ITERATIONS);
$mysqli->query("UPDATE users SET iterations='".DESIRED_ITERATIONS."', salt='".$newSalt."', hash='".$newHash."' "
."WHERE ID='".$_SESSION["userID"]."'");
$userBrowser = $_SERVER["HTTP_USER_AGENT"];
$_SESSION["loginString"] = lgnGenHash($newHash, $userBrowser, 10, 64, "sha512");
$ret = true;
}
}
} else {
addError("passChangeFailed", $mysqli->error);
}
}
return $ret;
}
function lgnCheckBrute($mysqli, $userID) {
// Copied and adjusted after https://de.wikihow.com/Ein-sicheres-Login-Skript-mit-PHP-und-MySQL-erstellen
// Hole den aktuellen Zeitstempel
// Alle Login-Versuche der letzten zwei Stunden werden gezählt.
if ($stmt = $mysqli->prepare("SELECT time FROM failedlogins WHERE ID = ? AND time > DATE_SUB(NOW(), INTERVAL 2 HOUR)")) {
$stmt->bind_param("i", $userID);
// Führe die vorbereitet Abfrage aus.
$stmt->execute();
$stmt->store_result();
// Wenn es mehr als 5 fehlgeschlagene Versuche gab
if ($stmt->num_rows > 5) {
return true;
}
}
return false;
}
function lgnCheckLogin($mysqli) {
// Überprüfe, ob alle Session-Variablen gesetzt sind
if (isset($_SESSION["userID"], $_SESSION["userLogin"], $_SESSION["loginString"])) {
$userID = $_SESSION["userID"];
$loginString = $_SESSION["loginString"];
$userLogin = $_SESSION["userLogin"];
// Hole den user-agent string des Benutzers.
$userBrowser = $_SERVER["HTTP_USER_AGENT"];
// Die UserID wird hier nochmal abgerufen, damit dem Rückgabewert der Funktion vertraut werden kann
if ($stmt = $mysqli->prepare("SELECT ID, Hash FROM sys_iservhashes WHERE ID = ? LIMIT 1")) {
$stmt->bind_param("i", $userID);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows == 1) {
// Wenn es den Benutzer gibt, hole die Variablen von result.
$stmt->bind_result($uID, $uHash);
$stmt->fetch();
if (lgnGenHash($uHash, $userBrowser, 10, 64, "sha512") == $loginString) {
// Eingeloggt!!!!
return $uID;
}
}
}
}
// Nicht eingeloggt
if ($mysqli->error!="") {
addError("mysql", $mysqli->error);
}
return false;
}
function lgnCheckRight($mysqli, $right, $userID = null) {
if ($right==null) {
return true;
}
if ($userID==null) {
$userID = lgnCheckLogin($mysqli);
}
$query = "SELECT b.name FROM Personal p "
."LEFT JOIN link_Personal_Personalgruppen lpp ON p.ID=lpp.Personal "
."LEFT JOIN link_Berechtigungen_Personalgruppen lbp ON lbp.Personalgruppen = lpp.Personalgruppen "
."LEFT JOIN Berechtigungen b ON b.ID = lbp.Berechtigungen "
."WHERE p.ID = ".$userID." and b.Name ";
if (is_array($right)) {
$query.= "IN ('".implode("', '", $right)."')";
} else {
$query.= "= '".$right."'";
}
if ($res = $mysqli->query($query)) {
if ($res->num_rows>0) {
return true;
}
}
return false;
}
?>