Hallo!

Kunnen jullie mij helpen mijn login systeem zo veilig mogelijk te maken? Hieronder staan mijn codes voor het login script. Alvast bedankt!

index.php

<?php
session_start(); // Start de session \\

// IMPORTEER ALLE BESTANDEN \\
REQUIRE_ONCE 'paneel/include/config.php';
REQUIRE_ONCE 'paneel/include/functions.php';
REQUIRE_ONCE 'paneel/include/login_script.php';

// ACTIVEER DE FUNCTIE 'LOGGED_IN' \\
if(logged_in()) {
	header('Location: /dashboard'); // Hier wordt je doorgelinkt naar '/dashboard' als je bent ingelogd \\
	die(); // Als je bent ingelogd, volgt de volgende code niet \\
}
// ONDERHOUD INSTELLINGEN \\
$currentLocation = "index"; // PAS DE LOCATIE NIET AAN \\
include 'lib/classes/site.status.php';
?>
<!DOCTYPE html>
<html>
	<head>
		<script>
			<?php echo $disable_form;?>
		</script>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<meta name="viewport" content="width=1,initial-scale=1,user-scalable=1" />
		<title>
			Inloggen - <?php echo $_CONFIG['bedrijf']; ?>
		</title>
		<link rel="shortcut icon" type="image/gif" href="<?php echo $_CONFIG['bedrijf_logo']; ?>" />
		<link rel="stylesheet" type="text/css" href="paneel/style/css/index.css" />
		<link href="http://fonts.googleapis.com/css?family=Lato:100italic,100,300italic,300,400italic,400,700italic,700,900italic,900" rel="stylesheet" type="text/css">
		<link rel="stylesheet" type="text/css" href="paneel/style/bootstrap/css/bootstrap.min.css" />
	</head>
	<body>
		<section class="container">
			<section class="login-form">
			
			<section>
				<p style="margin-bottom: -7px; margin-top: -15px; color: black; font-size: 18pt; font-weight: bold;"><?php echo $_CONFIG['bedrijf']; ?></p>
			</section>
			<div class="panel panel-default">
				<div class="panel-body">
					<form method="post" id="disable" action="" role="login">
						<div class="form-group">
							<p style="text-align: center;">Inloggen, geen account? <a class="disable" href='/registreer'>Maak er één!</a></p>
							<p style="text-align: center; color: red;"><?php echo $error; ?></p>
							<label>Gebruikersnaam</label>
							<input autofocus title="Maximaal 50 tekens." type="text" name="gebruikersnaam" maxlength="50" required class="form-control" />
						</div>
						
						<div class="form-group">
							<label>Wachtwoord</label>
							<input title="Maximaal 100 tekens." type="password" name="wachtwoord" maxlength="100" required class="form-control" />
						</div>
						
						<input type="checkbox" name="onthoud" value="1" /> Onthoud mijn gegevens.
						<button type="submit" name="inloggen" class="btn btn-primary btn-block">Inloggen</button>
					</form>
				</div>
				<div class="panel-footer">
					<a href="#">Wachtwoord vergeten?</a>
				</div>
			</div>
			<section>
				<a href="<?php $_SERVER["REQUEST_URI"]; ?>">Copyright &copy; <?php echo date("Y"); echo ' <b>'; echo $_CONFIG['bedrijf']; echo '</b>'; ?></a>
			</section>
			
			</section>
		</section>
		<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
		<script src="paneel/style/bootstrap/js/bootstrap.min.js"></script>
	</body>


config.php

<?php
error_reporting(0);
// DE DATABASE INFORMATIE \\
$setting = parse_ini_file('datafile.ini');
$con = new mysqli($setting['db_host'], $setting['db_user'], $setting['db_pass'], $setting['db_name']);

// CONTROLEER DE VERBINDING \\
if ($con->connect_error) {
    die('<title>Niet gelukt om te verbinden met MySQL</title>Verbinings fout (' . $con->connect_errno . ') ' . $con->connect_error); // DE ERROR ALS ER EEN FOUT IN DE VERBINDING IS \\
}

// SERVER INSTELLINGEN \\
$_SERVER['admin'] = $setting['admin'];
$_SERVER['admin_ip'] = $setting['admin_ip'];

// CONFIG INSTELLINGEN \\
$result = $con->query("SELECT * FROM `instellingen`")->fetch_array(); // SELECTEER ALLES VAN INSTELLINGEN \\
$_CONFIG['bedrijf'] = ucfirst($result['bedrijf']); // SELECTEER DE BEDRIJFSNAAM \\
$_CONFIG['bedrijf_logo'] = $result['bedrijf_logo']; // SELECTEER HET BEDRIJFS LOGO \\
?>


login_script.php

