Hallo,

Ik wou jullie even mijn PHP script laten controleren (als jullie tijd hebben). Ik heb de laatste tijd veel doorgenomen bij w3schools.com en andere php informatie websites. Zouden jullie even willen kijken of mijn script veilig is? Kwa SQL-injections etc. (bruteforce protection zit erop :-), en al uitgetest)


<?php
if (date("d-m-Y") <= "26-03-".date("Y"))
{
  $_SERVER['unix'] = strtotime("UTC");
}

if (date("d-m-Y") >= "26-03-".date("Y"))
{
    $_SERVER['unix'] = strtotime("UTC +1 hour");
}

function loggedIn()
{
  if (!empty($_SESSION['id']) && is_numeric($_SESSION['id']))
  {
    return true;
  }
  else
  {
    return false;
  }
}

function getIpadress()
{
  if (!empty($_SERVER['HTTP_CLIENT_IP']))
  {
    $_SERVER['ip'] = $_SERVER['HTTP_CLIENT_IP'];
  }
  elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
  {
    $_SERVER['ip'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
  }
  else
  {
    $_SERVER['ip'] = $_SERVER['REMOTE_ADDR'];
  }
}

function checkWrongAttempts() {
  include($_SERVER['DOCUMENT_ROOT'].'/paneel/includes/init.php');

  getIpadress();
  $ip = sha1($_SERVER['ip']);
  $datum = $_SERVER['unix'];

  $searchForWrongAttempts = $link->query("SELECT * FROM `paneel_foutepogingen` WHERE `ip`='$ip' ORDER BY `datum_foutepoging` DESC");
  if (!$searchForWrongAttempts)
  {
    echo '0+Er is een fout opgetreden, kom later terug';
    exit();
  }
  else
  {
    if ($searchForWrongAttempts->num_rows > 3)
    {
      $wrongAttempts = $searchForWrongAttempts->fetch_assoc();
      if ($_SERVER['unix'] <= strtotime('+15 minutes', $wrongAttempts['datum_foutepoging']))
      {
        $searchForLoginLog = $link->query("SELECT * FROM `paneel_logs` WHERE `ip`='$ip' AND `bericht`='Te veel foute pogingen achter elkaar om in te loggen/registreren/wachtwoord veranderen' ORDER BY `datum_log` DESC");
        if (!$searchForLoginLog)
        {
          echo '0+Er is een fout opgetreden, kom later terug';
          exit();
        }
        else
        {
          $loginLog = $searchForLoginLog->fetch_assoc();

          if ($_SERVER['unix'] >= strtotime('+15 minutes', $loginLog['datum_log']) || $searchForLoginLog->num_rows === 0)
          {
            $insertLog = $link->query("INSERT INTO `paneel_logs` (`ip`, `bericht`, `plaats`, `datum_log`) VALUES ('$ip', 'Te veel foute pogingen achter elkaar om in te loggen/registreren/wachtwoord veranderen', 'index', '$datum')");
            if (!$insertLog)
            {
              echo '0+Er is een fout opgetreden, kom later terug';
              exit();
            }
            else
            {
              echo '0+Er is een fout opgetreden, kom later terug';
              exit();
            }
          }
          else
          {
            echo '0+Er is een fout opgetreden, kom later terug';
            exit();
          }
        }
      }
      else
      {
        $deleteWrongAttempts = $link->query("DELETE FROM `paneel_foutepogingen` WHERE `ip`='$ip'");
        if (!$deleteWrongAttempts)
        {
          echo '0+Er is een fout opgetreden, kom later terug';
          exit();
        }
      }
    }
  }
}

function login($gebruikersnaam, $wachtwoord)
{
  include($_SERVER['DOCUMENT_ROOT'].'/paneel/includes/init.php');

  checkWrongAttempts();
  getIpadress();
  $ip = sha1($_SERVER['ip']);
  $datum = $_SERVER['unix'];
  $gebruikersnaam = $link->real_escape_string($gebruikersnaam);

  $searchForUser = $link->query("SELECT * FROM `leden` WHERE `gebruikersnaam`='$gebruikersnaam'");
  if (!$searchForUser)
  {
    $insertWrongLogin = $link->query("INSERT INTO `paneel_foutepogingen` (`ip`, `datum_foutepoging`) VALUES ('$ip', '$datum')");
    if (!$insertWrongLogin)
    {
      echo '0+Probeer het later opnieuw om in te loggen';
    }
    else
    {
      echo '0+Probeer het later opnieuw om in te loggen';
    }
  }
  else
  {
    if ($searchForUser->num_rows === 1)
    {
      $userDetails = $searchForUser->fetch_assoc();

      if (password_verify($wachtwoord, $userDetails['wachtwoord']))
      {
        $updateUserAccount = $link->query("UPDATE `leden` SET `laatst_online`='$datum' WHERE `gebruikersnaam`='$gebruikersnaam'");
        if (!$updateUserAccount)
        {
          echo '0+Probeer het later opnieuw om in te loggen';
        }
        else
        {
          $_SESSION['id'] = $userDetails['id'];
          echo '1+Je bent succesvol ingelogd';
        }
      }
      else
      {
        $insertWrongLogin = $link->query("INSERT INTO `paneel_foutepogingen` (`ip`, `datum_foutepoging`) VALUES ('$ip', '$datum')");
        if (!$insertWrongLogin)
        {
          echo '0+Probeer het later opnieuw om in te loggen';
        }
        else
        {
          echo '0+Er zijn foute log in gegevens ingevuld';
        }
      }
    }
    else
    {
      $insertWrongLogin = $link->query("INSERT INTO `paneel_foutepogingen` (`ip`, `datum_foutepoging`) VALUES ('$ip', '$datum')");
      if (!$insertWrongLogin)
      {
        echo '0+Probeer het later opnieuw om in te loggen';
      }
      else
      {
        echo '0+Deze gebruiker kan niet worden gevonden';
      }
    }
  }
}

function register($gebruikersnaam, $wachtwoord, $wachtwoordher, $emailadres)
{
  include($_SERVER['DOCUMENT_ROOT'].'/paneel/includes/init.php');

  checkWrongAttempts();
  getIpadress();
  $ip = sha1($_SERVER['ip']);
  $datum = $_SERVER['unix'];
  $gebruikersnaam = $link->real_escape_string($gebruikersnaam);
  $wachtwoord = $link->real_escape_string($wachtwoord);
  $emailadres = $link->real_escape_string($emailadres);

  $searchForUser = $link->query("SELECT * FROM `leden` WHERE `gebruikersnaam`='$gebruikersnaam'");
  if (!$searchForUser)
  {
    $insertWrongLogin = $link->query("INSERT INTO `paneel_foutepogingen` (`ip`, `datum_foutepoging`) VALUES ('$ip', '$datum')");
    if (!$insertWrongLogin)
    {
      echo '0+Probeer het later opnieuw om te registreren';
    }
    else
    {
      echo '0+Probeer het later opnieuw om te registreren';
    }
  }
  else
  {
    $userDetails = $searchForUser->fetch_assoc();

    if (strlen($gebruikersnaam) >= 2 && strlen($gebruikersnaam) <= 15)
    {
      if ($searchForUser->num_rows === 0)
      {
        if ($wachtwoord === $wachtwoordher)
        {
          if (preg_match('/\A(?=[\x20-\x7E]*?[A-Z])(?=[\x20-\x7E]*?[a-z])(?=[\x20-\x7E]*?[0-9])[\x20-\x7E]{6,}\z/', $wachtwoord) && strlen($wachtwoord) > 8)
          {
            if (filter_var($emailadres, FILTER_VALIDATE_EMAIL))
            {
              $checkPostedEmail = $link->query("SELECT * FROM `leden` WHERE `emailadres`='$emailadres'");
              if (!$checkPostedEmail)
              {
                echo '0+Probeer het later opnieuw om te registreren';
              }
              else
              {
                $wachtwoord = password_hash($wachtwoord, PASSWORD_DEFAULT);

                $createUserAccount = $link->query("INSERT INTO `leden` (`gebruikersnaam`, `wachtwoord`, `emailadres`, `ip`, `registratie_datum`) VALUES ('$gebruikersnaam', '$wachtwoord', '$emailadres', '$ip', '$datum')");
                if (!$createUserAccount)
                {
                  echo '0+Probeer het later opnieuw om te registreren';
                }
                else
                {
                  echo '1+Je account is aangemaakt, je kan nu inloggen';
                }
              }
            }
            else
            {
              $insertWrongLogin = $link->query("INSERT INTO `paneel_foutepogingen` (`ip`, `datum_foutepoging`) VALUES ('$ip', '$datum')");
              if (!$insertWrongLogin)
              {
                echo '0+Probeer het later om te registreren';
              }
              else
              {
                echo '0+Dit emailadres is niet geldig';
              }
            }
          }
          else
          {
            $insertWrongLogin = $link->query("INSERT INTO `paneel_foutepogingen` (`ip`, `datum_foutepoging`) VALUES ('$ip', '$datum')");
            if (!$insertWrongLogin)
            {
              echo '0+Probeer het later opnieuw om te registreren';
            }
            else
            {
              echo '0+Je wachtwoord moet bestaan uit kleine en grote letters, nummers, symbolen en grote zijn dan 8 tekens';
            }
          }
        }
        else
        {
          $insertWrongLogin = $link->query("INSERT INTO `paneel_foutepogingen` (`ip`, `datum_foutepoging`) VALUES ('$ip', '$datum')");
          if (!$insertWrongLogin)
          {
            echo '0+Probeer het later opnieuw om te registreren';
          }
          else
          {
            echo '0+De wachtwoorden komen niet overeen';
          }
        }
      }
      else
      {
        $insertWrongLogin = $link->query("INSERT INTO `paneel_foutepogingen` (`ip`, `datum_foutepoging`) VALUES ('$ip', '$datum')");
        if (!$insertWrongLogin)
        {
          echo '0+Probeer het later opnieuw om te registreren';
        }
        else
        {
          echo '0+Deze gebruiker helaas bestaat al';
        }
      }
    }
    else
    {
      $insertWrongLogin = $link->query("INSERT INTO `paneel_foutepogingen` (`ip`, `datum_foutepoging`) VALUES ('$ip', '$datum')");
      if (!$insertWrongLogin)
      {
        echo '0+Probeer het later opnieuw om te registreren';
      }
      else
      {
        echo '0+De gebruikersnaam moet tussen de 2 en 15 tekens bestaan';
      }
    }
  }
}
?>

Ik hoor graag verbeter punten! :D

[size=xsmall]Toevoeging op 12/03/2017 18:41:16:[/size]

TOEVOEGING:
IP adres wordt gehasht met SHA1 om de volgende reden: Voor het spel waar ik dit voor maak, controleren ze op of ik ips, keyloggers etc. achterhaal. Dus van hun moest ik IP doen met SHA1 of een andere hash.




Ik snapte niet wat ik moest isseten, nu wel :D


function loggedIn()
{
  if (isset($_SESSION['id']))
  {
    return true;
  }
  else
  {
    return false;
  }
}

function createAccount($gebruikersnaam, $wachtwoord, $emailadres, $admin, $ip, $datum)
{
  global $settings;
  global $link;

  $createAccount = $link->query("INSERT INTO `leden` (`gebruikersnaam`, `wachtwoord`, `emailadres`, `ip`, `datum`) VALUES ('".$link->real_escape_string($gebruikersnaam)."', '".$link->real_escape_string(password_hash($wachtwoord, PASSWORD_DEFAULT))."', '".$link->real_escape_string($emailadres)."', '$ip', '".$link->real_escape_string($datum)."')");

  if (!$createAccount)
  {
    return false;
  }
  else
  {
    if ($admin === 1)
    {
      $setUserToAdmin = $link->query("INSERT INTO `".$settings['prefix']."adminstratoren` (`gebruikersnaam`, `ip`) VALUES ('".$link->real_escape_string($gebruikersnaam)."', '$ip')");

      if (!$setUserToAdmin)
      {
        return false;
      }
      else
      {
        return true;
      }
    }
    else
    {
      return true;
    }
  }
}

function createLog($bericht, $plaats, $ip, $datum)
{
  global $settings;
  global $link;

  $createLog = $link->query("INSERT INTO `".$settings['prefix']."logs` (`bericht`, `plaats`, `ip`, `datum`) VALUES ('".$link->real_escape_string($bericht)."', '".$link->real_escape_string($plaats)."', '$ip', '".$link->real_escape_string($datum)."')");

  if (!$createLog)
  {
    return false;
  }
  else
  {
    return true;
  }
}

function checkWrongAttempts($ip, $datum)
{
  $searchForWrongAttempts = $link->query("FF SNEL");

  if (!$searchForWrongAttempts)
  {
    return false;
  }
  else
  {
    return true;
  }
}

function login(gebruikersnaam, $wachtwoord)
{
  global $settings;
  global $link;
  global $ip;
  global $datum;

  $searchForUser = $link->query("SELECT * FROM `leden` WHERE `gebruikersnaam`='".$link->real_escape_string($gebruikersnaam)."'");

  if($searchForUser)
  {
    $userDetails = $searchForUser->fetch_assoc();

    if (
        $searchForUser->num_rows === 1
        && password_verify($wachtwoord, $userDetails['wachtwoord'])
      )
    {
      if (createLog($gebruikersnaam.' is met succes ingelogd', 'index', sha1($ip), $datum) === true)
      {
        $_SESSION['id'] = $userDetails['id'];
        return true;
      }
      else
      {
        return false;
      }
    }
  }
  else
  {
    return false;
  }
}

Ik heb nu dit, is dit dan al beter?
Ikzelf ben net als Ward geen fan van de globals in je script. Ikzelf roep ze graag netjes in de parameter van de functie aan.

Ook heb ik in mijn eigen CMS de foutafhandeling op de query() functie ingebouwd in een extend van de MySQli-class. Het in één van de enkele oplossingen die kan doen om je code zo compact mogelijk te houden.
Dus met de parameters, zoiets raden jullie dus aan:


function createAccount($gebruikersnaam, $wachtwoord, $emailadres, $admin, $ip)
{
  $settings = parse_ini_file($_SERVER['DOCUMENT_ROOT'].'/../datafile.ini');
  include($_SERVER['DOCUMENT_ROOT'].$settings['path'].'paneel/includes/init.php');
  $datum = strtotime('Europe/Amsterdam');

  $createAccount = $link->query("INSERT INTO `leden` (`gebruikersnaam`, `wachtwoord`, `emailadres`, `ip`, `datum`) VALUES ('".$link->real_escape_string($gebruikersnaam)."', '".$link->real_escape_string(password_hash($wachtwoord, PASSWORD_DEFAULT))."', '".$link->real_escape_string($emailadres)."', '$ip', '".$link->real_escape_string($datum)."')");

  if (!$createAccount)
  {
    return false;
  }
  else
  {
    if ($admin === 1)
    {
      $setUserToAdmin = $link->query("INSERT INTO `".$settings['prefix']."adminstratoren` (`gebruikersnaam`, `ip`) VALUES ('".$link->real_escape_string($gebruikersnaam)."', '$ip')");

      if (!$setUserToAdmin)
      {
        return false;
      }
      else
      {
        return true;
      }
    }
    else
    {
      return true;
    }
  }
}

function createLog($bericht, $plaats, $ip)
{
  $settings = parse_ini_file($_SERVER['DOCUMENT_ROOT'].'/../datafile.ini');
  include($_SERVER['DOCUMENT_ROOT'].$settings['path'].'paneel/includes/init.php');
  $datum = strtotime('Europe/Amsterdam');

  $createLog = $link->query("INSERT INTO `".$settings['prefix']."logs` (`bericht`, `plaats`, `ip`, `datum`) VALUES ('".$link->real_escape_string($bericht)."', '".$link->real_escape_string($plaats)."', '$ip', '".$link->real_escape_string($datum)."')");

  if (!$createLog)
  {
    return false;
  }
  else
  {
    return true;
  }
}

function checkWrongAttempts($ip, $plaats)
{
  $settings = parse_ini_file($_SERVER['DOCUMENT_ROOT'].'/../datafile.ini');
  include($_SERVER['DOCUMENT_ROOT'].$settings['path'].'paneel/includes/init.php');
  $datum = strtotime('Europe/Amsterdam');

  $searchForWrongAttempts = $link->query("SELECT * FROM `".$settings['path']."foutepogingen` WHERE `ip`='$ip' AND `plaats`='".$link->real_escape_string($plaats)."' AND `datum` BETWEEN '$datum' AND '".strtotime('+15 minutes', $datum)."'");

  if (
      !$searchForWrongAttempts
      || $searchForWrongAttempts->num_rows === 0
    )
  {
    return false;
  }
  else
  {
    if ($searchForWrongAttempts->num_rows > 3)
    {
      return true;
    }
    else
    {
      return false;
    }
  }
}

function insertWrongAttempt($ip, $plaats)
{
  $settings = parse_ini_file($_SERVER['DOCUMENT_ROOT'].'/../datafile.ini');
  include($_SERVER['DOCUMENT_ROOT'].$settings['path'].'paneel/includes/init.php');
  $datum = strtotime('Europe/Amsterdam');
}

function login($gebruikersnaam, $wachtwoord)
{
  $settings = parse_ini_file($_SERVER['DOCUMENT_ROOT'].'/../datafile.ini');
  include($_SERVER['DOCUMENT_ROOT'].$settings['path'].'paneel/includes/init.php');
  $datum = strtotime('Europe/Amsterdam');
  global $ip;

  if (checkWrongAttempts(sha1($ip), $datum, 'index') === false)
  {
    $searchForUser = $link->query("SELECT * FROM `leden` WHERE `gebruikersnaam`='".$link->real_escape_string($gebruikersnaam)."'");

    if($searchForUser)
    {
      $userDetails = $searchForUser->fetch_assoc();

      if (
          $searchForUser->num_rows === 1
          && password_verify($wachtwoord, $userDetails['wachtwoord'])
        )
      {
        if (createLog($gebruikersnaam.' is met succes ingelogd', 'index', sha1($ip)) === true)
        {
          $_SESSION['id'] = $userDetails['id'];
          return true;
        }
        else
        {
          return false;
        }
      }
    }
    else
    {
      return false;
    }
  }
  else
  {
    return false;
  }
}
Wat is dit: strtotime('Europe/Amsterdam')? Wat is er mis met gewoon de juiste timezone in te stellen en time() te gebruiken? Ik kan me ook niet voostellen dat dat tot een correct resultaat leidt.

En nog steeds combineer je je ifs niet, de nesting is gewoon te veel.
Bedoel je met de juiste timezone UTC?
Want als ik dat doe en ik doe:
date_default_timezone_set('Europe/Amsterdam');
werkt het dan nog oké?

[size=xsmall]Toevoeging op 16/03/2017 16:48:23:[/size]

"En nog steeds combineer je je ifs niet, de nesting is gewoon te veel." waar zou ik dan me ifs kunnen combineren?
date_default_timezone_set() is de enige functie om de juiste tijdzone in te stellen. Maar doe dit bij voorkeur hogerop in php.ini. Tenzij je een afwijking wilt hebben op website-niveau. Of je moet op een buitenlands webhosting zitten. ;-)
Gebruik inderdaad date_default_timezone_set en gooi geen timezones in strtotime. Helemaal als strtotime niet van toepassing is zoals hoe jij het gebruikt. Gewoon time() gebruiken.

