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 '
Login diff --git a/www/users.php b/www/users.php index 464ba40..56c249b 100644 --- a/www/users.php +++ b/www/users.php @@ -31,12 +31,12 @@ elseif (isset($_GET['create']) && !$ldap) { $create = true; } -if ($create && !empty($_POST['create']) && !empty($_POST['login']) && !empty($_POST['password'])) { +if ($create && !empty($_POST['create']) && !empty($_POST['login']) && !empty($_POST['password']) && csrf_check()) { $users->create(trim($_POST['login']), trim($_POST['password'])); header('Location: ' . WWW_URL . 'users.php'); exit; } -elseif ($edit && !empty($_POST['save']) && !empty($_POST['login'])) { +elseif ($edit && !empty($_POST['save']) && !empty($_POST['login']) && csrf_check()) { if (!$ldap && empty($_POST['is_admin']) && $user->id == $me->id) { die("You cannot remove yourself from admins, ask another admin to do it."); } @@ -56,7 +56,7 @@ elseif ($edit && !empty($_POST['save']) && !empty($_POST['login'])) { header('Location: ' . WWW_URL . 'users.php'); exit; } -elseif ($delete && !empty($_POST['delete'])) { +elseif ($delete && !empty($_POST['delete']) && csrf_check()) { $users->delete($user); header('Location: ' . WWW_URL . 'users.php'); exit; @@ -64,9 +64,13 @@ elseif ($delete && !empty($_POST['delete'])) { html_head('Manage users'); +html_csrf_error(); + if ($create) { + $csrf = html_csrf(); echo << + {$csrf}
Create a new user
@@ -77,14 +81,17 @@ if ($create) {
+ EOF; } elseif ($edit) { + $csrf = html_csrf(); $login = htmlspecialchars($user->login); $is_admin = $user->is_admin ? 'checked="checked"' : ''; $quota = $user ? round($user->quota / 1024 / 1024) : DEFAULT_QUOTA; echo '
+ ' . $csrf . '
Edit user
'; @@ -106,17 +113,21 @@ elseif ($edit) {
-
'; +
+ '; } elseif ($delete) { + $csrf = html_csrf(); $login = htmlspecialchars($user->login); echo << + {$csrf}
Delete user

Do you want to delete the user "{$login}" and all their files?

+ EOF; } else {