Controleer of post van mijn pagina af komt

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Pagina: 1 2 volgende »

Danny von Gaal

Danny von Gaal

20/08/2015 12:04:31
Quote Anchor link
Ik stuurde een $_POST van een formulier altijd naar dezelfde pagina en dan ving ik het bovenaan mijn script af.
Alleen doordat je dan dubbele posts kan krijgen door per ongeluk de pagina te verversen wil ik nu mijn formulier waardes doorsturen naar login2.php en dan laten inloggen.

Alleen hoe weet ik dat die gene van mijn loginpagina komt? Is het slim om een hidden $_POST mee te sturen? Maar dat kan weer onderschept worden lees ik?
Hoe pakken jullie dat aan?
 
PHP hulp

PHP hulp

05/05/2024 20:28:01
 
- Ariën  -
Beheerder

- Ariën -

20/08/2015 12:23:31
Quote Anchor link
Maak een sessie aan op de plek van je formulier, met een md5() hash. En plaats deze ook in een hidden-field.
Controleer op de vervolgpagina of deze overeenkomen. Zo niet, dan is er sprake van een 'CSRF-attack', waarbij iemand de pagina oproept via een illegale manier dan er verwacht wordt.
 
Thomas van den Heuvel

Thomas van den Heuvel

20/08/2015 12:58:20
Quote Anchor link
Wat Aar zegt (token) + dit.

Stel je hebt form.php

Deze post je naar process.php

succes? > success.php
fail? > form.php?errors=1

Dit zou je ook kunnen reduceren tot één script als je deze netjes in acties opdeelt:

form.php (default actie, toon formulier eventueel met fouten/hints/eerdere invoer als ?errors=1)
form.php?action=process (verwerk-actie)
form.php?action=complete (boodschap tonen na verwerken, of je stuurt iemand gelijk ergens anders naartoe en toon je nog ergens dat alles is opgeslagen met een sessie-flash-message ofzo)
 
Danny von Gaal

Danny von Gaal

20/08/2015 13:56:18
Quote Anchor link
Bedankt, ik zal die sessie aanmaken en verifiëren.
Wat wel jammer is dat ik gebruikers meldingen zoals "geen gebruikersnaam ingevuld" niet automatisch kan checken.
Ik moet dit terug sturen met een GET is dat niet wat slordig?
 
Randy vsf

Randy vsf

20/08/2015 14:04:27
Quote Anchor link
Dat kan je afvangen met HTML5. het required atribute kan je toevoegen aan je input.
dan werkt de submit knop niet zolang dat veld niet is ingevuld.
Gewijzigd op 20/08/2015 14:05:53 door Randy vsf
 
Thomas van den Heuvel

Thomas van den Heuvel

20/08/2015 14:26:25
Quote Anchor link
@Danny zie mijn PB.
 
- Ariën  -
Beheerder

- Ariën -

20/08/2015 14:32:25
Quote Anchor link
Je kan prima dergelijke validaties voor gebruikersnamen toevoegen. Je zou dit met Javascript kunnen doen (jQuery validator), via HTML5 wat ietwat beperkt is, en zelfs via AJAX als je interactie moet leggen met je database of een waarde al bestaat.

Zog altijd voor:
Client-side controles, en bij voorkeur met HTML5, dan met JavaScript en dan nog eens serverside.
 
Danny von Gaal

Danny von Gaal

20/08/2015 14:48:29
Quote Anchor link
Ik weet dat dit via andere talen netter afgevangen kan worden. Ik zelf gebruik altijd JQUERY voor dit soort dingen maar als onderlaag doe ik het altijd eerst via PHP mocht iemand javascript uit hebben staan of de library is op een of andere manier onbereikbaar.

Ik zal dus de GET gebruiken voor PHP maar eerst met JQUERY het veld op laten lichten.
 
Ramon van Dongen

Ramon van Dongen

20/08/2015 14:49:17
Quote Anchor link
Mij lijkt het makkelijkste om op één pagina het formulier te hebben en op die pagina ook de verwerking van het formulier. Is er iets fout, laat je foutmeldingen zien op die pagina (met het formulier nog ingevuld). Is alles goed, DAN PAS stuur je de bezoeker door naar een andere pagina.

