Drukowana wersja tematu

Kliknij tu, aby zobaczyć temat w orginalnym formacie

Forum PHP.pl _ Przedszkole _ [PHP]AJAX logowanie

Napisany przez: casperii 7.10.2018, 10:56:46

Witam.
postanowiłem napisać logowanie opartym o jquery i teraz się zastanawiam czy to będzie dobry pomysł pod względem bezpieczeństwa.

php:

  1. /*Funkcja zapisująca ciasteczka */
  2. function docookie($setuid, $setusername) {
  3. $info = http://www.php.net/base64_encode("$setuid:$setusername");
  4. http://www.php.net/setcookie("user","$info",http://www.php.net/time()+3600);
  5. return $info;
  6. }
  7.  
  8.  
  9. $user = $_GET['Username'];
  10. $password = http://www.php.net/trim($_GET['Password']);
  11.  
  12. $query = $pdo->prepare("SELECT `user`, `password`, `pass_pass`, `id_user` FROM `users` WHERE `user` = :user AND `password` = :password LIMIT 1");
  13. $query->bindValue(':user', $user, PDO::PARAM_STR);
  14. $query->bindValue(':password', SafePassword($password), PDO::PARAM_STR);
  15.  
  16. $query->execute();
  17. $fetch = $query->fetch();
  18.  
  19. if(http://www.php.net/empty($user)){
  20. $status = "error";
  21. $message = "".LANG_AJAX_LOGIN_NIEPODANO.".";
  22. }elseif(!http://www.php.net/is_array($fetch)){
  23. $status = "error";
  24. $message = ''.LANG_AJAX_LOGIN_NIEMA.'.';
  25. }elseif(http://www.php.net/empty($password)){
  26. $status = "error";
  27. $message = "".LANG_AJAX_HASLO_NIEPODANO.".";
  28. }else{
  29.  
  30. http://www.php.net/mt_srand ((double)http://www.php.net/microtime()*1000000);
  31. $maxran = 1000000;
  32. $random_num = http://www.php.net/mt_rand(0, $maxran);
  33.  
  34.  
  35. $datekey = http://www.php.net/date("F j");
  36. $rcode = http://www.php.net/hexdec(http://www.php.net/md5($_SERVER['HTTP_USER_AGENT'] . $random_num . $datekey));
  37. $code = http://www.php.net/substr($rcode, 2, 6);
  38.  
  39. docookie($fetch['id_user'], $user);
  40.  
  41. $status = "success";
  42. $message = 'Zalogowano poprawnie.'.$code;
  43. }


JS:

  1. var SignIn = function() {
  2. $('#LoginButton,#LoginButtonTop').on('click', function (){
  3. var form = $('#login').serialize(),
  4. responseMsg = $('#messageLogin,#messageLoginTop');
  5. responseMsg.hide().addClass('response-waiting').text('czekaj...').fadeIn(200);
  6.  
  7. $.ajax({
  8. type: 'GET',
  9. url: "/ajax.php?p=login",
  10. data: form,
  11. processData: false,
  12. contentType: false,
  13. success: function(data){
  14. var responseData = jQuery.parseJSON(data),
  15. klass = '';
  16. switch(responseData.status){
  17. case 'error':
  18. klass = 'response-error';
  19. break;
  20.  
  21. case 'success':
  22. klass = 'response-success';
  23. break;
  24. }
  25.  
  26. responseMsg.fadeOut(200,function(){
  27. $(this).removeClass('response-waiting').addClass(klass).html(responseData.message).fadeIn(200,function(){
  28.  
  29. if(responseData.status == 'error'){
  30. setTimeout(function(){
  31. responseMsg.fadeOut(200,function(){
  32. $(this).removeClass(klass);
  33. });
  34. },3000);
  35.  
  36. }else { setTimeout('go_to_private_page()', 3000); }
  37.  
  38.  
  39. });
  40. });
  41. }
  42. });
  43. return false;
  44. });
  45. }

Napisany przez: viking 7.10.2018, 11:37:20

Czemu nie używasz password_hash i verify dla haseł?

Napisany przez: casperii 7.10.2018, 11:52:55

Po to tu napisałem by otrzymać pomoc smile.gif
Jak już wspomniałeś o:
password_hash i verify

możesz coś więcej nadmienić jak to powinno wyglądać ? hashuje hasło w jquery i przesyłaniu do php i tam je odkodowuje ? czy o co chodzi ?

Napisany przez: viking 7.10.2018, 11:57:58

Zobacz w dokumentacji. Do jquery i kodu js dostęp ma każdy więc to by była jedna z głupszych rzeczy.