Je kunt je if condities omdraaien, dan hoef je ook niet meer te nesten. Houd in het achterhoofd dat return de functie meteen stopt, dus dan heb je ook geen else condities meer nodig.

Bijvoorbeeld, in plaats van dit:

<?php
if (
          $searchForUser->num_rows === 1
          && password_verify($wachtwoord, $userDetails['wachtwoord'])
        )
?>


Kun je dit doen:

<?php
if (
          $searchForUser->num_rows !== 1
          || !password_verify($wachtwoord, $userDetails['wachtwoord'])
        ) {
  return false;
}
// volgende conditie hier
?>
Oké bedankt! Kan ik php.ini op mijn webhost gewoon aanpassen als ik die opzoek bij filezilla bv.?

[size=xsmall]Toevoeging op 16/03/2017 17:00:07:[/size]

Ben? Ik heb van dit:


<?php
session_start();
date_default_timezone_set('Europe/Amsterdam');

$settings = parse_ini_file($_SERVER['DOCUMENT_ROOT'].'/../datafile.ini');

include($_SERVER['DOCUMENT_ROOT'].$settings['path'].'paneel/includes/functions.php');

if (isset($_POST['gebruikersnaam'], $_POST['wachtwoord']) && loggedIn() === false)
{
  if (login($_POST['gebruikersnaam'], $_POST['wachtwoord']) === true)
  {
    echo '1+Je bent met succes ingelogd';
  }
  else
  {
    echo '0+De ingevulde gegevens zijn niet goed';
  }
}
?>