Quote:
Alleen doordat je dan dubbele posts kan krijgen door per ongeluk de pagina te verversen

Daar zit eigenlijk je probleem, niet in het doorsturen naar een andere pagina.

Dus als je dat afvangt, is het opgelost.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

if($_SERVER['REQUEST_METHOD'] == 'POST'){

    // foutcontrole


    if(geen fouten){

    // verwerking formulier
    
    header('Location: /nieuwepagina');
    exit;
    }



}
 
Danny von Gaal

Danny von Gaal

20/08/2015 15:16:09
Quote Anchor link
Dat is ook wel slim Ramon, bedankt.
 
- Ariën  -
Beheerder

- Ariën -

20/08/2015 15:20:41
Quote Anchor link
Klopt, zo vernietig je de POST-request na het correct versturen, maar het voorkomt niet dat anderen de pagina alsnog op een externe wijze kunnen aanroepen.
 
Danny von Gaal

Danny von Gaal

20/08/2015 15:39:44
Quote Anchor link
@ -Aar-: Zal ik die md5 sessie op basis van $_SERVER['REMOTE_ADDR'] maken?
is dat slim?
 
- Ariën  -
Beheerder

- Ariën -

20/08/2015 15:45:21
Quote Anchor link
Ik zou het niet doen, omdat een IP-adres meerdere gebruikers kan bevatten. Liever uniqid() ofzo.
Gewijzigd op 20/08/2015 17:49:10 door - Ariën -
 
Danny von Gaal

Danny von Gaal

20/08/2015 16:33:37
Quote Anchor link
- Aar - op 20/08/2015 15:45:21:
Ik zou het niet doen, omdat een IP-adres niet uniek is. Liever uniqid() ofzo.


Maar ik zie op php.net dat deze functie een id maakt op basis van de current-time in microseconds. Dat kan ik op de pagina er na toch niet meer verifieren omdat de microsecondes dan al gewijzigd zijn?
 
Frank Nietbelangrijk

Frank Nietbelangrijk

20/08/2015 16:43:40
Quote Anchor link
Wel als je dezelfde waarde bewaard in je sessie. Bovendien kun je tevens een timeout maken .
 
- Ariën  -
Beheerder

- Ariën -

20/08/2015 16:46:11
Quote Anchor link
Danny von Gaal op 20/08/2015 16:33:37:
- Aar - op 20/08/2015 15:45:21:
Ik zou het niet doen, omdat een IP-adres niet uniek is. Liever uniqid() ofzo.


Maar ik zie op php.net dat deze functie een id maakt op basis van de current-time in microseconds. Dat kan ik op de pagina er na toch niet meer verifieren omdat de microsecondes dan al gewijzigd zijn?

Je slaat die waarde op in een sessie, dus dan kan je het prima later nog vergelijken.
 
- SanThe -

- SanThe -

20/08/2015 17:14:42
Quote Anchor link
- Aar - op 20/08/2015 15:45:21:
Ik zou het niet doen, omdat een IP-adres niet uniek is.


Een ip-adres is wel uniek.
Wat jij bedoelt is dat je er niet van op aan kunt omdat het kan veranderen. (mobiel b.v.)
 
- Ariën  -
Beheerder

- Ariën -

20/08/2015 17:51:04
Quote Anchor link
Ja, dat bedoelde ik. Maar er kunnen meerdere gebruikers op zitten, en deze kan veelvuldig wijzigen op een mobiel netwerk. Wel weet ik dat dat gebeurt als je dataverbinding langdurig wegvalt.
 
Danny von Gaal

Danny von Gaal

21/08/2015 14:36:13
Quote Anchor link
Nou ik heb wat gemaakt en ben benieuwd of jullie nog aanmerkingen hebben.

