#dlaczego jest to (nie)bezpieczny sposób możemy dowiedzieć się z naszego forum(klikamy tutaj) - warto zobaczyć o co biega, gdyż może i w twoim skrypcie występuje ten błąd - ds
Zanim zaczniemy, wypadałoby się przygotować do pracy, no i oczywiście przygotować nasze skromne środowisko pracy. Mój przykład będzię się znajdował w katalogu / - Wy sobie wybierzcie inny, ale jeśli ja bede używał gdzieś tego skrótu to chce żebyście wiedzieli, że chodzi o katalog w którym znajduje się strona główna.
Teraz, przygotujemy sobie bazę MySQL'a, możesz sobie nazwać ją dowolnie, w moim przykładzie tabela z użytkownikami będzie nosić nazwę users i zawierać będzie tylko 4 pola (w praktycznym zastosowaniu, może zawierać i 150 pól dot użytkownika, te 4 są jednak niezbędne) Oto te pola:
id - int(11) - auto_increment
user - varchar(50)
pass - varchar(50)
nick - varchar(50)
Zapytanie SQL do stworzenia takowej tabeli to:
Kod:
CREATE TABLE `users` (
`id` int(11) NOT NULL auto_increment,
`user` varchar(50) NOT NULL default '',
`pass` varchar(50) NOT NULL default '',
`nick` varchar(50) NOT NULL default '',
PRIMARY KEY (`id`)
) TYPE=MyISAM AUTO_INCREMENT=17 ;
Krótkie objaśnienie:
pola id nie uzupełniamy - sam sie uzupełnia automatycznie!
w polach user i pass są przechopwywane zaszyfrowane dane! TAK - to oznacza, że nie widać na pierwszy rzut oka!
Pole nick służy nam do tego, żeby wiedzieć jak się zwracać do naszego kochanego użytkownika.
Teraz przejdzmy juz do konkretów, ważniejszym sposobem zabezpieczenia, ważnych dla nas plików jest zabronienie ludziom oglądania ich, zróbmy tak żeby tylko maszyna mogła czytać pliki. Tworzymy w tym celu katalog, a w nim plik:
/tajne/ - katalog
/tajne/.htaccess - plik
Do pliku .htaccess wpisujemy jedynie "deny from all", dzięki temu nasz Apache nie polwoli nikomu wejść do naszego
tajnego katalogu, nikt nie wejdzie leczy my (nasza strona) będziemy mogli includować umieszczone tam pliki.
Naszym najważniejszym plikiem będzie config.php, zawierać on będzie ważne dane oraz funkcje. Umieszczamy go w /tajne/
Oto jego zawartość wraz z opisem:
/tajne/confg.php
Kod:
<?php
/* Gdyby, ktoś(czytaj zły niedobry hacker) popsuł apacha tak, że nie widzi plików .htaaccess to musimy sami upewnić się czy plik został tylko includowany */
if(eregi("config.php",$_SERVER['PHP_SELF']) OR eregi("config.php",$_SERVER['QUERY_STRING']))
{ header("Location: /"); die(); }
/* Klucz XOR dla szyfrowania cookie dowolny ciąg znaków - musi mieć dokładnie 64 znaki
2x hash md5 */
$_CONFIG['kxc'] = "a523d703f908dd69e02db64ec35d07315f4c49ab3cacad14a97304b02f2fbb09";
/* Dane potrzebne do zalogowania sie do bazy MySQL - zastap swoimi */
$_CONFIG['MySQL']['host'] = "localhost";
$_CONFIG['MySQL']['user'] = "strefaphp";
$_CONFIG['MySQL']['pass'] = "super tajne haslo, ktore zawiera znaczki i cyfry #8 (no i jest dlugie)";
$_CONFIG['MySQL']['base'] = "strefaphp";
/* jesli nie mamy swojej sesji to ja zakladamy */
if(!isset($_SESSION['sesja'])) {
session_start();
$_SESSION['sesja'] = '';
}
/* Łączymy sie z Bazą Danych, jesli coś jest nie tak - wyskakuje nam "przyjazny" komunikat */
@mysql_connect($_CONFIG['MySQL']['host'], $_CONFIG['MySQL']['user'], $_CONFIG['MySQL']['pass']) or die('<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=iso-8859-2">
<title>Err0r</title>
<style type="text/css">
body { background: #FFFFFF; }
div { font-family: Verdana, Arial; font-size: 12px; color: #000000; }
</style>
</head>
<body>
<div>
Przepraszamy, wystąpiła chwilowa awaria serwisu.<br>
<br>
<b>Nie mogę połączyć się z serwerem bazy danych.</b><br>
<br>
Proszę powiadom <a href="mailto:ustek@ustek.one.pl">Webmastera</a>.
</div>
</html>');
/* To samo co wyżej, z tym, że teraz wybieramy bazę */
@mysql_select_db($_CONFIG['MySQL']['base']) or die('<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=iso-8859-2">
<title>Err0r</title>
<style type="text/css">
body { background: #FFFFFF; }
div { font-family: Verdana, Arial; font-size: 12px; color: #000000;}
</style>
</head>
<body>
<div>
Przepraszamy, wystąpiła chwilowa awaria serwisu.<br>
<br>
<b>Nie mogę odnaleść bazy Danych.</b><br>
<br>
Proszę powiadom <a href="mailto:ustek@ustek.one.pl">Webmastera</a>.
</div>
</html>');
function login() {
/* Pewnie sie zastanawiasz czemu nie globalizujemy tez potrzebnej nam tablicy $_POST - otórz ona już jest globalizowana - automatycznie */
global $_CONFIG;
/* Niezalogowany dopuki nie udowodni, że jest tym za kogo się podaje */
$zalogowany = false;
/* W pierwszej kolejności będą brane pod uwage dane z cistek, potem sesji, na końcu z formularza. Ta część funkcji ma ustalić, skąd pochodzą dane, i upewnić się, że owe dane są zaszyfrowane w md5. strtolower przy loginie, ma za zadanie sprawić, by wielkość liter nie miała znaczenia - ale tylko przy loginie */
if(isset($_COOKIE["dane"])) {
$dane = $_COOKIE["dane"]^$_CONFIG['kxc'];
$login = substr($dane, 0, 32);
$haslo = substr($dane, -32);
$metod = "cookies";
}
elseif(isset($_SESSION['login']) AND isset($_SESSION['haslo'])) {
$login = $_SESSION['login'];
$haslo = $_SESSION['haslo'];
$metod = "session";
}
elseif(isset($_POST['login']) AND isset($_POST['haslo'])) {
$login = md5(strtolower($_POST['login']));
$haslo = md5($_POST['haslo']);
$metod = "post";
}
/* Jeśli istnieje $metod - czyli jeśli dane zostały dostarczone, to sprawdzamy czy są poprawne. Możemy spokojnie wstawić zmienne $login i $haslo do zapytania SQL bo obydwie zmienne, zawsze i wszędzie wyglądać będą tak samo dwa ciągi zawierające 32 znaki czyli 2x hash md5 :> */
if(isset($metod)) {
$query = mysql_query("SELECT * FROM `users` WHERE `user`='".$login."' AND `pass`='".$haslo."';");
/* Jeśli baza danych zwróciła tylko jeden wynik to haslo i login zostały odnalezione zatem $zalogowany = true, ale oprucz tego musimy sie upewnić, że dane, które wykożysaliśmy nam nie przepadną */
if(mysql_num_rows($query) == 1) {
$zalogowany = true;
/* Jeśli dane nie pochodzą z sesji, to umieszczamy je w sesji + zapisujemy w sesji info, ktore może się do czegoś przydać, np nick */
if($metod <> "session") {
$wiersz = mysql_fetch_array($query);
$_SESSION['login'] = $wiersz['user'];
$_SESSION['haslo'] = $wiersz['pass'];
$_SESSION['nick'] = $wiersz['nick'];
/* Jeśli dane pochodzą z formularz i dodatkowo gość poprosił o zapamiętanie danych na przyszłość to dodatkowo umieszczamy potrzebne (zaszyfrowane) dane w cisteczkach */
if($metod == "post" AND isset($_POST['pamietaj']) AND $_POST['pamietaj'] == "ok") {
$dane = ($login.$haslo)^$_CONFIG['kxc'];
setcookie ("dane", $dane,time()+3600*24*365); /* straci ważnosc za rok */
}
}
}
}
return $zalogowany;
}
/* Wylogowanie, polega na zniszczeniu danych, które znajdują sie w sesji i jeśli są w cistakach to tam też sprzątamy */
function logout() {
if(isset($_COOKIE["dane"]))
setcookie ("dane", "",time()-3600*24*365);
unset($_SESSION['login']);
unset($_SESSION['haslo']);
unset($_SESSION['nick']);
}
?>
No kurde! :) Ładną funkcje napisaliśmy, teraz wypadałoby pokazać jak ją zastosować. Jako, że w pliku /tajne/config.php będziemy trzymać inne bardzo pomocne funkcje, oczywistym wydaje się, że będziemy includować ten plik...
Logować się będziemy przy drobnej pomocy pliku /logowanie.php a o to i on:
Kod:
<?php
include('tajne/config.php');
/* Jeśli funkcja zwróciła nieprawdę (false) znaczy, że gość nie jest zalogowany I jeśli forumularz nie został wyslany czyli nie ma $_POST['logowanie'] to wyswietlamy formularz do logowania */
if(!login() AND !isset($_POST['logowanie'])) {
$text = '
<br>
<center>
<table width="100%" cellpadding="5" cellpadding="0">
<th class="h">Logowanie!</th>
<tr>
<td align="center">
<br>
<br>
<form action="" method="post" name="loguj">
<input type="hidden" name="logowanie" value="k">
<table cellpadding="0" cellspacing="0">
<tr>
<td>Login: </td>
<td><input type="text" style="width: 250px" name="login"></td>
</tr>
<tr><td><img src="" width="1" height="3"></td></tr>
<tr>
<td>Hasło: </td>
<td><input type="password" style="width: 250px" name="haslo"></td>
</tr>
<tr>
<td colspan="2">
<input type="checkbox" name="pamietaj" value="ok"> - Zapamiętaj mnie!<br>
</td>
</tr>
</table>
<br>
<table cellspacing="7"><tr><td>
<input type="submit" value="Loguj!">
</td><td> </td></tr></table>
</form>
</td>
</tr>
</table>
';
die($text);
}
/* Podobnie jak wyżej, ale inaczej: jesli nie jesteśmy zalogowani, a forularz został wysłany! czyli istnieje $_POST['logowanie'] to znaczy, że ktoś wpisał złe dane*/
if(!login() AND isset($_POST['logowanie'])) {
$text = '
<br>
<center>
<table width="100%" cellpadding="5" cellpadding="0">
<th class="h">Logowanie!</th>
<tr>
<td align="center">
<font color="red"><b>Zły Login lub Hasło!</b></font><br>
<br>
<form action="" method="post" name="loguj">
<input type="hidden" name="logowanie" value="k">
<table cellpadding="0" cellspacing="0">
<tr>
<td>Login: </td>
<td><input type="text" style="width: 250px" name="login"></td>
</tr>
<tr><td><img src="" width="1" height="3"></td></tr>
<tr>
<td>Hasło: </td>
<td><input type="password" style="width: 250px" name="haslo"></td>
</tr>
<tr>
<td colspan="2">
<input type="checkbox" name="pamietaj" value="ok"> - Zapamiętaj mnie!<br>
</td>
</tr>
</table>
<br>
<table cellspacing="7"><tr><td>
<input type="submit" value="Loguj!">
</td><td> </td></tr></table>
</form>
</td>
</tr>
</table>
';
die($text);
}
/* Jeśli doszliśmy tak daleko (czyt. do tego komentarza) to znaczy, że nie wystąpił żaden błąd, i że prawdopodobnie jesteśmy zalogowani, ale cuda czasem sie dzieją, więc lepiej sprawdźmy to jeszcze raz, jeśli jesteśmy zalogowani to w sesji powinieny się pojawić jakieś fajowe informacje o zalogowanym np nick*/
if(login()){
$text = 'Witaj '.$_SESSION['nick'].'!<br>
<br>
Moje gratulacje udało Ci się zalogować, trzeba przyznać, dobry jesteś!<br>
<br>
Możesz teraz przejść do super tajnego działu MEMBERS :D<br>
<br>
<a href="members.php">Super Tajny Dział MEMBERS</a>';
die($text);
}
?>
No i proszę.
Umiemy się już logować. Teraz zapewne każdy inteligentny kosmita zapytałby - po co tyle zabawy???
Odpowiedz jest bardzo prosta, bo jest to wygodne w eksploatacji (patrz plik /members.php):
Oto plik /members.php:
Kod:
<?php
include('tajne/config.php');
/* Jeśli nie jesteśmy zalogowani, to musimy się pożegnać */
if(!login()) {
$text = '
Bardzo mi przykro, ale ten dział wymaga autoryzacji!<br>
<br>
(dla ciołków: Musisz się zalogować BARANIE!!!)<br>
<br>
<a href="logowanie.php">Logowanie</a>';
die($text);
}
/* Jeśli się nie pożegnaliśmy, to znaczy, że jesteśmy zalogowani */
$text = '
To jest ten super tajny i super ważny dział MEMBERS!<br>
<br>
Podoba Ci się???<br>
<br>
Mam lepsze nowiny, sesje nadal tutaj działają.<br>
Chcesz dowodu?<br>
Twój nick to: '.$_SESSION['nick'];
die(text);
?>
No i to było by na tyle, jeśli chodzi o (nie)bezpieczny sposób na logowanie. Tak wiem - on jest prymitywny, jest prymitywny, żebyś i Ty mógł go zrozumieć. Scryp taki można dowolnie rozbudowywać, pokazuje on jednie ideologie i mechanizm działania tego rodzaju skryptów. Być może za jakiś napisze jakiś, bardziej
atrakcyjny artykuł, gdzie dowiemy się jak rejestrować się przy takim logowaniu, i jak odzyskać zapomniane hasło.
Wszytskie (nie) w artykule neleży skreslić lub pozostawić wedle własnego uznania.
Skrypt jest tylko skryptem, a ja jestem tylko człowiekiem. Mogą byc błędy - i znając życie są ;]
Jeśli jakiś znalazłeś to proszę powiedz jak gdzie i po co go popełniłem, postaram się poprawić.
Wszystkie bluzgi, krytyki, podziękowania, gratulacje, majtki i staniki dziewczyn przysyłajcie na mój mail, jak znajde czas to odpowiem.
btw. wszytskie błędy ort popełniłem specjalnie, żeby się Wam trudniej czytało :)