dit gemaakt:

<?php
session_start();
date_default_timezone_set('Europe/Amsterdam');

$settings = parse_ini_file($_SERVER['DOCUMENT_ROOT'].'/../datafile.ini');

include($_SERVER['DOCUMENT_ROOT'].$settings['path'].'paneel/includes/functions.php');

if (
    isset($_POST['gebruikersnaam'], $_POST['wachtwoord'])
    && loggedIn() === false
    && login($_POST['gebruikersnaam'], $_POST['wachtwoord']) === false
  )
{
  echo '0+De ingevulde gegevens zijn niet goed';
}
else
{
  echo '1+Je bent met succes ingelogd';
}
?>

Dit is toch wat je bedoeld?
- Rob - op 16/03/2017 16:56:57

Oké bedankt! Kan ik php.ini op mijn webhost gewoon aanpassen als ik die opzoek bij filezilla bv.?

Ligt aan de installatie op de webserver.
Kijk in [php]phpinfo[/php] naar "Scan this dir for additional .ini files" of gebruik de php-flags in .htaccess.
Nee, dat is niet wat ik bedoel, je moet lezen wat ik als voorbeeld geef. Nu combineer je verschillende dingen die om verschillende redenen tot een fout leiden, dus technisch gezien ook met een ander bericht.
Bekijk het voorbeeld nog eens.

Reageren