Napisany przez: casperii 7.10.2018, 12:07:40

wcześniej kodowane hasło miałem za pomocą:

  1. function SafePassword($password) {
  2. return openssl_digest($password, 'sha512');
  3. }
  4. $query->bindValue(':password', SafePassword($password), PDO::PARAM_STR);


dobra kumam, trzeba iść z biegiem wyższego Php'a:
  1. $passwordPlain = 'pass123';
  2. $passwordHash = password_hash($passwordPlain, PASSWORD_BCRYPT);
  3. password_verify($passwordPlain, $passwordHash);


czyli:
  1. function SafePassword($password, $passwordTwo) {
  2. return password_verify($password, $passwordTwo);
  3. }


a przy zapisie / rejestracji usera
  1. password_hash($password, PASSWORD_BCRYPT);


czyli reasumując user wpisuje swój login muszę najpierw zwrócić hasło by później je wstawić do funkcji i porównać czy jest true czy false ?

Napisany przez: viking 7.10.2018, 12:14:59

Od 7.2 algorytmem jest argon2i. Funkcja safepassword w tym wypadku nic nie robi.

Napisany przez: casperii 7.10.2018, 12:32:37

nie bardzo wiem jak to teraz ugryźć, bo przy zapisie do bazy:

  1. function SafePassword($password) {
  2. return password_hash($password);
  3. }
  4.  
  5. $AddUser->bindValue(':password', SafePassword($password), PDO::PARAM_STR);


tak przy porównywaniu już na etapie bindowania mam te hasło porównywać czy najpierw te hasło wprowadzone hasło przelecieć raz jeszcze function SafePasswrod?smile.gif

a później w warunku sprawdzić ?

  1. if(http://www.php.net/empty($user)){
  2. $status = "error";
  3. $message = "".LANG_AJAX_LOGIN_NIEPODANO.".";
  4. }elseif(!http://www.php.net/is_array($fetch)){
  5. $status = "error";
  6. $message = ''.LANG_AJAX_LOGIN_NIEMA.'';
  7. }elseif(http://www.php.net/empty($password)){
  8. $status = "error";
  9. $message = "".LANG_AJAX_HASLO_NIEPODANO.".";
  10. }else{
  11. http://www.php.net/echo ' zalogowano';
  12.  
  13. }



Napisany przez: viking 7.10.2018, 12:39:28

Przy zapisie do bazy hash a potem wyciągasz użytkownika na podstawie loginu i porównujesz verify hasło podane z hashem.

Napisany przez: casperii 7.10.2018, 12:41:02

oł patrz na to: Call to undefined function password_hash()

a tu zonk:
PHP Version 5.3.29
a w/w działa od 5.5

Napisany przez: viking 7.10.2018, 13:22:02

No to najwyższa pora zmienić hosting bo nawet na takim starociu nie ma powodu żeby rozmawiać o "bezpieczeństwie". Od lat nie ma wsparcia ani łat.

Napisany przez: woxala123 7.10.2018, 18:00:37

https://stackoverflow.com/questions/14612551/mysql-remote-connection-fails-with-unknown-authentication-method

Napisany przez: casperii 7.10.2018, 23:26:42

@woxala123 tak na przyszłość nie podawaj linków , które nic nie wnoszą , tym bardziej u kogoś kto potrzebuje pomocy.
Temat z błędem mysql rozwiązany, wystarczyło usunąć usera i utworzyć ponownie oraz połączyć go z bazą danych.

ostateczny php:

  1. $query = $pdo->prepare("SELECT `user`, `password`, `pass_pass`, `id_user` FROM `users` WHERE `user` = :user LIMIT 1");
  2. $query->bindValue(':user', $user, PDO::PARAM_STR);
  3.  
  4. $query->execute();
  5. $row = $query->fetch(PDO::FETCH_ASSOC);
  6.  
  7. if(http://www.php.net/empty($user)){
  8. $status = "error";
  9. $message = "".LANG_AJAX_LOGIN_NIEPODANO.".";
  10. }elseif(http://www.php.net/empty($password)){
  11. $status = "error";
  12. $message = "".LANG_AJAX_HASLO_NIEPODANO.".";
  13. }elseif($row){
  14. if(password_verify($password,$row['password'])){
  15.  
  16. http://www.php.net/mt_srand ((double)http://www.php.net/microtime()*1000000);
  17. $maxran = 1000000;
  18. $random_num = http://www.php.net/mt_rand(0, $maxran);
  19.  
  20. $datekey = http://www.php.net/date("F j");
  21. $rcode = http://www.php.net/hexdec(http://www.php.net/md5($_SERVER['HTTP_USER_AGENT'] . $random_num . $sitekey . $datekey));
  22. $code = http://www.php.net/substr($rcode, 2, 6);
  23.  
  24. $status = "success";
  25. $message = 'Zalogowano poprawnie.'.$code;
  26. }else{
  27. $status = "error";
  28. $message = ''.LANG_AJAX_LOGIN_NIEMA.'';
  29. }
  30.  
  31. }


