Потребител може да достъпи страница на друг потребител

vinsbg

Registered
Здравейте,

сигурно е нещо супер "лесно" за оправяне, но забелязах, че когато един потребител се е логнал и директно в URL-то напише адрес до страница changepassword.php с друго ID на друг потребител и тя си се отваря и може да смени паролата на друг потребител.

След като потребител се логне си стартирам сесии и всичко, както трябва. Всеки потребител си има в профила 'Смяна на парола' и като го натисне му се отваря страница: changePassword.php?id=1

Ако обаче той ръчно напише в url-то changePassword.php?id=2,3 ... n ще отвори формата за смяна на парола на друг потребител.

Това имам на страница changePassword.php
Код:
<?php
include 'database.php';
	if(!empty($_SESSION['username'])) 
        {
              $pdo = Database::connect();
              if(isset($_GET['id']) && is_numeric($_GET['id'])){
                   $id = $_GET['id']; 
              { 
                      ....
              }
        }
        else 
        {
                 // редирект към логин формата
        }
в database.php накрая имам session_start()...

Навсякъде сесиите си работят нормално...
 
За мен е очевидно, не знам как ти убягва :wink:

Ти взимаш ид-то на юзера от $_GET. Защо? Нали имаш $_SESSION['username']? :)

$_SESSION e променлива, която сетваш сам.
$_GET е променлива, която идва от юзера.
 
anonimen каза:
За мен е очевидно, не знам как ти убягва :wink:

Ти взимаш ид-то на юзера от $_GET. Защо? Нали имаш $_SESSION['username']?
Бутона ми е:
<a href="passwordChange.php?id='.$_SESSION['id'].'">Смяна на парола</a>

т.е. Да не взимам юзър айди-то, а да си ползвам юзърнейма или?

edit:

Значи може така:
Код:
<a href="passwordChange.php?user='.$_SESSION['username'].'" >Смяна на парола</a>