Bovenaan mijn loginpagina maak ik een md5 hash aan op basis van ip-adres. (Sorry -Aar- maar die uniqueid begreep ik niet helemaal en deze applicatie is alleen maar beschikbaar op kantoor waar iedere pc een unieke ip-adres heeft).
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
<?php
session_start();
$_SESSION['hash'] = md5($_SERVER['REMOTE_ADDR']);
?>


Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<form name="login" method="post" action="login2.php">
                <table class="login">
                    <tr>
                        <td class="label">&nbsp;</td>
                        <td class="invoerveld"><p class="login verplicht">Verplichte velden zijn gemarkeerd met een *</p></td>
                    </tr>
                    <tr>
                        <td class="input"><p class="login">Gebruikersnaam *</p></td>
                        <td class="input"><input type="text" name="gebruikersnaam" id="gebruikersnaam" maxlength="100"/></td>
                    </tr>
                    <tr>
                        <td class="input"><p class="login">Wachtwoord *</p></td>
                        <td class="input"><input type="password" name="wachtwoord" id="wachtwoord" maxlength="20"/></td>
                    </tr>
                    <tr>
                        <td>&nbsp;</td>
                        <td>
                        <?php
                            // Laat errors zien bij het missen van gebruikersnaam of wachtwoord
                            if (isset($_GET['error'])) {
                                if ($_GET['error'] == "1") {
                                    echo "<div class='error'>Er is geen gebruikersnaam ingevuld</div>";
                                }
elseif ($_GET['error'] == "2") {
                                    echo "<div class='error'>Er is geen wachtwoord ingevuld</div>";
                                }
                            }

                        ?>

                        </td>
                    </tr>
                    <tr>
                        <td><input type="hidden" value="<?php echo $_SESSION['hash']; ?>" name="client-hash" /></td>
                        <td><input type="submit" value="Inloggen"/></td>
                    </tr>
                </table>
            </form>


Vervolgens handel ik alles af in een nieuw bestand zodat ik geen last heb van dubbele posts:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?php
session_start();

// Laat errors zien
error_reporting(E_ALL);
ini_set('display_errors', 1);

// Maak een connectie met de database
include("connect.php");

// Controleer of de gebruiker wel van onze login pagina komt
if (isset($_SESSION['hash'])) {
    
    // Controleer of de sessie overeenkomt met de login pagina
    if ($_SESSION['hash'] == md5($_SERVER['REMOTE_ADDR'])) {

        // Controleer of gebruikersnaam en wachtwoord is ingevuld
        if (isset($_POST['gebruikersnaam'], $_POST['wachtwoord'])) {

            // Controleer of gebruikersnaam niet leeg is
            if (empty($_POST['gebruikersnaam'])) {
                header( "refresh:0;url=login.php?error=1" ); // Error1 = gebruikersnaam is leeg
                
            // Controleer of wachtwoord niet leeg is

            } elseif (empty($_POST['wachtwoord'])) {
                header( "refresh:0;url=login.php?error=2" ); // Error2 = wachtwoord is leeg
                
            } else {
                // Voorkom SQL injection
                $gebruikersnaam = mysqli_real_escape_string($conn, $_POST['gebruikersnaam']);
                $wachtwoord = mysqli_real_escape_string($conn, $_POST['wachtwoord']);
                
                // Haal gebruiker op
                $sql = "SELECT gebruikersnaam, wachtwoord FROM gebruikers WHERE gebruikersnaam = '$gebruikersnaam'";
                $result = $conn->query($sql);
                
                // Ga door als er een gebruiker met dezelfde gebruikersnaam aanwezig is
                if ($result->num_rows > 0) {
                    while($row = $result->fetch_assoc()) {
                        if (password_verify($wachtwoord, $row['wachtwoord'])) {
                            $_SESSION['gebruikersnaam'] = $row['gebruikersnaam'];
                            header( "refresh:0;url=index.php" );
                        }
else {
                            echo 'Ongeldige gebruikersnaam/wachtwoord combinatie.';
                        }
                    }
                }
else {
                    echo "Kan geen gebruiker vinden met deze gebruikersnaam.";
                }
            }
            
        }
else {
            // Geen $_POST sessie? Naar login.php!
            header( "refresh:0;url=login.php" );
        }
        
    }
else {
        header( "refresh:0;url=login.php" );
    }
    
}
else {
    // Geen sessie?? Wegwezen!
    header( "refresh:0;url=login.php" );
}


