Защита с парола. Парола за страницата

Поставяме парола на страницата

Тази статия не претендира за някакво откровение, всички тези неща са доста очевидни и широко известни. Но след като напоследък получих няколко въпроса относно ограничаването на достъпа до уеб страници, реших да събера отговорите на тях.

Така че нашата задача е да зададем парола за достъп до определена страница. Нека започнем с най-примитивната, ако мога така да се изразя, защита - няколко реда JavaScript "e. Кодът е нещо като

Var pass = prompt ("Въведете паролата:", ""); if (pass == null) window.location = "bad.html"; иначе if (pass.toLowerCase () == "парола") window.location = "ok.html"; else window.location = "bad..js">фундаментално нищо не променя.

По-високо ниво е подобна система, внедрена в Java.

По-долу е даден опростен изходен код.

Импортиране на java.applet. *; импортирайте java.awt. *; импортирайте java.net. *; public class Password разширява аплета (вход за текстово поле, парола; низ за влизане = "вход"; низ парола = "парола"; публична парола () () public void init () (панел панел = нов панел (); panel.setLayout (нов GridLayout (2,2)); вход = ново TextField (20); парола = ново TextField (20); panel.add (нов етикет ("Login:")); panel.add (вход); panel.add (нов Етикет ("Парола:")); panel.add (парола); добавяне (панел); добавяне (нов бутон ("Ok"));) публично булево действие (Event evt, Object obj) (if (evt.target instanceof Бутон) (String s; if (login.getText (). Equals (Login) && password.getText (). Equals (Password)) (s = "http://www.webclub.ru/materials/ pagepsw / ok. html ";) else (s =" http://www.webclub.ru/materials/ pagepsw / bad.html ";) опитайте (getAppletContext (). showDocument (нов URL (s));) catch (Изключение e) (password.setText (e.toString ());) върне true;) върне false;))

Като включите този аплет в страница, можете да получите нещо подобно:

Проверка на паролата

Може да се направи по-интелигентен, да се създаде отделна страница за всеки потребител, да се накара да чете данни от файл и т.н. Основният недостатък е, че след като човек е стигнал до желаната страница, никой не може да му попречи да запомни този URL, така че това е еднократен инструмент. Разбира се, можете да скриете страницата в рамка, така че URL адресът да не свети в адресната лента, но вие сами разбирате от кого е тази защита. Отново аплетът отива изцяло на клиента и по принцип е напълно достъпен за проучване.

Решението, базирано на използването на CGI, е лишено от последния недостатък. Прост скрипт на Perl изглежда така:

#! / usr / bin / perl използва CGI qw (: стандартен); $ query = нов CGI; $ ok = "ok.html"; $ address = "bad.html"; $ login = "вход"; $ password = "парола"; $ l = $ query-> param ("вход"); $ p = $ query-> param ("парола"); if (($ p eq $ парола) && ($ l eq $ вход)) ($ адрес = $ ok;) print $ query-> redirect ($ адрес);

Пример за употреба:

За да се справите с първия недостатък, можете динамично да генерирате нова страница въз основа на това, което е скрито някъде вътре, без да издавате URL адреса.

Променен код:

#! / usr / bin / perl използва CGI qw (: стандартен); $ query = нов CGI; $ ok = "ok.html"; $ address = "bad.html"; $ docroot = $ ENV ("DOCUMENT_ROOT"); $ localpath = "/ материали / pagepsw /"; $ login = "вход"; $ password = "парола"; $ l = $ query-> param ("вход"); $ p = $ query-> param ("парола"); if (($ p eq $ парола) && ($ l eq $ вход)) ($ адрес = $ ok;) print $ query-> header (); отворен (FL, $ docroot. $ localpath. $ адрес); докато ( ) (# Тук в същото време можете да променяте html-кода в движение # Защо? Е, никога не знаете... :) print $ _; ) затваряне (FL);

Пример за употреба:

Както можете да видите, URL адресът на файла вече не свети, макар и за сметка на SSI, ако имаше нещо подобно (но това може да бъде уловено в изхода и обработено ръчно). Но дори и тук остава теоретична възможност за отгатване на URL адреса, като същевременно не трябва да забравяме, че всякакви снимки, включени в страниците, могат да направят лоша услуга – при използване на относителни пътища, разбира се.

И накрая, най-надеждният начин да зададете парола за достъп е да използвате сървърните инструменти - в края на краищата хората не напразно ги направиха. Ще се съсредоточа върху две - Apache като най-популярен и IIS като популярен също :)