и в changePassword.php
Код:
if(!empty($_SESSION['username'])) 
                {
        	  $pdo = Database::connect();                         
		            	$result = $pdo->prepare("SELECT *
		                      FROM users
		                      WHERE username = ? LIMIT 1");
                                        
	                    	$result -> bindParam(1, $_SESSION['username'], PDO::PARAM_INT);
				$result -> execute();
....

Така в урл-то получавам юзърнейма. Сега ако се опитам да отворя друг.. тоест да напиша ?user=test .. формата си стои на юзъра, който е логнат.

Това ли е правилния начин?
 
По-скоро:

PHP:
<a href="passwordChange.php" >Смяна на парола</a>

PHP:
$id = (int)$_SESSION['id'];
if($id)  { 
            $pdo = Database::connect();                          
            $result = $pdo->prepare("SELECT * FROM users WHERE id = ? LIMIT 1"); 
                                        
            $result -> bindParam(1, $id, PDO::PARAM_INT); 
            $result -> execute();
}
 
И двата начина работят коректно, доколкото мога да си го тествам. Въпроса е кой е по-правилния начин и по-сигурния от гледна точка юзърите да не могат да достъпят страницата и да сменят паролите на другите юзъри?
 
eLite каза:
По-скоро:

PHP:
<a href="passwordChange.php" >Смяна на парола</a>

PHP:
$id = (int)$_SESSION['id'];
if($id)  { 
            $pdo = Database::connect();                          
            $result = $pdo->prepare("SELECT * FROM users WHERE id = ? LIMIT 1"); 
                                        
            $result -> bindParam(1, $id, PDO::PARAM_INT); 
            $result -> execute();
}

това ползвай и ще се моля да не попадам в сайта ти :D някой да ми смени паролата :D
 
Тука въпроса не е какво ползваш, а в това да си сигурен че този който сменя паролата е същият потребител а не някой друг. Това е все едно да правиш проверката за логин. В много сайтове например те карат да набереш старата парола преди новата с цел сигурност. Дори в много сайтове такава опция изобщо не е налична и има само забравена парола, която се праща на мейла на регистрацията.
 
teroristd каза:
Тука въпроса не е какво ползваш, а в това да си сигурен че този който сменя паролата е същият потребител а не някой друг. Това е все едно да правиш проверката за логин. В много сайтове например те карат да набереш старата парола преди новата с цел сигурност. Дори в много сайтове такава опция изобщо не е налична и има само забравена парола, която се праща на мейла на регистрацията.
Да, така е.
Принципно формата изисква въвеждане на старата парола.
 
Напълно излишно е да казваш (ти, юзерът) на changePassword.php кой е юзера.
Грешка.
Напълно грешно е да казваш (ти, юзерът) на changePassword.php кой е юзера.
Дори:
Огромна дупка в сигурността е юзерът да има достъп до каквито и да е скриптове, свързани с четене и промяна на поверителна информация на други потребители (в случая в БД).

Никой няма право да променя каквато и да е парола, освен своята.

Ти (програмистът) си този, който ще каже на changePassword.php кой е юзера.

А единственото място, където юзерът удостоверява, че той е той, е там, където правиш
PHP:
$_SESSION['username'] = $res['username'];

Затова единственото място, откъдето можеш да вземеш информацията за юзера, е $_SESSION. Отникъде другаде.
Това е така, разбира се, когато потребителската система работи с вградените в php сесии. Ако си пишеш собствена система за сесии, които се запазват в БД, тогава там е сигурното място.

Това мисля че обяснява мнението на @стоянски. Ако системата ти работи по този начин, променям админската парола, влизам в админ-панела (ако има такъв :Д) и от там ясно какво става.

Off: 999 поста :Д
 
Взимаш ID-то от сесията, взимаш също ID-то от URL-а.
Проверяваш, дали ID-то в сесията отговаря на ID-то в URL-а... ако отговаря - да прави каквото иска, ако не отговаря - режеш.

eLite каза:
stoqnski каза:
това ползвай и ще се моля да не попадам в сайта ти :D някой да ми смени паролата :D

Поне обясни защо смяташ така. :)

Защото всеки, който е стартирал сесия и ID-то му е > 0 може да ти сменя паролата... само на потребители с ID <= 0 никой не може да им смени паролата (дори те самите).
 
Chance каза:
Защото всеки, който е стартирал сесия и ID-то му е > 0 може да ти сменя паролата... само на потребители с ID <= 0 никой не може да им смени паролата (дори те самите).

Имам два потребителя:

admin с id = 1
eLite с id = 2

В момента съм влезнал с eLite, демек: $_SESSION['id'] = 2;

С горния код, кое id ще бъде bind-нато? И чий user record ще върне?

Дори и да подадем username, каква е разликата? Имай в предвид, че не подавам id-то или username-а като GET параметър.

Естествено не вярвам, че това е най-удачния вариянт.
По-удачно би било да се изпраща имейл с уникален код / token.
 
На първо време не бива да се доверяваш на входните данни от потребител, когато става въпрос за критични моменти. Естествено трябва да вземеш новата парола от входа, но не бива да се осланяш например на някаква валидация от клиентска страна (допустми символи, дължина), а това да се върши от страната на сървъра. Тук критичното е ID-то на потребителя, което подаваш в GET/POST. Най-чистият вариант е да не подаваш въобще такъв параметър, а да работиш единствено със сесии и допълнителна проверка - съответствие със старата парала при смяна с нова. Естествено няма никакъв проблем да се подава параметъра, но той да не играе роля при определянето кой точно запис искаш да промениш. Частен случай се явява, когато привилегирован потребител иска да смени парола. Един вариант е да си подаваш всичко в сесията, а втори вариант е да отделиш администраторският панел в отделна страница, която да е защитена от случаен външен достъп.
 
Благодаря за хубавата дискусия.

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

В крайна сметка как е най-сигурно да го направя?

Както споменах при вход на юзъра запазвам в сесия:
Код:
	       $_SESSION['id'] = $id;
	       $_SESSION['username'] = $username;
В момента го направих, както предложи анонимен
бутона в профила на потребителя:
Код:
<a href="passwordChange.php?user='.$_SESSION['username'].'">Смяна на парола</a>
и съответно на страницата за смяна на парола:
Код:
		<?php
		if(!empty($_SESSION['username'])) 
                {
        	  $pdo = Database::connect();                         
			$result = $pdo->prepare("SELECT *
                            FROM users
                            WHERE username = ? LIMIT 1");
                                        
                        $result -> bindParam(1, $_SESSION['username'], PDO::PARAM_INT);
			$result -> execute();
                              // формата

Споменах и че потребителя трябва задължително да въведет и старата си парола.

Освен това при успешна смяна на паролата на e-mail на потребителя се получава съобщение, че паролата е сменена успешно и т.н. и че ако той не я е сменял има линк да си я ресетне.
( това разбирам, че не е кой знае какво, защото, докато потребителя види съобщението ... ще е късно :) )

Та в мен остава въпроса така дали е добре..?

п.п. сесия не пазя в базата данни.. и не е готова система..

п.п2.
lamerko каза:
.... а втори вариант е да отделиш администраторският панел в отделна страница, която да е защитена от случаен външен достъп.
Може ли малко разяснение тук? В момента админа се намира в друга папка, където са и всичките му файлове.. Принципно няма да се смесват с файловете/страниците на часта, която е за потребителите.
 
Добре, аз ще напиша changePassword?user=admin и ще пробвам различни пароли, докато не стане. :) Защо просто не ползваш $_SESSION['user'] в самия changePassword, защо с GET параметър?
 
djman каза:
Защо просто не ползваш $_SESSION['user'] в самия changePassword, защо с GET параметър?
Това не го разбрах?

Иначе, доколкото успях да го пробвам, какъвто и юзър да пишеш тук: changePassword?user=admin, формата винаги си е на твоя юзър заради сесията.. т.е. не се отваря друг юзър?
 
vinsbg каза:
djman каза:
Защо просто не ползваш $_SESSION['user'] в самия changePassword, защо с GET параметър?
Това не го разбрах?

Иначе, доколкото успях да го пробвам, какъвто и юзър да пишеш тук: changePassword?user=admin, формата винаги си е на твоя юзър заради сесията.. т.е. не се отваря друг юзър?

anonimen каза:
Напълно излишно е да казваш (ти, юзерът) на changePassword.php кой е юзера.
Грешка.
Напълно грешно е да казваш (ти, юзерът) на changePassword.php кой е юзера.
Дори:

Защо по дяволите трябва changePasword да приема каквито и да е аргументи?? :o :D :D

(в случая - аргументи == входни данни)

off// 1000 поста :Д
 
Т.е. се връщаме на това... без предаване на каквото и да е в бутона и с проверка на сесията в passwordChange.php ?
бутон
Код:
<a href="passwordChange.php">Смяна на парола</a>
Код:
<?php
      if(!empty($_SESSION['username'])) 
                {
             $pdo = Database::connect();                         
         $result = $pdo->prepare("SELECT *
                            FROM users
                            WHERE username = ? LIMIT 1");
                                        
                        $result -> bindParam(1, $_SESSION['username'], PDO::PARAM_INT);
         $result -> execute();
                              // формата
 
Това имах предвид още в първия си пост :?:
Само да вметна, че аз бих го направил да работи по ид, а не по юзърнейм. Не че второто е грешно, но там търсиш по стринг, а иначе по число.
 

Back
Горе