teraz pytanie co powinienem przekazać do jquery żeby zalogować i żeby nie można było tego wyłudzić ?
wymyśliłem sobie, że tworząc $code będzie można go przekazać i w jquery sprawdzać jego poprawność ale nie wiem czy to nie przekombinowane ?

Napisany przez: nospor 8.10.2018, 09:56:16

Nie bardzo rozumiem po co chcesz jakies info przekazywac do jQuery? Zalogowanie zrobiles w php i user jest zalogowany. Co ma ci ktos wyludzac w jquery?

Napisany przez: borabora 8.10.2018, 10:22:11

na froncie powinieneś mieć coś takiego

  1. success: function (response) {
  2. // jak wyślesz kod odpowiedzi 200 to się wykona ten blok
  3. // po pytaniach wątpię, że robisz SPA, dlatego możesz zrobić refresh dla strony i wyświetli się widok dla zalogowanego
  4. },
  5. error: function (xhr, ajaxOptions, thrownError) {
  6. // w przypadku errorów walidacji wysyłaj kod 400,
  7. // wtedy wykona się zawartość tej funkcji
  8. // mozesz rozróżnic kod odpowiedzi, w przypadku 500 pokazuj inną informację
  9. }

Napisany przez: viking 8.10.2018, 11:04:38

Kod
Deprecation Notice: The jqXHR.success(), jqXHR.error(), and jqXHR.complete() callbacks are removed as of jQuery 3.0. You can use jqXHR.done(), jqXHR.fail(), and jqXHR.always() instead.

Napisany przez: casperii 8.10.2018, 20:35:23

@borabora , @viking a to nie jest tak , że success() , error() zostało zastąpione done() , fail()
@borabora możesz wyjaśnić o co chodziło czy robię "SPA" ?

Napisany przez: borabora 9.10.2018, 15:07:55

SPA - single page application. Czyli "cały" front ładuje się raz, a następnie po logowaniu dostajesz obiekt (token, nick, avatar...). Wtedy zmieniasz stan z wylogowanego na zalogowany. Dłuższy temat...

Napisany przez: casperii 10.10.2018, 20:12:46

No dobra czyli w efekcie końcowym ma być tak:

  1. var SignIn = function() {
  2. $('#LoginButton,#LoginButtonTop').on('click', function (){
  3. var form = $('#login').serialize(),
  4. responseMsg = $('#messageLogin,#messageLoginTop');
  5. responseMsg.hide().addClass('response-waiting').text('czekaj...').fadeIn(200);
  6.  
  7. $.ajax({
  8. type: 'GET',
  9. url: "/ajax.php?p=login",
  10. data: form,
  11. processData: false,
  12. contentType: false,
  13.  
  14. success: function(data, textStatus, jQxhr) {
  15. var responseData = jQuery.parseJSON(data),
  16. klass = '';
  17. switch(responseData.status){
  18. case 'error':
  19. klass = 'response-error';
  20. break;
  21.  
  22. case 'success':
  23. klass = 'response-success';
  24. break;
  25. }
  26.  
  27. responseMsg.fadeOut(200,function(){
  28. $(this).removeClass('response-waiting').addClass(klass).html(responseData.message).fadeIn(200,function(){
  29.  
  30. if(responseData.status == 'error'){
  31. setTimeout(function(){
  32. responseMsg.fadeOut(200,function(){
  33. $(this).removeClass(klass);
  34. });
  35. },3000);
  36.  
  37. }
  38.  
  39. if(responseData.status == 'success'){
  40. var url4 = window.location.href;
  41. setTimeout(function() {
  42. window.location.reload(url4);
  43. location.reload(true);
  44. }, 1000); /*automatyczne odświeżenie strony */
  45. }
  46.  
  47. });
  48. });
  49.  
  50. },
  51. complete: function() {
  52. //ten fragment wykona się po zakończeniu łączenia - nie ważne czy wystąpił błąd, czy sukces
  53. },
  54. error: function(jqXHR, errorText, errorThrown) {
  55. console.log( errorThrown );
  56. }
  57. });
  58.  
  59. return false;
  60.  
  61. });
  62. }


ktoś rzucił by fachowym okiem i wyeliminował nie potrzebne fragmenty ? smile.gif