<?php
if(isset($_POST['inloggen'])){
	// DEFINITEER $GEBRUIKERSNAAM EN $WACHTWOORD \\
	$gebruikersnaam   = $_POST['gebruikersnaam'];
	$wachtwoord       = $_POST['wachtwoord'];
	
	// BESCHERM DE GEGEVENS \\
	$gebruikersnaam   = $con->real_escape_string($gebruikersnaam);
	$wachtwoord       = md5($wachtwoord);
	
	// LOGIN SCRIPT \\
	$result = $con->query("SELECT * FROM `leden` WHERE `gebruikersnaam`='$gebruikersnaam'")->fetch_array(); // SELECTEER ALLE DATA VAN DE GEBRUIKERSNAAM \\
	if (( $gebruikersnaam ) == ( $result['gebruikersnaam'] )){
		if (( $wachtwoord ) == ( $result['wachtwoord'] )){
			$id = $con->query("SELECT `id` FROM `leden` WHERE `gebruikersnaam`='$gebruikersnaam'")->fetch_array();
			$_SESSION['id'] = $id['id'];
			header('Location: /dashboard');
		}
		else{
			$error = "Er is een fout wachtwoord ingevoerd voor de gebruiker '$gebruikersnaam'.";
			header('Refresh: 2; Url=/');
		}
	}
	else{
		$error = "De gebruiker '$gebruikersnaam' kan niet worden gevonden.";
		header('Refresh: 2; Url=/');
	}
}
?>


functions.php

<?php
function logged_in(){
	if(!empty($_SESSION['id'])){
		return true;
	}
	else{
		return false;
	}
}

function logout(){
	session_unset();
	header('Location: /');
}
?>


site_status.php

<?php	
$result = $con->query("SELECT * FROM `instellingen`")->fetch_array();

$maintenanceMode      = $result['status'];
$maintananceGlobal    = $result['status2'];
$maintenanceLocations = $result['status3'];
$maintenanceMessage   = "<!DOCTYPE html>
<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=utf-8' />
<title>Onderhoud Modus</title>
<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js'></script>

<script type='text/javascript'>
$(document).ready(function() {	

		var id = '#dialog';
	
		//Get the screen height and width
		var maskHeight = $(document).height();
		var maskWidth = $(window).width();
	
		//Set heigth and width to mask to fill up the whole screen
		$('#mask').css({'width':maskWidth,'height':maskHeight});
		
		//transition effect		
		$('#mask').fadeIn(1000);	
		$('#mask').fadeTo('slow',0.8);	

	
		//transition effect
		$(id).fadeIn(2000); 		
		
		var fields = document.getElementById('disable').getElementsByTagName('*');
for(var i = 0; i < fields.length; i++)
{
    fields[i].disabled = true;
}
});
</script>

<style type='text/css'>
body {
font-family:verdana;
font-size:15px;
}
#overlay {
  position: fixed;
  height: 100%;
  width: 100%;
  z-index: 1000000;
  background: url('link/to/semitransparent.png');
}

a {color:#333; text-decoration:none}
a:hover {color:#ccc; text-decoration:none}

#mask {
  position:absolute;
  left:0;
  top:0;
  z-index:9000;
  background-color:#000;
  display:none;
}  
#boxes .window {
  position:absolute;
  left:0;
  top:0;
  width:340px;
  height:200px;
  display:none;
  z-index:9999;
  padding:20px;
}
#boxes #dialog {
    width: 350px;
    height: 200px;
  background-color: white;
    position: absolute !important;
    top:0 !important;
    bottom: 0 !important;
    left: 0 !important;
    right: 0 !important;
    margin: auto !important;
}
</style>
</head><body>

<div id='boxes'>
<div style='top: 199.5px; left: 551.5px; display: none;' id='dialog' class='window'>
<b style='font-size: 15pt;'><center>Onderhoud</center></b>Momenteel is het paneel in onderhoud, hierom is gebruik maken van het paneel niet mogelijk. Deze onderhoud is waarschijnlijk snel voorbij. <br><br><b>- Het Beheer</b>
</div>
<div style='width: 1478px; height: 602px; display: none; opacity: 0.8;' id='mask'></div>
</div>
</body>
</html>
"; 

if (($maintenanceMode) == "onderhoud")
{
	if (($maintananceGlobal) == "niet_overal")
	{
		if (($currentLocation) == ($maintenanceLocations))
		{
			echo $maintenanceMessage;
		}
	}
	else
	{
		echo $maintenanceMessage;
	}
}
?>



Bedankt voor jullie reacties voor het veilig te maken! PS: ik gebruik md5 omdat ik het fijn vind om te gebruiken en password_hash() werkt op een of andere manier niet.
Ziet er aardig veilig uit, maar waarom zoek je niet uit waarom password_hash() niet werkt? MD5 is tegenwoordig zeer kwetsbaar.

