Drafted this up today out of the need for a very simple php based login form to protect an html page.
The app is simply included the top of index.html
like this:
<?php require_once('./login.php'); ?>
Usernames are stored in a flat csv file 3 levels up (just above docroot). For this particular application I am not concerned about storing the passwords as plaintext since documents outside the docroot should be unreadable to anyone without server access.
The logins.csv file looks like this:
username1,password1 username2,password2
etc.
The authentication file itself uses an adaptation of this template and is as follows:
if (!session_id()) { ini_set('session.use_cookies', 'On'); ini_set('session.use_trans_sid', 'Off'); session_set_cookie_params(0, '/'); session_start(); } $title = '{title of this website}'; $favicon = '{url link to favicon image}'; $warning = false; if ($_SERVER['REQUEST_METHOD'] == 'POST') { $_SESSION['logged'] = validate($_POST); if ($_SESSION['logged']) { header("Location: " . $_SERVER['REQUEST_URI']); } else { $warning = "Invalid Login. Please Try Again."; } } $loginForm = ' <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>' . $title . '</title> <link rel="shortcut icon" href="' . $favicon . '" /> <style> @import url(https://fonts.googleapis.com/css?family=Roboto:300); .login-page { width: 360px; padding: 8% 0 0; margin: auto; } .form { position: relative; z-index: 1; background: #FFFFFF; max-width: 360px; margin: 0 auto 100px; padding: 45px; text-align: center; box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24); } .form input { font-family: "Roboto", sans-serif; outline: 0; background: #f2f2f2; width: 100%; border: 0; margin: 0 0 15px; padding: 15px; box-sizing: border-box; font-size: 14px; } .form button { font-family: "Roboto", sans-serif; text-transform: uppercase; outline: 0; background: #4CAF50; width: 100%; border: 0; padding: 15px; color: #FFFFFF; font-size: 14px; -webkit-transition: all 0.3 ease; transition: all 0.3 ease; cursor: pointer; } .form button:hover,.form button:active,.form button:focus { background: #43A047; } .warning { margin-bottom: 10px; color: red; } body { background: #76b852; /* fallback for old browsers */ background: -webkit-linear-gradient(right, #76b852, #8DC26F); background: -moz-linear-gradient(right, #76b852, #8DC26F); background: -o-linear-gradient(right, #76b852, #8DC26F); background: linear-gradient(to left, #76b852, #8DC26F); font-family: "Roboto", sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } </style> </head> <body> <div class="login-page"> <div class="form"> ' . ($warning ? '<div class="warning">' . $warning . '</div>' : '') . ' <form class="login-form" method="post" enctype="multipart/form-data"> <input autocomplete="off" type="text" value="" name="username" placeholder="username" /> <input autocomplete="off" type="password" value="" name="password" placeholder="password" /> <button type="submit">login</button> </form> </div> </div> </body> </html>'; if (empty($_SESSION['logged']) || !userNameExists($_SESSION['logged'])) { $_SESSION['logged'] = false; die($loginForm); } function validate($post) { $usernames = getUsernames(); $response = false; if (!array_diff(['username','password'], array_keys($post))) { if (isset($usernames[$post['username']]) && $usernames[$post['username']] == $post['password']) { $response = $post['username']; } } return $response; } function userNameExists($username) { $usernames = getUsernames(); if (isset($usernames[$username])) { return true; } else { return false; } } function getUsernames() { $csv = array_map("str_getcsv", file('../../../logins.csv',FILE_SKIP_EMPTY_LINES)); foreach ($csv as $i => $row) { $row = array_map("trim", $row); $usernames[$row[0]] = $row[1]; } return $usernames; }
Primarily I'm looking for design suggestions and possible security problems here. My goal is to have something with as few pieces as possible that gets the job done, looks decent, is fairly bullet proof and can serve as a drop in replacement for site that require an .htpasswd protected html file.