diff --git a/lib/KaraDAV/Users.php b/lib/KaraDAV/Users.php index 09aee70..7cfadc8 100644 --- a/lib/KaraDAV/Users.php +++ b/lib/KaraDAV/Users.php @@ -8,6 +8,14 @@ class Users { protected ?stdClass $current = null; + public function __construct() + { + if (!session_id()) { + // Protect the cookie : CSRF/JS stealing the cookie + session_set_cookie_params(['samesite' => 'Lax', 'httponly' => true]); + } + } + static public function generatePassword(): string { $password = base64_encode(random_bytes(16)); diff --git a/www/_inc.php b/www/_inc.php index 9eedacf..2075219 100644 --- a/www/_inc.php +++ b/www/_inc.php @@ -25,21 +25,16 @@ if (!file_exists(DB_FILE)) { $db->exec(file_get_contents(__DIR__ . '/../schema.sql')); if (!LDAP::enabled()) { - @session_start(); $users = new Users; $p = 'karadavdemo'; $users->create('demo', $p, 10, true); - $_SESSION['install_password'] = $p; $users->login('demo', $p); + $_SESSION['install_password'] = $p; } $db->exec('END;'); } -if (isset($_COOKIE[session_name()]) && !isset($_SESSION)) { - @session_start(); -} - function html_head(string $title): void { $title = htmlspecialchars($title); @@ -102,3 +97,45 @@ function http_log(string $message, ...$params): void file_put_contents(LOG_FILE, $msg, FILE_APPEND); } } + +function html_csrf() +{ + $expire = time() + 1800; + $random = random_bytes(10); + $action = $_SERVER['REQUEST_URI']; + $token = hash_hmac('sha256', $expire . $random . $action, STORAGE_PATH . session_id()); + + return sprintf('', $token, base64_encode($random), $expire); +} + +function csrf_check(): bool +{ + if (empty($_POST['_c_'])) { + return false; + } + + $verify = strtok($_POST['_c_'], ':'); + $random = base64_decode(strtok(':')); + $expire = strtok(false); + + if ($expire < time()) { + return false; + } + + $action = $_SERVER['REQUEST_URI']; + + $token = hash_hmac('sha256', $expire . $random . $action, STORAGE_PATH . session_id()); + + return hash_equals($token, $verify); +} + +function html_csrf_error() +{ + if (empty($_POST['_c_'])) { + return; + } + + if (!csrf_check()) { + echo '
Sorry, but the form expired, please submit it again.
'; + } +} diff --git a/www/login.php b/www/login.php index 739e492..f2dccdf 100644 --- a/www/login.php +++ b/www/login.php @@ -13,7 +13,7 @@ if (empty($_GET['nc']) && $users->current()) { $error = 0; -if (!empty($_POST['login']) && !empty($_POST['password'])) { +if (!empty($_POST['login']) && !empty($_POST['password']) && csrf_check()) { if ($users->login($_POST['login'], $_POST['password'])) { $url = null; @@ -55,9 +55,11 @@ echo ' if (isset($_GET['nc'])) { printf('', htmlspecialchars($_GET['nc'])); - echo 'The NextCloud app is trying to access your data. Please login to continue.
'; + echo 'An external application is trying to access your data. Please login to continue and allow access.
'; } +echo html_csrf(); + echo ' + '; } elseif ($delete) { + $csrf = html_csrf(); $login = htmlspecialchars($user->login); echo <<