Napisany przez: nospor 10.10.2018, 20:50:44

Z takich pierdow ale az klujacych w oczy

nie: klass
a: class

Nie: SignIn
a: signIn - trzymaj sie jednej konwencji a nie wolna amerykanka

No i czemu jak jest blad to pojazujesz go dopiero po 3 sekundach? Po co bez sensu zwlekac?
No i czemu jak jest ok to przekierowujesz dopiero po jednej sekundzie? przeciez nie robisz nic w miedzyczasie. I znowu pytanie: po co wiec zwlekac?

Napisany przez: viking 11.10.2018, 06:42:43

I nie zastosowałeś done/fail tylko usunięte succes/error. Dodatkowo bezsensowne przetwarzanie success switchem zamiast wysłanie odpowiedniego błędu. Dlaczego contentType: false?
https://prophp.pl/advice/show/17/jak_przygotowac_php_do_obslugi_zadan_xhr_json%3F

Napisany przez: casperii 11.10.2018, 19:28:30

@nospor SignIn poprawiony na signIn smile.gif

to:

  1.  
  2. if(responseData.status == 'error'){
  3. setTimeout(function(){
  4. responseMsg.fadeOut(200,function(){
  5. $(this).removeClass(klass);
  6. });
  7. },3000);
  8.  
  9. }


nie powoduje opóźnienia wyświetlenia błędu tylko usunięcie klasy z informacją o błędzie.
podobnie jest z chwilą success - wyświetlam informację o poprawnym zalogowaniu i przeładowuje stronę.

klass gdy zmienię na class to wywala błąd smile.gif

Napisany przez: nospor 11.10.2018, 19:51:09

To nazwij to np. messageClass tylko na jadro linuksa nie spolszaczaj tego w ten sposob tongue.gif

Napisany przez: casperii 14.10.2018, 20:06:22

@viking fail() / done() jest w nowszej wersji jQuery , nie chce teraz ruszać strony by się nie posypała smile.gif
@nospor usunąłem switcha i (c/k)lass smile.gif

czy teraz wygląda Panowie kod optymalnie , nie czepiając się oczywiście nowego jQuery.

obecny JS wygląda tak:

  1. var signIn = function() {
  2. $('#LoginButton,#LoginButtonTop').on('click', function (){
  3. var form = $('#login').serialize(),
  4. responseMsg = $('#messageLogin,#messageLoginTop');
  5. responseMsg.hide().addClass('response-waiting').text('czekaj...').fadeIn(200);
  6.  
  7. $.ajax({
  8. type: 'GET',
  9. url: "/ajax.php?p=login",
  10. data: form,
  11. dataType: 'json',
  12.  
  13. success: function(data, textStatus, jQxhr) {
  14. responseMsg.fadeOut(200,function(){
  15. $(this).removeClass('response-waiting').addClass('response-success').html(data.message).fadeIn(200,function(){
  16. var url4 = window.location.href;
  17. setTimeout(function() {
  18. window.location.reload(url4);
  19. location.reload(true);
  20. }, 1000); /*automatyczne odświeżenie strony */
  21. });
  22. });
  23. },
  24. complete: function() {
  25. //ten fragment wykona się po zakończeniu łączenia - nie ważne czy wystąpił błąd, czy sukces
  26. },
  27. error: function(jqXHR, errorText, errorThrown) {
  28. console.log( errorThrown );
  29.  
  30. responseMsg.fadeOut(200,function(){
  31. $(this).removeClass('response-waiting').addClass('response-error').html(jqXHR.responseJSON.message).fadeIn(200,function(){
  32.  
  33. setTimeout(function(){
  34. responseMsg.fadeOut(200,function(){
  35. $(this).removeClass('response-error');
  36. });
  37. },3000);
  38. });
  39. });
  40.  
  41.  
  42. }
  43. });
  44. return false;
  45. });
  46. }


Panowie jeśli treść do jQuery z php wysyłam w ten sposób:
  1. http://www.php.net/echo json_encode(['message' => 'wiadomość przekaż']);
  2. return;


to jak powinno wyglądać poprawnie w samym jQuery odebranie tego i wstawienie do diva ?

  1. .fail(function(jqXHR, errorText, errorThrown) {
  2. console.log( errorThrown );
  3. $(this).html(jqXHR.responseJSON.message);
  4. });
  5. return false;


niby dla powyższego działa, ale wydaje mi się, że nie jest to poprawnie, ponieważ w przypadku gdy wykona się done() to wówczas wywala bład z message
No i jak powinno zostać przekazane info z php do diva w przypadku done ?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)