?>
Gewijzigd op 21/08/2015 14:59:35 door Danny von Gaal
 
- Ariën  -
Beheerder

- Ariën -

21/08/2015 15:02:02
Quote Anchor link
Danny von Gaal op 21/08/2015 14:36:13:
Bovenaan mijn loginpagina maak ik een md5 hash aan op basis van ip-adres. (Sorry -Aar- maar die uniqueid begreep ik niet helemaal en deze applicatie is alleen maar beschikbaar op kantoor waar iedere pc een unieke ip-adres heeft).


Het stelt bar weinig voor:

Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
echo md5(uniqid());
?>


En de uitwerking:
https://3v4l.org/i9HHT
 
Thomas van den Heuvel

Thomas van den Heuvel

21/08/2015 15:17:52
Quote Anchor link
Ingeval van een loginformulier lijkt het mij logisch dat je zowel een gebruikersnaam als een wachtwoord invoert, ik weet niet of het heel veel zin heeft gebruikers hier expliciet op te wijzen. Volgens mij kun je gewoon volstaan met "login mislukt" en eventueel al voor verzenden voorkomen dat een (half) leeg formulier verzonden wordt.

In andere formulieren zou het handig / gebruiksvriendelijk zijn als de reeds ingevulde velden teruggeplaatst worden bij een foutmelding met eventueel een hint van wat er fout was. Een loginformulier leent zich hier overigens niet echt voor (je zou in dat geval ook geen hints moeten geven over wat er niet klopt).

Je token wordt nergens ongeldig gemaakt en is ook niet random. Dat maakt het token niet erg geschikt voor zijn doel. De opzet met uniqid() is geschikter. En zorg dat deze meteen ongeldig wordt gemaakt nadat je deze hebt gebruikt. Voorbeeld van een "random" token functie:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
<?php
function getRandomToken() {
    return sha1(uniqid(mt_rand(), true));
}

?>


Dan is een token formulier-invoer waarbij het formulierveld een bepaalde waarde zou moeten hebben waarop gevalideerd moet worden. De eerste controle die je dus zou moeten uitvoeren in login2.php zou eigenlijk een check moeten zijn of je met een POST request van doen hebt. Daarna zou je in eerste instantie kunnen kijken of het token voldoet en de rest van de velden valideren.

Je wachtwoord escapen met mysqli_real_escape_string (waarom niet $conn->real_escape_string()?) lijkt mij in dit geval niet goed, want als er in het wachtwoord karakters zitten die in de MySQL context geescaped zouden worden, dan mislukt je password_verify() aanroep. Je gebruikt $wachtwoord ook helemaal niet in een query...

De syntax header("refresh:0;url=..." ) ben ik niet bekend mee. Waarom gebruik je geen header('Location: ...')? Daarnaast zou na elke header die je redirect een exit moeten staan anders gaat de executie van het script gewoon door. Headers worden pas aan het einde van het script / voor het begin van output verstuurd.

Als je dus zoiets hebt:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
<?php
if ($als_de_authenticatie_check_mislukt) {
    header('Location: ergens_anders.php');
}

// CODE DIE UITGEVOERD WORDT ALS AUTHENTICATIE SLAAGT
// ...

?>

En de authenticatie-check mislukt, dan wordt je header geset, vervolgens wordt CODE DIE UITGEVOERD WORDT ALS AUTHENTICATIE SLAAGT uitgevoerd, en dan word je geredirect.

Het toevoegen of weglaten van een exit kan het verschil maken tussen een veilige of een onveilige applicatie.

Of nog beter, maak een functie/methode zodat je dit nooit vergeet:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
<?php
function redirect($url) {
    header('Location: '.$url);
    exit;
}

?>

Je kunt hier ook nog HTTP status codes aan toevoegen als je wilt (bijvoorbeeld HTTP/1.1 303 See Other), en officieel moet $url een volledige URL zijn.
Gewijzigd op 21/08/2015 15:19:49 door Thomas van den Heuvel
 

Pagina: 1 2 volgende »



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.