1Danke
ERLEDIGT
NEIN
NEIN
ANTWORTEN
3
3
ZUGRIFFE
1431
1431
EMPFEHLEN
-
Hi, ich bin was Sicherheit angeht ein absoluter Neuling.
Habe die letzten Tage das erste mal versucht einen Login "absolut" Sicher zu Programmieren, da ich einen Login benötige der das maximum an Sicherheit bietet.
So jetzt ein Post der eher für die härteren ist... Aber wenn dann richtig******
Vorerst zur Struktur. Ich hoffe meine Projectstruktur ist leicht zuverstehen:
../aliases enthält die defines
classes enthält die Klassen
processes enthält die processe und ruft die KlassenFunktionen auf
public_html Ordner der vom Webserver als "root" gesehen wird und im www erreichbar istprojectnamecss enthält die css datein
view enthält die formulare bzw. das was zu sehen ist
index.php ruft klassen auf und bindet die benötigten datein ein
Alle Ordner bis auf die CSS Ordner enthalten IMMER 3 Datein.
1. .htaccess (Order deny,allow Deny from all)
2. index.php und index.html
beide enthalten:
Das war mein Versuch alles vor einem "oberflächlichem" Zugriff zu schützen. Somit ist kein Ordner aufrufbar und keine Datei die in dem Ordner enthalten ist.HTML-Code:<html> <head> <title>ACCESS DENIED</title> <meta HTTP-EQUIV="REFRESH" content="0; url=http://www.xy.de/" /> </head> <body></body> </html>
Darüber hinaus ist jede .php Datei nocheinmal am Anfang mit einem code geschützt, der es nicht erlaubt die .php alleine aufzurufen, sondern nur ein include über die index.php zulässt.
Das Project enthält bis jetzt:
- Die Möglichkeit sich zu registrieren
- Die Möglichkeit sich einzuloggen
- Die Möglichkeit sich auszuloggen
Das ist wie folgt realisiert:
der Ordner VIEW welcher sich an der Oben genannten Stelle in /public_html/projectname/view befindet, enthält die Formulare.
REGISTER
PHP-Code:<?php
defined( '_UEBERINDEX' ) or die( header('location: http://xy.de/') );
if(!isset($_SESSION['usr_id'])){ ?>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" id="registerForm" method="POST" class="registerForm">
<span class="registerForm">email</span> <input type="text" name="reg_email" size="10" maxlength="25" class="registerForm" />
<span class="registerForm">passwort</span> <input type="password" name="reg_pass" size="10" maxlength="25" class="registerForm" />
<input type="submit" name="formsubmit_registerForm" value="register" class="registerForm" />
</form>
<?php } ?>
LOGIN
PHP-Code:<?php
defined( '_UEBERINDEX' ) or die( header('location: http://xy.de/') );
if(!isset($_SESSION['usr_id'])){ ?>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" id="loginForm" method="POST" class="loginForm">
<span class="loginForm">email</span> <input type="text" name="login_email" size="10" maxlength="25" class="loginForm" value="" />
<span class="loginForm">passwort</span> <input type="password" name="login_pass" size="10" maxlength="25" class="loginForm" value="" />
<input type="submit" name="formsubmit_loginForm" value="login" class="loginForm" />
</form>
<?php } ?>
LOGOUT
PHP-Code:<?php
defined( '_UEBERINDEX' ) or die( header('location: http://xy.de/') );
if(isset($_SESSION['usr_id'])){ ?>
<form action="<?php $_SERVER['PHP_SELF']; ?>" id="registerForm" method="POST">
<input type="hidden" name="logout" value="1">
<input type="submit" name="formsubmit_logoutForm" value="logout" />
</form>
<?php } ?>
Diese Formulare rufen die Index.php auf über die sie included wurden.
PHP-Code:<?php
session_start();
define( '_UEBERINDEX', 1 );
//ALLE DATEN SHCON HIER AUFBEREITEN
require_once '../../classes/user.php';
require_once '../../classes/SQLconfig.php';
require_once '../../classes/SecurityHandler.php';
require_once '../../aliases/aliases.php';
$user = new User;
$security = new SecurityHandler();
$dbconn = new OIConf();
$dbconn->connect();
require_once '../../processes/package_user/package_user_processes.php';
if(isset($_SESSION['usr_id'])){$security->save_session();}
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title></title>
<?php include 'css/style.php'; ?>
</head>
<body>
<span style="color:red;">
<?php
foreach($_SESSION as $k => $v){
if($k == 'error'){
foreach($v as $vk => $vv){
echo $vv.'<br>';}
}
}
unset($_SESSION['error']);
?></span>
<div id="top"></div>
<div id="left">
<?php
echo $security->isUserLoggedin();
include "view/package_user/module_logout/logoutForm.php";
echo '<br />';
include "view/package_user/module_register/registerForm.php";
echo '<br />';
include "view/package_user/module_login/loginForm.php";
?></div>
<div id="middle"></div>
<div id="right"></div>
</body>
</html>
<?php $dbconn->disconnect();
?>
Die index.php enthält wie oben gezeigt den Code "require_once '../../processes/package_user/package_user_processes.php';"
Darin sind die .php Datein die die Anfrage der Formulare verarbeiten.
die .php Datein liegen im Ordner /processes und sind nicht über das Webinterface aufrufbar.
jedes Formular hat eine Datei die den Prozess verarbeitet und auch auf ungültige eingaben überprüft, sowie einen Fehler an den User ausgibt wenn etwas nicht stimmt.
REGISTER
LOGINPHP-Code:<?php
defined( '_UEBERINDEX' ) or die( header('location: http://xy.de/') );
if(isset($_POST['formsubmit_registerForm'])){
if(strlen($_POST['reg_pass'])< 6){
$_SESSION['error']['001'] = SESSION_ERROR01;
$confirmprocess = false;
}
if(strlen($_POST['reg_pass'])> 20){
$_SESSION['error']['002'] = SESSION_ERROR02;
$confirmprocess = false;
}
if(strlen($_POST['reg_email'])< 6){
$_SESSION['error']['003'] = SESSION_ERROR03;
$confirmprocess = false;
}
if(strlen($_POST['reg_email']) > 50){
$_SESSION['error']['004'] = SESSION_ERROR04;
$confirmprocess = false;
}
if(!isset($confirmprocess)){
$checkMail = $security->stringControl($_POST['reg_email']);
$checkPass = $security->stringControl($_POST['reg_pass']);
$checkMail = $security->checkemail($checkMail);
if($checkMail != false && $checkPass != false && !isset($_SESSION['user_id'])){
$ver_passwort = $security->verschluesseln($checkPass);
$user->set_email($checkMail);
$user->quick_save_user($ver_passwort, $security->getSalt());
echo 'regestriert! als '.$user->get_email().'';
}
elseif(!$checkMail){
$_SESSION['error']['005'] = SESSION_ERROR05;
}
elseif(!$checkPass){
$_SESSION['error']['006'] = SESSION_ERROR06;
}
elseif(isset($_SESSION['user_id'])){
$_SESSION['error']['007'] = SESSION_ERROR07;
}
else{
$_SESSION['error']['000'] = SESSION_ERROR00;
}
}
}
?>
PHP-Code:<?php
defined( '_UEBERINDEX' ) or die( header('location: http://xy.de/') );
if(isset($_POST['formsubmit_loginForm']) == 'login'){
$checkPass = $security->stringControl($_POST['login_pass']);
$checkMail = $security->stringControl($_POST['login_email']);
if($checkMail != false && $checkPass != false){
$user->get_user($checkMail,$checkPass);
}
elseif(!$checkMail){
$_SESSION['error']['001'] = SESSION_ERROR01;
}
elseif(!$checkPass){
$_SESSION['error']['002'] = SESSION_ERROR02;
}
else{
$_SESSION['error']['000'] = SESSION_ERROR00;
}
}
?>
LOGOUT
PHP-Code:<?php
defined( '_UEBERINDEX' ) or die( header('location: http://xy.de/') );
if($_POST['logout'] == 1){
$_SESSION = array();
if($_COOKIE['session_name()']){
setcookie(session_name(), '', time()-42000, '/');
}
session_unset();
session_destroy();
header('location: /connectionplattform/index.php');
}
?>
Ist die Eingabe O.K. wird die jeweilige Funktion der Klasse aufgerufen, die dann den Eintrag in die Datenbank vornimmt oder Überprüft ob der User in der der Datenbank ist sowie das Passwort verschlüsselt usw.
Dafür gibt es 3 Klassen:
SQLconfig.php enthält die SQL config Datein.
SecurityHandler.php verschlüsselt Passwörter Kontolliert eingaben usw.
user.php alles was mit dem User zu tun hat (user speichern, DB abrufen, einloggen usw.)
Aus Übersichtsgründen kommen die Klassen im nächsten Post....Geändert von Orex (26.11.10 um 02:16 Uhr)
-
Zu den Klassen. Es 3 Klassen:
SQLconfig.php enthält die SQL config Datein.
SecurityHandler.php verschlüsselt Passwörter Kontolliert eingaben usw.
user.php alles was mit dem User zu tun hat (user speichern, DB abrufen, einloggen usw.)
SQLconfig.php
PHP-Code:<?php
defined( '_UEBERINDEX' ) or die( header('location: http://xy.de/') );
/**
* Description of SecurityHandler
*
* @author 1337
*/
class SecurityHandler {
private $input;
private $output;
private $tryCount;
private $sessionHash;
private $salt;
function isUserLoggedin(){
if(isset($_SESSION['user_id'])){return true;}
else{return false;}
}
function stringControl($input){
$output = mysql_real_escape_string($input);
if($input == $output){return $output;}
else{return false;}
}
function erzeugeSalt() {
$auswahl = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456789?}]{[%§&!?ß";
$salt = substr( str_shuffle( $auswahl ), 0, 6 );
$salt = htmlentities($salt);
$this->salt = $salt;
return $salt;
}
function verschluesseln($pass, $salt=NULL) {
if($salt == NULL)
$salt = $this->erzeugeSalt();
$cryptedPasswort = hash('xxx'.$pass.$salt.'xxx').'xxx'; //xxx sind fixed salts
return $cryptedPasswort;
}
function getSalt(){
return $this->salt;
}
function stringControl_id($id){
$id = (int)$id;
return $id;
}
function checkemail($email) {
// externes script! Danke an den Autor "KD3" , hat mir etwas schreibarbeit erspart!!
// http://www.tutorials.de/php-codeschnipsel/303451-email-adresse-ueberpruefen.html
$email = htmlspecialchars($email); // Email-Adresse ( z.B someone@gmx.de
$r = false; // Standard auf false gesetzt, weil wenn die
// if-Abfragen abweichend sind und kein true zurückgegeben wird, dann
if(preg_match('/(.*?)\@(.*?)\.(\w){2,6}/i', $email)) {
$split = explode('@', $email); // [0] => someone , [1] => gmx.de
$split2 = explode('.', $split[1]); // [0] => gmx , [1] => de
if(preg_match('/([a-z]){3,64}/i', $split2[0])) {
if(fsockopen($split[1], 80)) {
if(preg_match('/([a-z0-9\!\"\$\&\/\(\)\?\~\#\+\.\:\_\-]+){1,64}[^\@]/i', $split[0])) {
$r = true;
}
}
}
}
if($r == true){return $email;}
else{return false;}
}
function refreshSession(){
$_SESSION = array();
if($_COOKIE['session_name()']){
setcookie(session_name(), '', time()-42000, '/');
}
session_unset();
session_destroy();
header("location: /index.php");
}
function save_session(){
$sessionid = session_id();
$client_ip = $_SERVER['REMOTE_ADDR'];
$usr_id = (int)$_SESSION['usr_id'];
$query = "INSERT INTO sec (usr_id,sec_usr_session,sec_usr_ip) Values('".$usr_id."','".$sessionid."','".$client_ip."')";
$result = mysql_query($query)
or die(mysql_error());
return $result;
}
}
?>
SQLconfig.php
PHP-Code:<?php
defined( '_UEBERINDEX' ) or die( header('location: http://xy.de/') );
class OIConf{
private $databaseURL = "xxxx";
private $databaseUName = "xxxx";
private $databasePWord = "xxxx";
private $databaseName = "xxxx";
private $connection;
function connect(){
$this->connection = mysql_connect($this->databaseURL,$this->databaseUName,$this->databasePWord);
$db = mysql_select_db($this->databaseName, $this->connection);
}
function disconnect(){
mysql_close($this->connection);
}
}
?>
user.php
PHP-Code:<?php
defined( '_UEBERINDEX' ) or die( header('location: http://xy.de/') );
/*
This is a Guest helper class. Instance of
this class can store Guest information.
*/
class User{
private $UID;
private $name;
private $email;
//private $firstName;
//private $lastName;
//private $country;
//private $streetNr;
//private $plz;
//private $city;
//private $iban;
//private $swift;
//private $birthday;
/* ... */
private $adress;
private $balance;
private $puk;
function set_email($email){
$this->email = $email;
}
function set_name($name){
$this->name = $name;
}
function set_balance($balance){
$this->balance = $balance;
}
function set_adress($adress){
$this->adress = $adress;
}
function get_UID(){
return $this->UID;
}
function get_name(){
return $this->name;
}
function get_email(){
return $this->email;
}
function get_balance(){
return $this->balance;
}
function get_adress(){
return $this->adress;
}
function quick_save_user($password,$salt){
$query = "INSERT INTO users (usr_pass,usr_email,usr_puk) Values('".$password."','".$this->get_email()."','".$salt."')";
$result = mysql_query($query)
or die(mysql_error());
return $result;
}
function change_user(){
$query = "UPDATE users SET usr_email = '" . $this->get_email() ."' WHERE user_id = '". $this->get_UID() ."'";
$result = mysql_query($query)
or die(mysql_error());
return $result;
}
function get_user($email, $passwort){
$query = " SELECT usr_puk
FROM users
WHERE usr_email = '$email' ";
$result = mysql_query($query)
or die(mysql_error());
$row = mysql_fetch_array($result);
$passwort = SecurityHandler::verschluesseln_2($passwort,$row["usr_puk"]);
$query = " SELECT *
FROM users
WHERE usr_pass = '".$passwort."'";
$result = mysql_query($query)
or die(mysql_error());
$row = mysql_fetch_assoc($result);
if(!$row){
$_SESSION['error']['008'] = SESSION_ERROR08;
}
else{
$_SESSION['usr_email'] = $row["usr_email"];
$_SESSION['usr_id'] = $row["usr_id"];
}
return true;
}
}
?>
Eine mir sehr wichtige Frage wäre noch. Ich würde die Userdaten, also EMAIL, USER_ID, NAME, ADRESSE, usw (passwort natürlich nicht) in der $_SESSION variable speichern, da ich es ständig brauche und nicht jedes mal die Datenbank belästigen will.... Ist das sicher?
Falls es zu einem SessionHijacking kommen würde, wäre es eh wurscht weil der Angreifer dann die Daten auch hätte, wenn er die Seiten aufrufen würde. Ändern könnte er nichts, da ich davor nochmal ein Passwort check machen würden..
So abschließend:
JEDEM der das ganze überhaupt liest schonmal ein RIESENGROßES DANKE!
Sollte jemandem dann etwas auffallen was er für eine Sicherheitslücke hält, wäre ich ihm sehr Dankbar wenn er das einfach schnell drunter Posten würde!
Sollte das Script ausgezeichnet sein und keine mängel enthalten, freu ich mich natürlich auch über ein positives feedback.
Vielen Dank
und eine schöne restliche Nacht
Geändert von Orex (26.11.10 um 16:20 Uhr) Grund: fixed function verschlüsseln - thx 2 Bratkartoffel
-
26.11.10 14:00 #3
- Registriert seit
- Jun 2007
- Ort
- Passau (Niederbayern)
- Beiträge
- 1.394
Hi,
habe mir jetzt noch nicht alles durchgelesen (dauert ja auch ein bisschen
), mir ist aber schon was aufgefallen:
In der SecurityHandler die Funktion erzeugeSalt()
Diese erzeugt bei jedem Aufruf einen anderen Salt, den du dann an das Passwort anhängst. Dieser Salt geht aber verloren oder? Wie soll sich dann der Benutzer nochmals anmelden, bzw. wie soll dann das Passwort überprüft werden? Dynamische Salts müssen von irgendwas, das mit dem Benutzer assoziiert ist zusammenhängen (z.B.: email-adresse, benutzername, vorname etc.)
Ausserdem könntest du das auch so verkürzen:
Somit sparst du dir die verschluesseln_2().PHP-Code:function verschluesseln($pass, $salt=NULL) {
if($salt == NULL)
$salt = $this->erzeugeSalt();
$cryptedPasswort = hash('xxx'.$pass.$salt.'xxx').'xxx'; //xxx sind fixed salts
return $cryptedPasswort;
}
In der erzeuge_salt() kannst du das htmlentities() rausnehmen, du hast ja nur ASCII-Zeichen:
In der checkemail() prüfst du auch, ob der Mailserver einen Webserver hat. Diese überprüfung ("if(fsockopen($split[1], 80)) { ") würde ich rausnehmen, ich kenne ein paar Mailserver, die keinen Webserver auf Port 80 laufen haben und somit würden die Adresse abgelehnt werden. Würde hier eher auf Port 25 die Verbindung öffnen (SMTP), der müsste bei jedem Mailserver offen sein.PHP-Code:function erzeugeSalt() {
$auswahl = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz123456789?}]{[%§&!?ß";
$salt = substr( str_shuffle( $auswahl ), 0, 6 );
$this->salt = $salt;
return $salt;
}
$_SESSION sollte sicher sein, die Daten können vom Benutzer nicht direkt manipuliert werden da diese nur auf dem Server bleiben.
Dass du jede Änderung an dem User sofort in die Datenbank schreibst finde ich etwas unperformant. Ich habe da normalerweise so einen Ansatz:
Du kannst im obigen Beispiel also die set-Methoden beliebig oft aufrufen, die Daten werden dann nur einmal in die Datenbank gespeichert (wenn die Seite fertig ist, also der Destruktor aufgerufen wird). Bei dir könnte es halt sein dass du die save-Methode vergisst aufzurufen, bei obigen funktioniert das automatischPHP-Code:class Test {
private $id;
private $name;
// weitere felder
private $is_dirty = false;
public function __construct($pk_in_db) {
// von db laden
}
public function __destruct() {
if($this->is_dirty) $this->saveToDb();
}
private function saveToDb() {
// in die db speichern
$this->dirty = false;
}
// Hier die ganzen set-Methoden, sobald ein Wert verändert wird,
// dann wird die $this->dirty auf true gesetzt.
}

Gruß
BKGeändert von Bratkartoffel (26.11.10 um 14:05 Uhr)
Über eine gute Bewertung freut sich jeder ;)
Bitte erledigte Threads als "Erledigt" markieren.
"Though a program be but three lines long, someday it will have to be maintained.''
-- Geoffrey James, "The Tao of Programming"
-
Hey, vielen dank schonmal! Werde deine Vorschläge sofort umsetzten und nacher auch die Posts mal ändern!
Der Salt wird in der DB gespeichert. Jeder user hat nen anderen Salt und der wird in der spalte "tan" abgelegt.Geändert von Orex (26.11.10 um 15:03 Uhr)
Ähnliche Themen
-
Sicherer Auto-Login
Von ZodiacXP im Forum Coders TalkAntworten: 0Letzter Beitrag: 04.09.09, 11:30 -
Sicherer Upload
Von Pius Hermit im Forum PHPAntworten: 5Letzter Beitrag: 11.01.09, 21:09 -
Sicherer Hash
Von ZodiacXP im Forum PHPAntworten: 3Letzter Beitrag: 05.09.08, 00:13 -
2x Escapen sicherer?
Von KD3 im Forum PHPAntworten: 1Letzter Beitrag: 22.05.07, 01:10 -
Sicherer Login mit CMS
Von Lyn555 im Forum Coders TalkAntworten: 3Letzter Beitrag: 17.03.07, 13:56





Zitieren

Login






[PHP][Snippet] Array zu XML konvertieren