Verder zou ik bij een foute inlogpoging niet vermeldde of de gebruikersnaam óf het wachtwoord fout is. Maar toon liever dat één of beiden fout is. Je wilt het account-kapers (hackers) niet makkelijk maken om een account over te nemen.

Verder zou een brute-force detectie een handige maatregel zijn, zodat het inloggen op je account een poosje geblokkeerd is na xx aantal foutieve inlogpogingen.

En eventueel kan je de gebruiker de keuze geven voor Two-Factor Authentication, zodat hij bijv. met SMS of Google Authenticator op zijn tablet/smartphone zijn inlogactie moet bevestigen.

- Sla geen onderhoudsstatus op in de database. Stel je voor dat je MySQL-server problemen heeft. Dan kan je jouw site niet eventjes netjes uitschakelen, tot het probleem is verholpen.

- Ik zie een paar variabelen die niet ge-echo'd worden.

En een heel belangrijke:
Zet je datafile.ini BUITEN je webroot!!!!!!

- Ariën - op 04/12/2016 17:27:35

Ziet er aardig veilig uit, maar waarom zoek je niet uit waarom password_hash() niet werkt? MD5 is tegenwoordig zeer kwetsbaar.

Verder zou ik bij een foute inlogpoging niet vermeldde of de gebruikersnaam óf het wachtwoord fout is. Maar toon liever dat één of beiden fout is. Je wilt het account-kapers (hackers) niet makkelijk maken om een account over te nemen.

Verder zou een brute-force detectie een handige maatregel zijn, zodat het inloggen op je account een poosje geblokkeerd is na xx aantal foutieve inlogpogingen.

En eventueel kan je de gebruiker de keuze geven voor Two-Factor Authentication, zodat hij bijv. met SMS of Google Authenticator op zijn tablet/smartphone zijn inlogactie moet bevestigen.

- Sla geen onderhoudsstatus op in de database. Stel je voor dat je MySQL-server problemen heeft. Dan kan je jouw site niet eventjes netjes uitschakelen, tot het probleem is verholpen.

- Ik zie een paar variabelen die niet ge-echo'd worden.

En een heel belangrijke:
Zet je datafile.ini BUITEN je webroot!!!!!!



Waar zet ik hem buiten mijn webroot? een ander domein of??
- Sla geen onderhoudsstatus op in de database. Stel je voor dat je MySQL-server problemen heeft. Dan kan je jouw site niet eventjes netjes uitschakelen, tot het probleem is verholpen.

Dankzij jouw script kan ik het nu via .ini laten lopen :D Zodat er geen MySQL-server nodig is. Heb je toevallig nog een link liggen naar een goede manier voor brute-force tegen te gaan? Zodat ik er meer uit kan leren en toepassen :D
Je slaat dat bestand op in een hoger op in een map. Dus buiten /public_html of waar je webserver je site maar ook opzoekt. Niemand mag het dus kunnen bekijken via de browser.
- Ariën - op 04/12/2016 18:11:37

Je slaat dat bestand op in een hoger op in een map. Dus buiten /public_html of waar je webserver je site maar ook opzoekt. Niemand mag het dus kunnen bekijken via de browser.


Ik heb hem op localhost voor nu, maar dus op webserver buiten /private_html en hoe moet ik hem dan pakken? met ../?
Is /private_html niet de beste plek? Als die map hoger staat dan /public_html dan is hij prive.
- Ariën - op 04/12/2016 18:15:30

Is /private_html niet de beste plek?

Hoe bedoel je?


Private = prive = niet openbaar ;-)

Met ../private_html/datafile.ini kan je hem dan openen.
- Ariën - op 04/12/2016 18:19:10

Private = prive = niet openbaar ;-)

Met ../private_html/datafile.ini kan je hem dan openen.


Even kijken, maar hoe include ik dat dan bij alles? Want bij de config.php include ik hem maar in een volgende map include die m niet meer

[size=xsmall]Toevoeging op 04/12/2016 18:23:24:[/size]

En bij /private_html kan j hem nog steeds lezen
Sla die locatie op in variabele. Dan hoef je het pad naar datefile.ini niet steeds op vele plekken in je code te wijzigen.

En in welke map leest je webserver? Normaal is dat /htdocs, /public_html of /www. Die /private_html hoort daar NIET in te staan.
- Ariën - op 04/12/2016 18:27:28

Sla die locatie op in variabele. Dan hoef je het pad naar datefile.ini niet steeds op vele plekken in je code te wijzigen.

En in welke map leest je webserver? Normaal is dat /htdocs, /public_html of /www. Die /private_html hoort daar NIET in te staan.

private_html staat op webserver door SSL, maar hoe bedoel je precies? [qoute]Sla die locatie op in variabele. Dan hoef je het pad naar datefile.ini niet steeds op vele plekken in je code te wijzigen.[/quote]

Reageren