С IIS всичко е доста просто - защитата се осъществява с помощта на NTFS, което, разбира се, донякъде ограничава възможностите на администраторите, които не са сървъри. Идеята е следната: на потребителя IUSR_xxxx, под чийто акаунт работят всички посетители на сайта по подразбиране, е отказан достъп до желания файл / директория. След това само тези потребители, за които това е изрично посочено в Properties-> Security, ще имат достъп до тези файлове. Ясно е, че е много по-удобно да ги комбинирате в групи. Тук има няколко тънкости. Първо, на посочените потребители трябва да бъде предоставено правото на локално влизане (Policies-> User Rights в User Manager "e). Второ, ако не изберете услугата Основно удостоверяване (Clear Text) в настройките на WWW, само потребителите на Internet Explorer ще бъдат разрешено вътре. "a.

Apache прави нещата малко по-различно. Защитата се поставя на ниво директория. Съответните директиви могат да бъдат поставени както в общия конфигурационен файл (в раздела ) и .htaccess файлове. Наборът от директиви и в двата случая е еднакъв и за повечето хора, които наемат място за сайт/страница на чужд сървър, вторият метод е много по-актуален. И така, създавате файл .htaccess в директорията, до която планирате да ограничите достъпа, и след това вмъквате следните директиви в него (ето основните):

AuthType вид контрол- Обикновено се използва Basic.

AuthName име- определя името на областта, в която са валидни потребителските имена и пароли. Това е името, което браузърът показва в диалоговия прозорец за въвеждане на парола. Като зададете едно такова име за различни директории, можете да спестите на потребителите време за въвеждане на допълнителна парола.

AuthGroupFile име- определя името на файла, който съхранява имената на групите и техните членове. Форматът му е:
група1: член1 член2 ...
група2: член3 член4 ...

AuthUserFile име- задава името на файла с парола. Като цяло, за да го генерирате, трябва да използвате помощната програма htpasswd от дистрибуцията на Apache. Но поне за някои версии на сървъра този формат е:
потребител 1: passwordhash1
потребител 2: passwordhash2

Passwordhash е доста достъпен със стандартна функция на Perl:
$ хеш = крипта ($ пас, $ сол);
където $ pass е паролата, $ salt е низ от два знака, използван за формиране на хеша.

Така че е напълно възможно да се автоматизира процеса на добавяне на нови потребители, промяна на пароли чрез html формуляри и т.н.

изисква потребител потребител1 потребител2и изискват група потребител1 потребител2ви позволяват да посочите кои потребители и групи ще имат достъп до дадена директория.

изискват валиден потребителпозволява достъп на всички потребители, посочени в системния файл с парола.

... къде метод идефинира HTTP метод. Например, ограничава използването на вложени директиви до случаите на използване на методите GET и POST (обикновено това е повече от достатъчно). Директивите Require, Order, allow и deny могат да бъдат вложени.

Още няколко полезни директиви - забрани и разреши - съответно забрани и разреши достъп. Използват се така:
отрича от всички
позволете от 192.168

По подразбиране първо се изпълнява всички откази, а след това всички разрешаване, така че разреши от всички ще разреши достъп на всички потребители, независимо от отказа. Поръчката може да бъде променена със заповедта: директива разреши, забрани.

deny from all е идеално комбиниран с втория метод за защита на страници чрез CGI, именно с тази директива е най-добре да скриете всички пароли за книги за гости и т.н.

Между другото, тук, между времената, ние демонстрираме независима обработка на грешки: в този случай кодът 403, Забранено. Любимите на всички 404, Not Found и 401, Unauthorized се обработват по подобен начин. За да направите това, просто добавете директивата към .htaccess ErrorDocument url код:
ErrorDocument 404 /cgi-bin/bad.pl
ErrorDocument 403 /cgi-bin/badaccess.pl
ErrorDocument 401 /cgi-bin/badaccess.pl

Всичко, което скриптът прави, е да генерира съобщение за грешка, използвайки променливата на средата REQUEST_URI, така че можете просто да посочите подходяща страница вместо това.

За последния пример, нека използваме файла .htaccess със следното съдържание:

AuthType Basic AuthName Тест AuthGroupFile /.../pagepsw/deny/tgroup AuthUserFile /.../pagepsw/deny/tuser изискват групов тест

Във файла tgroup има само един ред - тест: тест за влизане, във файла tuser - криптирани пароли за влизане (парола) и тест (тест). Моля, имайте предвид, че когато отворите повторно тази страница, браузърът разбира, че току-що е осъществил достъп до тази област и не притеснява потребителя с ненужна заявка за парола.

Накратко, това е минималният набор от информация, необходима за защита на уеб страниците. Както показва практиката, струва си повече или по-малко да се доверявате само на решения, базирани на средствата, предоставени от сървъра (и след това, докато се намери следващата дупка в сървъра), така че ако има възможност, по-добре е да ги изберете.

Обсъждат се прости начини за затваряне на директория или файлове с парола. Как да оторизирате потребител чрез бисквитки. Идентификация на потребителя чрез вградения механизъм на сесията на PHP4.

Парола за страницата. Част 1. По-скоро теоретична.

Реших да опиша начини за защита с парола на част от сайта. Темата всъщност е голяма, така че за първи път ще се огранича само с php + mysql авторизация.

Първият въпрос, който обикновено възниква, е как да затворите директорията с административните скриптове с парола. В същото време не са необходими излишни украшения - един или няколко администратора имат еднакви права, а личностите рядко се променят. Най-лесният начин в тази ситуация да използвате стандартна авторизация на сървъра е да поставите файловете .htaccess и .htpasswd и да запишете необходимите параметри в тях.

Ще добавя две неща. Първото е къде да поставите файла .htpasswd. Експериментално установих, че ако, например, пътят към документа със съобщението за грешка (ErrorDocument) е написан спрямо системната променлива DocumentRoot. Но пътят до файла с пароли (UserFile) се записва спрямо ServerRoot. Доколкото разбирам е невъзможно да се постави .htpasswd над ServerRoot - "../" не се възприема. Всичко това се прави, за да можете да поставите файл с пароли, например, едно ниво над главната директория на сайта, така че изобщо да няма достъп до файла от мрежата.

Второто е, че скриптът може да разбере кой го отваря и паролата: променливите $ PHP_AUTH_USER и $ PHP_AUTH_PW.

Основният недостатък на този метод е, че сървърът не може да блокира отгатването на парола (след няколко неуспешни опита за влизане, потребителят е помолен да изчака час или два и през това време заявките от неговия IP адрес се игнорират). Написано е в официална документацияот Apache.

Друг недостатък е необходимостта от презаписване на файлове с пароли при изтриване на потребител или въвеждане на нов. Но ако това се случва рядко, този метод е напълно достатъчен, освен това не е нужно да се притеснявате да пишете механизъм за оторизация.

Автоматизация на авторизацията

Това е необходимо не само за опростяване на работата с голям брой потребители и техния голям "оборот". Ако трябва да съхранявате допълнителна информация за потребителите или имате нужда от гъвкаво разграничаване на правата, по-добре е да прехвърлите оторизацията към базата данни.

Всяка страница от затворената територия включва файл със следния код:

$ result = mysql_query ("SELECT * FROM person WHERE login =" ". preg_replace (" / [^ \\ w _-] / "," ", $ PHP_AUTH_USER)." "И преминете =" ". md5 ($ PHP_AUTH_PW). ). "" "); if (@mysql_num_rows ($ резултат)! = 1) (заглавка ("WWW-Удостоверяване: Основна област = \" Потребителска област \ ""); заглавка ("HTTP / 1.0 401 Неупълномощен"); print ("За да влезете в потребителя част от сайта, трябва да въведете потребителско име и парола. "); изход ();); $ user_row = mysql_fetch_array ($ резултат);

В първия ред всички знаци с изключение на букви, цифри, тирета и долни черти се премахват от входа. След това се проверява броят на получените линии и само ако е един ред, се дава достъп. В други случаи потребителят ще види прозорец в браузъра, предлагащ да въведете потребителско име и парола. Ако потребителят е влязъл успешно, имаме цялата информация за него в масива $ user_row.

Разбира се, примерът, който дадох, има редица съществени недостатъци. Не го преписвайте едно към едно, за да не станете жертва на опити за отгатване на парола, т.к.
1.няма защита срещу бране
2. ако потребителската таблица е голяма, нападателят най-вероятно ще "попълни" базата данни, когато познае паролата

И последният метод за днес е съхраняването на криптирани данни в бисквитки.

Има скрипт за влизане, останалите свързват кода, който само позволява продължетедействия в частната зона - ако бисквитката изтече или той излезе от там, ще трябва да се върнете на страницата за вход.

Скриптът за влизане проверява потребителското име и паролата и издава две бисквитки. В първия има вход за незабавно идентифициране на потребителя (в базата данни полето за вход, разбира се, е уникално или дори ключово). Втората бисквитка съдържа хеша на времето за влизане и паролата (за пълнота на конспирацията добавям буквата "Y" към тези редове - тогава е почти невъзможно да се намери хеша :).

Всички други програми включват код, който прави следното. Прави заявка към базата данни - избира реда с полученото влизане. От този ред той взема полето "log_time" и паролата и прави хеширане от тях, както е описано по-горе. Сравнява го с полученото и ако съвпадат, издава нова хеш бисквитка отново от паролата, часа и буквата "Y" и прави заявка към базата данни "UPDATE user SET log_time =" ... "КЪДЕ login = "$ cookie_login" ".

If (isset ($ HTTP_COOKIE_VARS [$ cookie_login]) && isset ($ HTTP_COOKIE_VARS [$ cookie_code])) ($ вход = $ HTTP_COOKIE_VARS [$ cookie_login]; $ код = $ HTTP_COOKIE_VARS [$ cookie_qcode]; $ резултат = mys "mys" date_format (log_date, "% Y% m% d% H% i% s") като log_date1, pass, uid ОТ потребител WHERE email = "$ login" И log_date> "DATE_SUB (СЕГА (), ИНТЕРВАЛ 15 МИНУТИ)" " ); if (! mysql_error () && @mysql_num_rows ($ резултат) == 1) ($ log_time0 = време (); $ log_time1 = дата ("YmdHis", $ log_time0); $ log_time2 = дата ("Ymd H: i : s ", $ log_time0); $ current_user = mysql_fetch_array ($ резултат); if (md5 ($ current_user [" pass "]. $ current_user [" log_date1 "]. $ md5letter) == $ код) (mysql_query (" АКТУАЛИЗИРАНЕ). потребител SET log_date = "$ log_time2" WHERE uid = ". $ current_user [" uid "]); setcookie ($ cookie_code, md5 ($ current_user [" pass "]. $ log_time1. $ md5letter), time () + 900, $ site_path); $ auth = true;) else unset ($ current_user);););

Отново няма защита срещу атаки с груба сила и атаки на сървъра (между другото, тук можете да напишете IP адреса на потребителя вместо буквата "Y" - така че, например, съсед от офиса да не може да вземе бисквитка файл и влезте от неговия компютър).

Парола за страницата. Част 2. Заключване

Когато пуснах този брой последния път, се спънах на място, казват, че с такова заключване можете и да "дерайлирате" сървъра.

Но първо, относно блокирането на селекцията. Бастилности, но все пак. Парола от десет знака от латински букви и цифри - има много опции. Ако се опитате да познаете парола с 1 000 000 вариации в секунда, това ще отнеме няколко хиляди години. Но тъй като подобни глупости са трудни за запомняне, често правим парола от смислени думи. Преди няколко години се оказа, че повечето пароли могат да се отгатнат с помощта на речник от 10 000 думи. По едно време в мрежата се появи червей (такъв вирус), който се катери на сървърите на Unix, използвайки техните дупки в сигурността, и вдигна паролите на привилегировани потребители, използвайки ... правописния речник на системата Unix. Нямаше нужда да носите нищо!

Всеки потребител, докато не въведе правилното потребителско име и парола, се счита за злобен хакер. С какво се занимаваме, когато потребителят въведе нещо нередно?

  • забравяне (за това на прилични сайтове има формуляр "забравена парола", за да изпратите същата парола на имейла, въведен в системните настройки)
  • самоугаждане ("за нефиг")
  • избор на парола с помощта на речник (вероятността за успешна селекция е висока, поради което е необходимо да я затворите, особено ако сайтът е с търговски характер)
  • DoS атака (за да не се претовари сървъра, е необходимо да се сведат до минимум действията, които скриптът ще извърши в този случай)

    От доста време си мисля как е възможно да се предизвика претоварване на сървъра, ако защитният механизъм е на файловете. Оказа се лесно (колко ще струва е друг въпрос). Така че, да кажем, че сървърът няма да оцелее, ако скриптът се опита да отвори файлове за писане 1000 пъти в секунда и да запише данни в тях. Тъй като след 5 неуспешни опита за влизане в системата, потребителят веднага ще получи отказ за достъп (без запис на данни във файла), е необходимо да се намерят 200 уникални IP адреса, от които пет пъти и да се приложи. Възможно е. Окачваме html банер с пет тагове в ротатора на банера:

    Потребителят незабавно прави пет обаждания, сървърът пише във файла пет пъти (между другото, в някои браузъри може да се появи прозорец за въвеждане на потребителско име и парола). Можете да направите html страница с пет такива снимки и да вмъкнете самата страница през iframe в посещавания сайт (чрез iframe - за да не се намери референтното поле. Малко вероятно е безплатната услуга за поддръжка на хостинг да се справи с такива неща като ровене в регистрационни файлове в търсене на реферали) ... Примерите, които дадох, разбира се, са разтегнати, но самият факт, че можете да се възползвате от такъв недостатък на системата, е доказан. Между другото, нещо подобно вече се е случило.

    Но все пак ще дам този метод - писах напразно, или какво? Между другото, може да се използва без много страх за ограничен брой адреси (например за локалната мрежа на компания), като поставите в директорията файл .htaccess със следното съдържание:

    Отказване на поръчка, разрешаване отказ от всички позволете от xxx.xxx.xxx

    А ето и програмния код:

    $ грешки = 0; $ fn = "игнориране /". preg_replace ("[^ \ d \.]", "", $ REMOTE_ADDR. ".". $ HTTP_FORWARDED_FOR); if (is_file ($ fn)) (if (време на файла ($ fn)< time()-3600) unlink($fn); else $errors = fread(fopen($fn, "r"), 2); }; if ($errors>5) (печат ("Достъпът е отказан. Върнете се след час."); Изход (););

    // тук се установява връзка със сървъра на базата данни. за да не го пипа напразно, ако потребителя веднага бъде "бит".

    $ result = mysql_query ("SELECT * FROM user WHERE login =" ". preg_replace (" / [^ \ w _ \ -] / "," ", $ PHP_AUTH_USER)." "И преминете =" ". md5 ($ PHP_AUTH_PW). ). "" "); if (@mysql_num_rows ($ резултат)! = 1) (заглавка ("WWW-Удостоверяване: Основно царство = \" секретна област \ ""); заглавка ("HTTP / 1.0 401 Unauthorized"); печат ("Изисква се упълномощаване") ; fwrite (fopen ($ fn, "w"), ++ $ грешки); exit ();); $ current_user = mysql_fetch_array ($ резултат); mysql_free_result ($ резултат);

    Въпреки това е грях да се работи с файлове, ако има база данни. шега. За неуспешни оторизации създайте таблица:

    CREATE TABLE unauth (потребителско име VARCHAR (64) NOT NULL, подаване на VARCHAR (64) NOT NULL, ip VARCHAR (255), време за влизане TIMESTAMP)

    И вместо да осъществяваме достъп до файлове, ние работим с базата данни.

    $ errors = @mysql_result (mysql_query ("SELECT count (username) as falses FROM unauth WHERE logintime> DATE_SUB (СЕГА (), ИНТЕРВАЛ 1 ЧАС) И ip =" $ REMOTE_ADDR ""), 0); if (mysql_error ()) умре (mysql_error ()); if ($ errors> 5) (отпечатайте ("Достъпът е отказан. Моля, върнете се след час."); изход ();); $ result = mysql_query ("SELECT * FROM user WHERE login =" ". preg_replace (" / [^ \ w _ \ -] / "," ", $ PHP_AUTH_USER)." "И преминете =" ". md5 ($ PHP_AUTH_PW). ). "" "); if (@mysql_num_rows ($ резултат)! = 1) (заглавка ("WWW-Удостоверяване: Основно царство = \" секретна област \ ""); заглавка ("HTTP / 1.0 401 Unauthorized"); печат ("Изисква се упълномощаване") ; mysql_query ("INSERT INTO unauth (потребителско име, пропуск, ip) VALUES (" $ PHP_AUTH_USER "," $ PHP_AUTH_PW "," $ REMOTE_ADDR $ HTTP_X_FORWARDED_FOR ")"); изход (); $ current_user = mysql_fetch_array ($ резултат); mysql_free_result ($ резултат);

    Дали да се пазят стари записи за статистика или не е майсторска работа. Ако има нещо, те могат да бъдат изтрити чрез изпълнение на заявката преди оторизация:

    DELETE FROM unauth WHERE време за влизане

    При големи натоварвания такъв механизъм ще работи по-бързо и по-надеждно от файловете - в базата данни често използваните данни се буферират и обработват директно в RAM.

    Парола за страницата. Част 3. Парола от базата

    Веднъж имах проблем: трябва да затворя административната част на сайта, но в същото време не мога да поставя файла .htpasswd над главната директория на сайта. Вроденото подозрение не позволяваше поставяне на файл с парола и отделна директория и блокиране на достъпа до него чрез http. Реших да се опитам да направя защита като в phpMyAdmin: потребителят се пита за вход и парола, с които скриптът се свързва с базата данни. В моя лог анализатор направих точно това. Удобството на метода е, че файлът може да бъде поставен навсякъде - без бисквитки, без сървърни директиви за директорията. В същото време, ако паролата в базата данни се промени, няма нужда да коригирате нищо в скрипта.

    Ще опиша метода като използвам MySQL като пример. Нека напишем функция, например, mysql_die:

    Функция mysql_die () (заглавка ("HTTP / 1.0 401 Unauthorized"); заглавка ("WWW-автентикация: основна област = \" Статистика \ ""); print ("Достъпът е отказан. Изисква се потребителско име и парола."); Изход ();)

    В началото на програмата се посочват хостът на сървъра на базата данни и, ако е необходимо, името на базата данни:

    $ db_host = "localhost"; $ db_name = "някаква база данни";

    И за да се свържете с базата данни, се вземат променливите на сървъра: $ PHP_AUTH_USER и $ PHP_AUTH_PW.

    $ db_connect = @mysql_connect ($ db_host, $ PHP_AUH_USER, $ PHP_AUTH_PW) или mysql_die ();

    И това е всичко. Сега за недостатъците. Разбира се, с такава защита можете да опитате да отгатнете паролата (по принцип можете да прикачите заключване, но тогава цялата красота на метода ще бъде загубена). Паролата, както в случая със защитата на сървъра, се изпраща в чист текст. Но за прости задачи това ще свърши добре.

Парола за страницата. Част 4. Бисквитки

Този метод е приложим, когато, първо, има много потребители и техният контингент непрекъснато се променя. Второ, където трябва да направите удобно влизане - за да можете да влезете в системата, като въведете вашето потребителско име и парола във формата на страницата.

Начертаваме формуляр и правим файл, който получава потребителско име и парола (вече описах защитата от селекцията, добавете я тук сами).

// обработка на ред с вход$ login = str_repalce ("" "," ", $ login); $ login_result = mysql_query (" SELECT id FROM user WHERE login = "$ login" AND pass = "". md5 ($ pass). "" "); if (! mysql_error () && @mysql_num_rows ($ login_result) == 1) ( / * издаване на бисквитки. По-добре е да дефинирате имената и пътя на бисквитките в един файл за включване, за да избегнете объркване. * / setcookie ($ COOKIE_LOGIN_NAME, $ вход, време () + 3600, $ COOKIE_PATH); setcookie ($ COOKIE_PASSW_NAME, $ проход, време () + 3600, $ COOKIE_PATH); / * Веднага след влизане, потребителят се пренасочва към адрес, защитен с парола. * / header ("Местоположение: / някакъв път /"); изход; ) elseif (! mysql_error ()) ( / * показва съобщение за грешка и формуляр за повторно влизане * / print ("Грешно потребителско име или парола."); ) else print (mysql_error ());

Всички затворени страници извикват файл, който проверява правилността на получената парола от бисквитката:

$ login = str_repalce ("" "," ", $ HTTP_COOKIE_VARS [$ COOKIE_LOGIN_NAME]); $ login_result = mysql_query (" ИЗБЕРЕТЕ ИД ОТ потребител WHERE login = "$ login" И pass = "". md5 ($ HTTP_COOKIE_KOOP $ ]) . "" "); if (! mysql_error () && @mysql_num_rows ($ login_result)! = 1) ( / * Ако в таблицата няма такъв ред, потребителят се пренасочва към страницата за вход. * / header ("Местоположение: /login.php"); изход; ) else print (mysql_error ());

Имената на бисквитките ще се използват на няколко места, така че е по-добре да ги поставите на едно място предварително (например чрез деклариране на константи), за да не се налага по-късно да се коригират няколко пъти.

Както можете да видите, паролата ще премине през канала и ще бъде във файла с бисквитки в отворен, нешифрован вид. Това е много несигурно. При отсъствие на собственика можете да отидете на компютъра, да погледнете файла, където браузърът съхранява бисквитки, и да напишете паролата на лист хартия (и ако всичко е обичайно в локалната мрежа, тогава нямате нужда да се появи и можете да откраднете паролата точно пред собственика).

За да предотвратите това, паролата трябва да бъде кодирана. Приемлив вариант е хешът md5. Тук вече не можете да видите паролата и да влезете в системата, като я запишете на лист хартия или copy-paste-nouveau. Между другото, така можете да влезете в уеб интерфейси с парола и без знанието на приятел, които изграждат авторизация за сесии. Следователно последното нещо, което трябва да направите в тази посока, е да променяте бисквитката всеки път, когато страницата се зареди.

Самият аз веднъж направих такава схема: в таблицата на потребителите има колона с датата на последния достъп. Потребителят получава тази дата на последния достъп и паролата, кодирана чрез md5, при всяко повикване. Системата взема бисквитка с вход, изтегля този низ от базата данни, генерира хеш от полетата last_log и passwd и го сравнява с получения. Ако съвпадат, тогава посетителят може да бъде допуснат. За допълнителна сигурност можете да добавите проверка за изтичане на бисквитката - бисквитката трябва да изтече след половин час неактивност и съответно датата на последния лог в базата данни трябва да е преди по-малко от половин час.

$ login = str_repalce ("" "," ", $ HTTP_COOKIE_VARS [$ COOKIE_LOGIN_NAME]); $ login_result = mysql_query (" SELECT * FROM user WHERE login = "$ login" И last_log> DATE_SUB (СЕГА (), ИНТЕРВАЛ 30 МИНУТИ " ); if (! mysql_error () && @mysql_num_rows ($ login_result) == 1) ( / * Вземете ред в таблицата и генерирайте хеш от задължителните полета. * /$ current_user = mysql_fetch_array ($ login_result); $ hash_to_check = md5 ($ current_user ["passwd"]. "S - така че никой няма да познае". $ current_user); if ($ hash_to_check == $ HTTP_COOKIE_VARS [$ COOKIE_HASH_NAME]) ($ current_time = time (); / * Актуализиране на последното поле за вход и издаване на нова бисквитка. * / mysql_query ("UPDATE user SET last_log =" ". date (" Y-m-d H: i: s ", $ current_time)." "WHERE login =" $ login "); setcookie ($ COOKIE_HASH_NAME, md5 (дата ("Y-m-d H: i: s", $ current_time). "S - така че никой няма да познае". $ current_user ["passwd"]), $ current_time + 1800, $ COOKIE_PATH); ) друго ( / * Ако хешът не съвпада, потребителят се пренасочва към страницата за вход. * / header ("Местоположение: /login.php"); изход; ); ) elseif (! mysql_error () && @mysql_num_rows ($ log_result)! = 1) (заглавка ("Location: /login.php"); exit;) else print (mysql_error ());

Разбира се "Y - така че никой да не познае"по-добре е също да го разпределите в отделна променлива, но е по-добре да използвате ip-адреса на посетителя вместо този ред (или, за крайно комутиране, първите две/три числа на ip-адреса).

Между другото, относно IP адреса. По-добре е да го проверите, но не целия адрес, а само първите два (за ip, започващ с число по-малко от 127) или три (съответно повече от 127) адресни номера. Това ще спести потребителите на лош и счупен комутируем телефон от необходимостта да се оторизират отново след прекъсване на връзката и в същото време ще попречи на кракера, който е откраднал бисквитката, да влезе. Разбира се, той няма да може да се обади и да влезе през друг доставчик - адресът на басейна не е същият, но това не са наши проблеми („седят си вкъщи при такова време“). Точно както нашият проблем е кражбата на пароли в рамките на компанията. Защитили сме се от любопитни другари и неграмотни кракери, но не можем да направим нищо срещу троянци и снифери, които могат да бъдат доставени на жертвата.

На това "звънци и свирки" приключиха. По-надеждна защита вече не може да се направи. Никой няма да влезе във файла с бисквитки за хеш и да го вземе. Ще бъде по-лесно да поставите снифер между потребителя и уеб интерфейса и да го използвате, за да намерите паролата. Можете да поставите троянски кон, който ще запомни всичко, което потребителят е въвел на клавиатурата, но това вече не е наш проблем. За да се предпазите от подслушване на канала, трябва да използвате връзки като SSL или криптиране на данни.

Парола за страницата. Част 5. Сесии

Защо написах бележка за бисквитките? "Не разбирам защо се пише за бисквитки, когато има сесии в php?!" След това, така че читателите да нямат плоска картина пред очите си. Не навсякъде има php 4-та версия, а в третата те не се поддържат. Освен това сесиите не са толкова необходими навсякъде - с редки изключения, алгоритъмът за оторизация проверява правилността на данните за вход / паролата и коректността на данните за сесията и след това или изхвърля клиента към страницата за вход, или взема масив (или обект ) с потребителски данни.

Случаите, когато се налага работа в сесии, не са толкова чести. Например в моята игра „Монополист“ веднага започнах да използвам сесии, тъй като потребителят може да играе няколко игри и една и съща страница в една и съща сесия може да съдържа различни данни. Там е по-добре да съхранявате данни за една от игрите, в които потребителят участва в сесия и да направите страница за превключване между игри.

Като цяло не предполагам, че не е необходимо да използвате сесии. Необходимо е, само че всичко има своето място. Ще се върна към въпроса за приложимостта на трите метода за упълномощаване - през 401-вото заглавие („realm“), бисквитки или сесии по-късно. Сега да поговорим за сесиите.

Сесиите в php всъщност не са метод за оторизация (самата концепция е погрешна, но форумите питат точно "как да упълномощи потребител чрез сесии?"). Механизмът за потребителска сесия, вграден в php, идентифицира само тези потребители, оторизирането отново е работа на вашия скрипт.

Няма да говоря много за механизма на сесиите - вече беше казано. В най-простата си форма (или по-скоро в самия dafault) този механизъм работи по следния начин: системата поддържа файл на сесията на сървъра, който съдържа неговите променливи. Когато стартира сесия, потребителят получава уникален идентификатор (обикновено чрез бисквитка) и го изпраща при достъп до други страници. Когато стартира механизма на сесията във вашия скрипт, php манипулаторът проверява дали файлът съществува, съответстващ на получения идентификатор на сесия - ако съществува, скриптът ще може да чете данни от файла, ако не, ще бъде стартирана нова сесия и файлът ще бъде създаден. Разбира се, името на тази променлива се дефинира в настройките на php.

Сега за това какви функции използваме.

начало_на сесия ()... Стартира самия механизъм на сесията. Трябва да има променлива и съответен файл от потребителя. Ако няма файл, той се създава и сесията се стартира от нулата. Ако няма нито файл, нито променлива, тогава се генерира променлива (например се изпраща заглавка с бисквитка) и се създава файл.

регистър_сесия (име1, име2, име3 ...)... Индикация кои променливи да се запомнят във файла в края на скрипта. След като потребителят отиде на друга страница, механизмът на сесията може да бъде стартиран и след извикване на тази функция променливите ще бъдат налични.

session_destroy ()... Изтрива файла с данни за сесията (когато използвате бисквитки, трябва да ги изтриете ръчно, като зададете празна бисквитка: "setcookie (име на сесия ())").

session_set_cookie_params (живот, път, домейн)... Задаване на параметри на бисквитката с идентификатор на сесията (по подразбиране бисквитката е настроена на root сървъра и за 0 секунди - докато браузърът се затвори).

Това е всичко за сега. Ще има отделни въпроси за сесиите в детайли. Засега ще опиша механизма за оторизация и идентификация на потребителя с помощта на сесии.

И така, имаме три файла - login (login), check (auth) и logout (logout).

// изрязване на всички нежелани знаци$ login = preg_replace ("/ [^ \ w _ \. \ -] /", "", $ HTTP_POST_VARS ["вход"]); $ проход = отрязване ($ HTTP_POST_VARS ["проход"]); // проверка на променливите if (strlen ($ login) == 0 || strlen ($ pass) == 0) $ error = "Въведете вашето потребителско име и парола"; друго ( // проверка на входа и паролата$ user_result = mysql_query ("SELECT * FROM user WHERE login =" $ login "AND pass =" ". md5 ($ pass)." ""); / * ако е имало грешка в базата данни (например потребителят е вмъкнал дълга променлива в сесията, която базата данни не е искала да смила) или има повече от един ред, изхвърлете потребителя * / if (mysql_error ()) умре (mysql_error ()); elseif (@mysql_num_rows ($ user_result)! = 1) $ error = "Невалидно потребителско име или парола."; // ако всичко е наред, изберете данните, стартирайте сесията else ($ user = mysql_fetch_assoc ($ user_result); session_set_cookie_params (1800, "/"); session_start (); // запомня потребителските данни session_register ("потребител"); // и след това го изпратете някъде if (isset ($ HTTP_POST_VARS ["return"])) header ("Местоположение: ($ HTTP_POST_VARS [" return "])"); заглавка else ("Местоположение: /"); изход (); ); ); / * тук потребителят не е влязъл, но може да изпрати бисквитка от затворена сесия. нека го почистим. * / if (isset ($ HTTP_COOKIE_VARS)) setcookie (име на сесия ()); // начертайте формата по-нататък, не е интересно.

Този скрипт е едновременно манипулатор и форма за въвеждане на данни. След получаване на данните за вход и парола, той ги обработва и, ако са правилни, спира да работи, като изпраща потребителя на желаната страница. Ако данните са неправилни или изобщо липсват, рисува фигурата.

/ * убива потребителската променлива, така че да е невъзможно изпращането на данни в заявка за публикуване чрез изчертаване на формуляр. * / unset ($ user); // флаг "грешка в сесията" - ако е активиран, работата ще спре.$ session_error = false; // ако няма бисквитка с идентификатор на сесията, повдигнете флага if (! isset ($ HTTP_COOKIE_VARS)) $ session_error = true; // ако съществува, стартирайте механизма на сесията и регистрирайте потребителската променлива $. else (session_start (); session_register ("потребител"); / * ако случайно в масива няма потребителско име и парола, работата също спира ("ние не знаем нищо, ние ви ги дадохме") * / if (! isset ($ user ["login"]) ||! isset ($ user ["pass"])) $ session_error = true; ); / * ако потребителят досега героично е успявал да избегне грешки, проверка се извършва през базата по същия начин, както на входа. * / if (! $ session_error) ($ check_result = mysql_query ("ИЗБЕРЕТЕ uid ОТ потребител КЪДЕ влизане =" ($ потребител) "И преминете =" ($ потребител) ""); if (mysql_error () || @mysql_num_rows ($ user_result = 1) $ session_error = true;); // ако е имало някаква грешка, тогава if ($ session_error) ( // унищожаване на данните за сесиятасесия_унищожи (); // унищожи бисквитката, ако е била if (! isset ($ HTTP_COOKIE_VARS)) setcookie (име на сесия (), "", "/"); / * изпращане на потребителя да влезе, с възможност за връщане на искания адрес * / header ("Местоположение: /login.php?return=$REQUEST_URI"); // Спри да работишизход (); ); mysql_free_result ($ check_result);

Потребителят е проверен и в масива $ потребители - всички данни за него, можете например да го поздравите по име и отчество:

<? print ("Здравствуйте, {$user} {$user}!"); ?>

Ако (избор ($ HTTP_COOKIE_VARS)) ( // стартиране на механизма на сесиятаначало_на сесия (); // Изтрий файласесия_унищожи (); // изтриване на бисквитки setcookie (session_name ()); ); // излизане от страницата header ("Местоположение: /login.php");

Няколко бележки: защитената с парола част в този пример е целият сървър (например service.firm.ru), за да затворите директорията, трябва да коригирате пътищата. Вместо PHPSESSIDизползван от име на сесия ()така че можете свободно да променяте името на идентификатора. Между другото, на един и същ физически сървър можете да направите различни имена на идентификатори на сесиите - просто поставете файла .htaccess с реда php_value session.name "ABRACADABRA".




Ако имате още въпроси или нещо не е ясно - добре дошли при нас

Така че нашата задача е да зададем парола за достъп до определена страница. Нека започнем с най-примитивната, ако мога така да се изразя, защита - няколко реда на JavaScript:

Var pass = prompt ("Въведете паролата:", ""); if (pass == null) window.location = "wrong.html"; иначе if (pass.toLowerCase () == "wwvsfc") window.location = "temp.html"; else window.location = "wrong.html"; Трикове като скриване на скрипт в отделен файл с помощта на конструкцияфундаментално нищо не променя.

Подобна система, внедрена в Java:

Импортиране на java.applet. *; импортирайте java.awt. *; импортирайте java.net. *; public class Password разширява аплета (вход за текстово поле, парола; низ за влизане = "вход"; низ парола = "парола"; публична парола () () public void init () (панел панел = нов панел (); panel.setLayout (нов GridLayout (2,2)); вход = ново TextField (20); парола = ново TextField (20); panel.add (нов етикет ("Login:")); panel.add (вход); panel.add (нов Етикет ("Парола:")); panel.add (парола); добавяне (панел); добавяне (нов бутон ("Ok"));) публично булево действие (Event evt, Object obj) (if (evt.target instanceof Бутон) (String s; if (login.getText (). Equals (Вход) && password.getText (). Equals (Password)) (s = "http://www.hackzone.ru/articles/ok.html" ;) else (s = "http://www.hackzone.ru/articles/bad.html";) опитайте (getAppletContext (). showDocument (нов URL (s));) catch (Изключение e) (password.setText (e.toString ());) връща вярно;) връща false;))

Като включите този аплет в страница, можете да получите нещо подобно (всички следващи примери използват ok.html и bad.html):

Проверка на паролата

Може да се направи по-интелигентен, да се създаде отделна страница за всеки потребител, да се накара да чете данни от файл и т.н. Основният недостатък е, че след като човек е стигнал до страницата, която търси, никой не може да му попречи да запомни този URL, така че това е еднократен инструмент. Разбира се, можете да скриете страницата в рамка, така че URL адресът да не свети в адресната лента, но вие сами разбирате от кого е тази защита. Отново аплетът отива изцяло на клиента и по принцип е напълно достъпен за проучване.

Решението, базирано на използването на CGI, е лишено от последния недостатък. Прост скрипт на Perl изглежда така:

#! / usr / bin / perluse CGI qw (: стандартен); $ query = нов CGI; $ ok = "ok.html"; $ адрес = "bad.html"; $ login = "вход"; $ password = "парола"; $ l = $ query-> param ("вход"); $ p = $ query-> param ("парола"); if (($ p eq $ парола) && ($ l eq $ вход)) ($ адрес = $ ok;) print $ query-> redirect ($ адрес);

Пример за употреба:

За да се справите с първия недостатък, можете динамично да генерирате нова страница въз основа на това, което е скрито някъде вътре, без да издавате URL адреса.

Променен код:

#! / usr / bin / perluse CGI qw (: стандартен); $ query = нов CGI; $ ok = "ok.html"; $ address = "bad.html"; $ docroot = $ ENV ("DOCUMENT_ROOT"); $ localpath = "/ articles /"; $ login = "вход"; $ password = "парола"; $ l = $ query-> param ("вход"); $ p = $ query-> param ("парола"); if (($ p eq $ парола) && ($ l eq $ вход)) ($ адрес = $ ok;) print $ query-> header (); отворен (FL, $ docroot. $ localpath. $ адрес); докато ( ) (# Тук в същото време можете да променяте html-кода в движение # Защо? Е, никога не се знае... :) print $ _;) close (FL);

Пример за употреба:

Както можете да видите, URL адресът на файла вече не свети, макар и за сметка на SSI (все пак те могат да бъдат уловени в изхода и обработени ръчно). Но и тук остава теоретична възможност за отгатване на URL адреса , и не бива да се забравя, че всякакви картини, включени в страници - при използване на относителни пътища, разбира се.

И накрая, най-надеждният начин да зададете парола за достъп е да използвате сървърните инструменти - ненапразно хората ги направиха все пак. Ще се спра на две - Apache като най-популярен и IIS като популярен :)

С IIS всичко е доста просто - защитата се осъществява с помощта на NTFS, което, разбира се, донякъде ограничава възможностите на администраторите, които не са сървъри. Идеята е следната: за потребителя IUSR_xxxx, под чиято сметка всички посетители на сайта работят по подразбиране, достъпът до желания файл/директория е отказан. След това само тези потребители, за които това е изрично посочено в Properties-> Security, ще имат достъп до тези файлове. Ясно е, че е много по-удобно да ги комбинирате в групи. Тук има няколко тънкости. Първо, на посочените потребители трябва да бъде предоставено правото на локално влизане (Политики-> Права на потребителя в User Manager "e). Второ, ако не изберете услугата Основно удостоверяване (Изчистен текст) в настройките на WWW, само потребителите на Internet Explorer ще бъдат разрешено вътре.

Apache прави нещата малко по-различно. Защитата се поставя на ниво директория. Съответните директиви могат да бъдат поставени както в общия конфигурационен файл на php.ini, така и във файловете .htaccess. Наборът от директиви е един и същ и в двата случая и за повечето хора, които наемат място за сайт/страница на чужд сървър, първата опция не е налична. Така че създавате файл .htaccess в директорията, до която искате да ограничите достъпа, и след това вмъквате следните директиви в него:

AuthType вид контрол- Обикновено се използва Basic.

AuthName име- определя името на областта, в която са валидни потребителските имена и пароли. Това е името, което браузърът показва в диалоговия прозорец за въвеждане на парола. Като зададете едно такова име за различни директории, можете да спестите на потребителите време за въвеждане на допълнителна парола.

AuthGroupFile име- определя името на файла, който съхранява имената на групите и техните членове. Форматът му е:
група1: член1 член2 ...
група2: член3 член4 ...

AuthUserFile име- задава името на файла с парола. Като цяло, за да го генерирате, трябва да използвате помощната програма htpasswd от дистрибуцията на Apache. Но поне за някои версии на сървъра този формат е:
потребител 1: passwordhash1
потребител 2: passwordhash2

Passwordhash е доста достъпен със стандартна функция на Perl:
$ хеш = крипта ($ пас, $ сол);
където $ pass е паролата, $ salt е низ от два знака, използван за формиране на хеша.

Така че е напълно възможно да се автоматизира процеса на добавяне на нови потребители, промяна на пароли чрез html формуляри и т.н.

изисква потребител потребител1 потребител2и изискват група потребител1 потребител2ви позволяват да посочите кои потребители и групи ще имат достъп до дадена директория.

изискват валиден потребителпозволява достъп на всички потребители, посочени в системния файл с парола.

... къде метод идефинира HTTP метод. Например, ограничава използването на вложени в недирективи до случаите на използване на методите GET и POST (обикновено това е повече от достатъчно). Директивите Require, order, allow и deny могат да бъдат вложени.

Няколко други полезни директиви - забрани и разреши - съответно забрани и разреши достъп. Те се прилагат по следния начин:
отрича от всички
позволете от 192.168

По подразбиране първо се изпълнява всички откази, а след това всички разрешаване, така че разреши от всички ще разреши достъп на всички потребители, независимо от отказа. Редът може да бъде променен с директивата за поръчка: заповед разрешаване, отказ.

deny from all е идеално комбиниран с втория метод за защита на страници чрез CGI, именно с тази директива е най-добре да скриете всички пароли за книги за гости и т.н. При опит за достъп до страници от тази директория, потребителят ще получи съобщение за несъществуваща страница.

Между другото, тук, между времената, ние демонстрираме независима обработка на грешки: в този случай кодът 403, Забранено. Любимите на всички 404 – Not Found и 401 – Unauthorized се обработват по същия начин. За да направите това, просто добавете директивата към .htaccess ErrorDocument url код:
ErrorDocument 404 /cgi-bin/bad.pl
ErrorDocument 403 /cgi-bin/badaccess.pl
ErrorDocument 401 /cgi-bin/badaccess.pl

Всичко, което скриптът прави, е да генерира съобщение за грешка, използвайки променливата на средата REQUEST_URI, така че можете просто да посочите подходяща страница вместо това.

За последния пример, нека използваме файла .htaccess със следното съдържание:

AuthType BasicAuthName TestAuthGroupFile / my / local / path / tgroupAuthUserFile / my / local / path / tuser изискват групов тест

Във файла tgroup има само един ред - тест: тест за влизане, във файла tuser - криптирани пароли за влизане (парола) и тест (тест). Моля, имайте предвид, че при повторен достъп до тази страница браузърът разбира, че току-що е осъществил достъп до тази област и не притеснява потребителя с ненужно подканване на парола.

Накратко, това е минималният набор от информация, необходима за защита на уеб страниците. Както показва практиката, струва си повече или по-малко да се доверявате само на решения, базирани на средствата, предоставени от сървъра (и след това, докато се намери следващата дупка в сървъра), така че ако има възможност, по-добре е да ги изберете.


.

Една от основните аксиоми на информационната сигурност е, че „комфортът на една система е обратно пропорционален на нейната сигурност“. Това означава, че при избора на система за защита е необходимо да се намери оптималният баланс между сложността на защитата и удобството на потребителите.


От друга страна, разработването и прилагането на защитата изисква определени разходи на работна сила и ресурси. Следователно е необходимо разумно да се подходи към дизайна на защитата. Просто казано, няма нужда да създавате сложна и скъпа система за сигурност, ако на сайта не се съхранява нищо ценно. Никой натрапник няма да се опита да разбие вашата начална страница, сайт за визитки на малка компания или сайт на детска градина.


В предишния урок разгледахме оторизацията на уеб сървъра (Основна авторизация). Това е може би най-лесният и безопасен начин за ограничаване на достъпа до ресурси. Поддръжката на такъв механизъм обаче отнема доста време, особено при голям брой потребители с различни права. Освен това не всички сървъри позволяват HTTP удостоверяване.


По-популярна алтернатива е защитата с парола. Смисълът му е, че сървърът съхранява списъци с потребители и съответните им данни за влизане, пароли и права за достъп. При първия достъп до сайта потребителят въвежда потребителско име/парола и получава достъп до ресурси. Сървърът "запомня" потребителя и не иска парола, докато не се отвори следващата сесия (рестартиране на браузъра).

Организацията на защитата с парола е изцяло на плещите на програмиста. Отговорност на разработчика е да гарантира сигурността на съхраняване на потребителски списъци, проверка на влизания/пароли, запазване на контексти за сигурност и повторното им използване. Контекстът за сигурност тук се разбира като набор от параметри, които уникално дефинират потребител (поне това е потребителско име, парола и идентификатор на сесия).

Помислете за пример за прилагане на най-простата защита с парола. Нека създадем файл logon.php

Когато щракнете върху бутона "вход", данните от формуляра ще бъдат изпратени на сървъра, където скриптът ще провери въведените потребителско име и парола и ако са равни на "admin" и "megaPass", съответно, ще се покаже съобщение, че влизането е разрешено. Ако входът или паролата са неправилни, потребителят ще види предупредително съобщение.

Първият недостатък на този скрипт: прехвърляне на данни чрез метода GET. Когато използвате този метод, данните се предават директно в адреса, което означава, че са видими дори с просто око. Например, ако сте въвели правилното потребителско име и парола, тогава в адресната лента ще видите

Http: //localhost/logon.php? Login = admin & passwd = megaPass

Втори недостатък: потребителските имена и пароли са твърдо кодирани направо в кода. Това означава, че за да добавите нови потребители, ще трябва постоянно да променяте кода на файла. Представете си какъв размер ще бъде файлът, ако имате поне хиляда регистрирани потребители на вашия сайт... Списъците с потребители се съхраняват най-добре в отделен файл или по-добре в база данни. Много по-лесно е нападателят да открадне файл, отколкото да извлече нещо от база данни.

Третият недостатък: резултатите от влизането на потребителя не се запомнят, т.е. просто опреснете страницата и ще бъдете помолени да въведете паролата си отново.

Така че, нека да разгледаме начините за премахване на тези недостатъци.

Най-лесният начин да скриете предадените данни е да използвате метода за POST предаване. В този случай самият браузър (скрит от потребителя) ще предаде всички необходими данни на сървъра и ще бъде възможно да ги прихване само със специални програми от арсенала на ИТ специалисти, програмисти или хакери.

Както бе споменато по-горе, списъците с потребители трябва да се съхраняват отделно. Нека създадем таблица в тестовата база данни:

СЪЗДАВАНЕ НА ТАБЛИЦА `smplusers` (
`user_id` int (11) НЕ NULL auto_increment,
`user_name` varchar (50) НЕ NULL,
`user_login` varchar (50) НЕ NULL,
`user_password` varchar (50) НЕ NULL,
`reg_date` datetime NOT NULL,
ПЪРВИЧЕН КЛЮЧ (`user_id`)
)

и добавете някои потребителски записи към него:

ВМЕСЕТЕ В smplUsers
(user_name, user_login, user_password, reg_date)
стойности
("Иванов I.I.", "ivanov-i-i", "pass1", СЕГА ()),
("Петров П.П.", "петрович", "пас2", СЕГА ()),
("Sidorov S.S.", "sidorov", "pass3", СЕГА ())

Обърнете внимание, че операторът INSERT позволява множество записи да бъдат добавени към таблицата наведнъж, като данните са изброени в блокове, разделени със запетая.

Сега нека променим logon.php, така че потребителското име и паролата да се проверяват правилно директно в базата данни:

// свържете се с базата данни тук
// $ link - връзка към връзката
$ връзка = mysql_connect ("localhost", "db_user", "db_passwd");
mysql_select_db ("db_name", $ връзка);
?>

$ passwd = isset ($ _ POST ["passwd"])? $ _ POST ["passwd"]: "";
$ login = mysql_real_escape_string ($ вход);
$ passwd = mysql_real_escape_string ($ passwd);

Ако ($ вход! = "" || $ passwd! = "")
{
$ sql = "ИЗБЕРЕТЕ * ОТ smplUsers
WHERE user_login = "$ вход"
И user_password = "$ passwd"
LIMIT 1";
$ qry = mysql_query ($ sql, $ връзка);
ако ($ qry)
{
ако (mysql_num_rows ($ qry)> 0)
{
echo „Достъпът е предоставен
"." \ н ";

echo "Потребител:". $ ред ["user_name"];
}
друго
echo "Достъпът е отказан!";
}
}
друго
echo "Въведете вашето потребителско име и парола";
?>





Сега входът и паролата се предават тайно, а идентификационните данни са много лесни за промяна чрез редактиране на таблицата в базата данни. Остава последният щрих - да научите сървъра да помни факта на регистрация. Най-лесният начин да направите това е да използвате механизма на сесията. Нека направим необходимите промени:

начало_на сесия (); if (! $ _ SESSION ["user_id"]) $ _SESSION ["user_id"] = -1; // свържете се с базата данни тук ...
?>

$ login = isset ($ _ POST ["login"])? $ _ POST ["login"]: "";
...
ако (mysql_num_rows ($ qry)> 0)
{
echo „Достъпът е предоставен
"." \ н ";
$ ред = mysql_fetch_array ($ qry);
echo "Потребител:". $ ред ["user_name"]; $ _SESSION ["user_id"] = $ ред ["user_id"]; $ _SESSION ["user_name"] = $ ред ["user_name"];
}
...) иначе ехо "Здравей". $ _SESSION ["user_name"];
?>
...

Сървърът вече ще запомни всеки потребител, който е влязъл успешно, и следващия път, когато страницата се опресни, ще покаже съобщение за добре дошли.

Този скрипт е само пример за организацията на защита с парола, макар и доста функционален. Можете да направите практически ценна извадка от него, като добавите валидиране на входни данни, функции за криптиране, възстановяване на парола, прекратяване на сесията и т.н.

Реших да опиша начини за защита с парола на част от сайта. Темата всъщност е голяма, така че за първи път ще се огранича само с php + mysql авторизация.

Първият въпрос, който обикновено възниква, е как да затворите директорията с административни скриптове с парола. В същото време не са необходими излишни украшения - един или няколко администратора имат еднакви права, а личностите рядко се променят. Най-лесният начин в тази ситуация да използвате стандартна авторизация на сървъра е да поставите файловете .htaccess и .htpasswd и да запишете необходимите параметри в тях. Вече е писано много за това, така че няма да кажа нищо особено ново.

Ще добавя две неща. Първото е къде да поставите файла .htpasswd. Експериментално установих, че ако, например, пътят към документа със съобщението за грешка (ErrorDocument) е написан спрямо системната променлива DocumentRoot. Но пътят до файла с пароли (UserFile) се записва спрямо ServerRoot. Доколкото разбирам е невъзможно да се постави .htpasswd над ServerRoot - "../" не се възприема. Всичко това се прави, за да можете да поставите файл с пароли, например, едно ниво над главната директория на сайта, така че изобщо да няма достъп до файла от мрежата.

Второто е, че скриптът може да разбере кой го отваря и паролата: променливите $ PHP_AUTH_USER и $ PHP_AUTH_PW.

Основният недостатък на този метод е, че сървърът не може да блокира отгатването на парола (след няколко неуспешни опита за влизане, потребителят е помолен да изчака час или два и през това време заявките от неговия IP адрес се игнорират). Това е записано в официалната документация на Apache.

Друг недостатък е необходимостта от презаписване на файлове с пароли при изтриване на потребител или въвеждане на нов. Но ако това се случва рядко, този метод е напълно достатъчен, освен това не е нужно да се притеснявате да пишете механизъм за оторизация.

Автоматизация на авторизацията

Това е необходимо не само за опростяване на работата с голям брой потребители и техния голям "оборот". Ако трябва да съхранявате допълнителна информация за потребителите или имате нужда от гъвкаво разграничаване на правата, по-добре е да прехвърлите оторизацията към базата данни.

Всяка страница от затворената територия включва файл със следния код:

$ result = mysql_query ("SELECT * FROM person WHERE login =" ". preg_replace (" / [^ w _-] / "," ", $ PHP_AUTH_USER)." "И премине =" ". md5 ($ PHP_AUTH_PW). " ""); if (@mysql_num_rows ($ резултат)! = 1) (заглавка ("WWW-Удостоверяване: Основно царство =" Потребителска зона ""); заглавка ("HTTP / 1.0 401 Unauthorized"); print ("За да влезете в потребителската зона, трябва да въведете вашето потребителско име и парола. "); изход ();); $ user_row = mysql_fetch_array ($ резултат);

В първия ред всички знаци с изключение на букви, цифри, тирета и долни черти се премахват от входа. След това се проверява броят на получените линии и само ако е един ред, се дава достъп. В други случаи потребителят ще види прозорец в браузъра, предлагащ да въведете потребителско име и парола. Ако потребителят е влязъл успешно, имаме цялата информация за него в масива $ user_row.

Разбира се, примерът, който дадох, има редица съществени недостатъци. Не го преписвайте едно към едно, за да не станете жертва на опити за отгатване на парола, т.к.
1.няма защита срещу бране
2. ако потребителската таблица е голяма, нападателят най-вероятно ще "попълни" базата данни, когато познае паролата

И последният метод за днес е съхраняването на криптирани данни в бисквитки.

Има скрипт за влизане, останалите свързват кода, който ви позволява само да продължите действията в затворената зона - ако бисквитките изтекат или той излезе оттам, ще трябва да се върнете към страницата за вход.

Скриптът за влизане проверява потребителското име и паролата и издава две бисквитки. В първия има вход за незабавно идентифициране на потребителя (в базата данни полето за вход, разбира се, е уникално или дори ключово). Втората бисквитка съдържа хеша на времето за влизане и паролата (за пълнота на конспирацията добавям буквата "Y" към тези редове - тогава е почти невъзможно да се намери хеша :).

Всички други програми включват код, който прави следното. Прави заявка към базата данни - избира реда с полученото влизане. От този ред той взема полето "log_time" и паролата и прави хеширане от тях, както е описано по-горе. Сравнява го с полученото и ако съвпадат, издава нова хеш бисквитка отново от паролата, часа и буквата "Y" и прави заявка към базата данни "UPDATE user SET log_time = '...' WHERE login = '$ cookie_login'".

if (isset ($ HTTP_COOKIE_VARS [$ cookie_login]) && isset ($ HTTP_COOKIE_VARS [$ cookie_code])) ($ вход = $ HTTP_COOKIE_VARS [$ cookie_login]; $ код = $ HTTP_COOKIE_VARS [$ cookie_qcode]; $ резултат = mys "mys" date_format (log_date, "% Y% m% d% H% i% s") като log_date1, pass, uid ОТ потребител WHERE email = "$ login" И log_date> "DATE_SUB (СЕГА (), ИНТЕРВАЛ 15 МИНУТИ)" " ); if (! mysql_error () && @mysql_num_rows ($ резултат) == 1) ($ log_time0 = време (); $ log_time1 = дата ("YmdHis", $ log_time0); $ log_time2 = дата ("Ymd H: i : s ", $ log_time0); $ current_user = mysql_fetch_array ($ резултат); if (md5 ($ current_user [" pass "]. $ current_user [" log_date1 "]. $ md5letter) == $ код) (mysql_query (" АКТУАЛИЗИРАНЕ). потребител SET log_date = "$ log_time2" WHERE uid = ". $ current_user [" uid "]); setcookie ($ cookie_code, md5 ($ current_user [" pass "]. $ log_time1. $ md5letter), time () + 900, $ site_path); $ auth = true;) else unset ($ current_user);););

Отново няма защита срещу атаки с груба сила и атаки на сървъра (между другото, тук можете да напишете IP адреса на потребителя вместо буквата "Y" - така че, например, съсед от офиса да не може да вземе бисквитка файл и влезте от неговия компютър).

Парола за страницата. Част 2. Заключване

Когато пуснах този брой последния път, се спънах на място, казват, че с такова заключване можете и да "дерайлирате" сървъра.

Но първо, относно блокирането на селекцията. Бастилности, но все пак. Парола от десет знака от латински букви и цифри - има много опции. Ако се опитате да познаете парола с 1 000 000 вариации в секунда, това ще отнеме няколко хиляди години. Но тъй като подобни глупости са трудни за запомняне, често правим парола от смислени думи. Преди няколко години се оказа, че повечето пароли могат да се отгатнат с помощта на речник от 10 000 думи. По едно време в мрежата се появи червей (такъв вирус), който се катери на Unix сървъри, използвайки техните дупки в сигурността, и вдигна пароли на привилегировани потребители, използвайки ... системния правописен речник на Unix. Нямаше нужда да носите нищо!

Всеки потребител, докато не въведе правилното потребителско име и парола, се счита за злобен хакер. С какво се занимаваме, когато потребителят въведе нещо нередно?
забравяне (за това на прилични сайтове има формуляр "забравена парола", за да изпратите същата парола на имейла, въведен в системните настройки)
самоугаждане ("за нефиг")
избор на парола с помощта на речник (вероятността за успешна селекция е висока, поради което е необходимо да я затворите, особено ако сайтът е с търговски характер)
DoS атака (за да не се претовари сървъра, е необходимо да се сведат до минимум действията, които скриптът ще извърши в този случай)

От доста време си мисля как е възможно да се предизвика претоварване на сървъра, ако защитният механизъм е на файловете. Оказа се лесно (колко ще струва е друг въпрос). Така че, да кажем, че сървърът ще се провали, ако скриптът се опита да отвори файлове за писане 1000 пъти в секунда и да запише данни в тях. Тъй като след 5 неуспешни опита за влизане в системата, потребителят веднага ще получи отказ за достъп (без запис на данни във файла), е необходимо да се намерят 200 уникални IP адреса, от които пет пъти и да се приложи. Възможно е. Окачваме html банер с пет тагове в ротатора на банера:

Потребителят незабавно прави пет обаждания, сървърът пише във файла пет пъти (между другото, в някои браузъри може да се появи прозорец за въвеждане на потребителско име и парола). Можете да направите html страница с пет такива снимки и да вмъкнете самата страница през iframe в посетения сайт (чрез iframe - за да не се намери референтното поле. Малко вероятно е безплатната услуга за поддръжка на хостинг да направи такива неща като ровене в регистрационни файлове в търсене на реферали) ... Примерите, които дадох, разбира се, са разтегнати, но самият факт, че можете да се възползвате от такъв недостатък на системата, е доказан. Между другото, нещо подобно вече се е случило.

Но все пак ще дам този метод - писах напразно, или какво? Между другото, може да се използва без много страх за ограничен брой адреси (например за локалната мрежа на компания), като поставите в директорията файл .htaccess със следното съдържание:

заповед отказва, разрешава
отрича от всички
разреши от xxx.xxx.xxx

А ето и програмния код:

$ грешки = 0; $ fn = "игнориране /". preg_replace ("[^ d.]", "", $ REMOTE_ADDR. ".". $ HTTP_FORWARDED_FOR); if (is_file ($ fn)) (if (време на файла ($ fn)< time()-3600) unlink($fn); else $errors = fread(fopen($fn, "r"), 2); }; if ($errors>5) (печат ("Достъпът е отказан. Върнете се след час."); Изход ();); // тук се установява връзка със сървъра на базата данни. за да не го пипа напразно, ако потребителя веднага бъде "бит". $ result = mysql_query ("SELECT * FROM user WHERE login =" ". preg_replace (" / [^ w _-] / "," ", $ PHP_AUTH_USER)." "И преминете =" ". md5 ($ PHP_AUTH_PW). " ""); if (@mysql_num_rows ($ резултат)! = 1) (заглавка ("WWW-Удостоверяване: Основно царство =" тайна област ""); заглавка ("HTTP / 1.0 401 Unauthorized"); отпечатайте ("Изисква се упълномощаване"); fwrite (fopen ($ fn, "w"), ++ $ грешки); изход ();); $ current_user = mysql_fetch_array ($ резултат); mysql_free_result ($ резултат); Въпреки това е грях да се работи с файлове, ако има база данни. шега. За неуспешни оторизации създайте таблица: CREATE TABLE unauth (потребителско име VARCHAR (64) NOT NULL, подайте VARCHAR (64) NOT NULL, ip VARCHAR (255), време за влизане TIMESTAMP) И вместо да осъществяваме достъп до файлове, ние работим с базата данни. $ errors = @mysql_result (mysql_query ("SELECT count (username) as falses FROM unauth WHERE logintime> DATE_SUB (СЕГА (), ИНТЕРВАЛ 1 ЧАС) И ip =" $ REMOTE_ADDR ""), 0); if (mysql_error ()) умре (mysql_error ()); if ($ errors> 5) (отпечатайте ("Достъпът е отказан. Моля, върнете се след час."); изход ();); $ result = mysql_query ("SELECT * FROM user WHERE login =" ". preg_replace (" / [^ w _-] / "," ", $ PHP_AUTH_USER)." "И премине =" ". md5 ($ PHP_AUTH_PW). " ""); if (@mysql_num_rows ($ резултат)! = 1) (заглавка ("WWW-Удостоверяване: Основно царство =" тайна област ""); заглавка ("HTTP / 1.0 401 Unauthorized"); печат ("Изисква се упълномощаване"); mysql_query ("INSERT INTO unauth (потребителско име, пропуск, ip) VALUES (" $ PHP_AUTH_USER "," $ PHP_AUTH_PW "," $ REMOTE_ADDR $ HTTP_X_FORWARDED_FOR ")"); изход (); $ current_user = mysql_fetch_array ($ резултат); mysql_free_result ($ резултат);

Дали да се пазят стари записи за статистика или не е майсторска работа. Ако има нещо, те могат да бъдат изтрити чрез изпълнение на заявката преди оторизация:

DELETE FROM unauth WHERE време за влизане

При големи натоварвания такъв механизъм ще работи по-бързо и по-надеждно от файловете - в базата данни често използваните данни се буферират и обработват директно в RAM.

Парола за страницата. Част 3. Парола от базата

Веднъж имах проблем: трябва да затворя административната част на сайта, но в същото време не мога да поставя файла .htpasswd над главната директория на сайта. Вроденото подозрение не позволяваше поставяне на файл с парола и отделна директория и блокиране на достъпа до него чрез http. Реших да се опитам да направя защита като в phpMyAdmin: потребителят се пита за вход и парола, с които скриптът се свързва с базата данни. В моя лог анализатор направих точно това. Удобството на метода е, че файлът може да бъде поставен навсякъде - без бисквитки, без сървърни директиви за директорията. В същото време, ако паролата в базата данни се промени, няма нужда да коригирате нищо в скрипта.