Single login script dubbele hash

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Michael -

Michael -

08/11/2019 15:29:31
Quote Anchor link
Hoi,

Ik moest even snel een single login scriptje hebben tegen pottenkijkers :-)
Het werkt prima alleen bij inloggen wordt een hash opgeslagen, en daarna wordt deze vergeleken en wordt de hash 'vernieuwt'. Omdat ik een location header gebruik na het inloggen wordt dit beide uitgevoerd en dus twee hashes gegenereerd. Het is geen ramp, maar was benieuwd of iemand hier een idee over heeft. En gelijk een goed moment voor een check, aangezien twee ogen meer zien dan één.

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
<?php
defined('ROOT') or define('ROOT',dirname(__FILE__));
require_once ROOT . '/_config.php';
define('ACCESS_PASSWORD', '$argon2i$v=19$m=65536,t=4,p=1$bXFoSC9vYTZhWmNJVGtwYQ$FMYDTnYGuvtBjGM+oJTp/ByjXr1veFG5KBxVjssLKEM');

function
generatehash() {
    return base64_encode(openssl_random_pseudo_bytes(32));
}


$timenow = (new \DateTime())->format('Y-m-d H:i:s');
$access = false;

if($_SERVER['REMOTE_ADDR'] == REMOTE_ADDR) {
    $access = true;
}
else if(isset($_SESSION['hash'])) {
    try {
        $stmt = $db->prepare("
        SELECT
            hash,
            hashtime
        FROM
            "
.  TABLE_PREFIX . "access
        WHERE
            hash = '"
. $_SESSION['hash'] . "'
        AND
            hashtime >= (NOW() - INTERVAL 30 MINUTE)
        LIMIT
            0,1
        "
);
        $stmt->execute();
        
        if($stmt->rowCount() > 0) {
            $stmt = $db->prepare("
            INSERT IGNORE
                INTO "
. TABLE_PREFIX . "access
                (
                    hash,
                    hashtime
                )
                VALUES
                (
                    :hash,
                    :hashtime
                )
            "
);

            $stmt->bindParam(':hash', $hash, PDO::PARAM_STR);
            $stmt->bindParam(':hashtime', $hashtime, PDO::PARAM_STR);

            $hash = generatehash();
            $hashtime = $timenow;
            
            $stmt->execute();
            if($stmt->rowCount() > 0) {
                $access = true;
                unset($_SESSION['hash']);
                $_SESSION['hash'] = $hash;
            }
        }
else {
            unset($_SESSION['hash']);
            $notes[] = 'Your session has expired';
        }
    }

    catch(PDOException $e)
    {
    
        $debugMsg = 'Line: '.$e->getLine().'<br />'
        .'File: '.$e->getFile().'<br />'
        .'Message: '.$e->getMessage();
        echo '<p>' . $debugMsg . '</p>';
    }
}
else if($_SERVER['REQUEST_METHOD'] == "POST") {
    if(isset($_POST['password']) && password_verify($_POST['password'], ACCESS_PASSWORD)) {
        try {
            $stmt = $db->prepare("
            INSERT IGNORE
                INTO "
. TABLE_PREFIX . "access
                (
                    hash,
                    hashtime
                )
                VALUES
                (
                    :hash,
                    :hashtime
                )
            "
);

            $stmt->bindParam(':hash', $hash, PDO::PARAM_STR);
            $stmt->bindParam(':hashtime', $hashtime, PDO::PARAM_STR);

            $hash = generatehash();
            $hashtime = (new \DateTime())->format('Y-m-d H:i:s');
            
            $stmt->execute();
            if($stmt->rowCount() > 0) {
                $access = true;
                unset($_SESSION['hash']);
                $_SESSION['hash'] = $hash;
                header('Location: ' . $_SERVER['SCRIPT_NAME']);
                exit();
            }
        }
catch(PDOException $e) {
            $debugMsg = 'Line: '.$e->getLine().'<br />'
            .'File: '.$e->getFile().'<br />'
            .'Message: '.$e->getMessage();
            echo '<p>' . $debugMsg . '</p>';
        }
    }
else $notes[] = 'Password incorrect';
}

if($access === false) {
?>

<!-- Hier het inlogformulier -->
<?php
exit();
}

?>
Gewijzigd op 08/11/2019 16:03:32 door Michael -
 
PHP hulp

PHP hulp

19/11/2019 04:25:04
 
Thomas van den Heuvel

Thomas van den Heuvel

08/11/2019 21:24:44
Quote Anchor link
Dit is dus een soort "nonce" ofzo? Mja, dat gaat waarschijnlijk wel werken. Maar alles dichtgooien op IP lijkt mij om kortstondig pottenkijkers buiten te houden afdoende? Of voorziet dit juist in dynamische IP's ofzo?

Daarbij, stel dat je dadelijk een complete applicatie hebt die zo werkt, en je hebt dan AJAX-calls enzo... dat wordt op den duur een behoorlijke puinzooi?

En dan, stel dat je sessie expired (standaard na ca. 24 minuten) en je submit dan een zwik werk, dan wil je eigenlijk dat je sessie onder water doorstart zonder dat je je werk kwijt bent.

Dan nog wat inhoudelijke opmerkingen:
- een prepared statement met hierin een $_SESSION geconcateneerd? errrr
- waarom een unset en daarna een assignment? doe de assignment meteen?
- $timenow en $hashtime zullen meestal dezelfde waarde hebben, houd het op 1 variabele?
- heb je al gekeken of je access table niet langzaan volloopt op deze manier?
- implicaties van rowCount() > 0 tov rowCount() = 1 al bekeken?
- misschien is het ook handig om de sessies zelf op te slaan in de database?
- je gebruikt nergens session_regenerate_id(), waarom (niet)?
- waar wordt $notes gebruikt?
- dat hele INSERT-gedoe, je doet in wezen 2x nagenoeg hetzelfde, kun je dat niet inkorten? het enige wat verschilt is de conditie vooraf, en de actie achteraf
- zou het record niet gelocked moeten worden tijdens het inspecteren en bijwerken?

meh.
 
Michael -

Michael -

11/11/2019 07:09:16
Quote Anchor link
Quote:
Dit is dus een soort "nonce" ofzo?

Het is niet voor eenmalig gebruik.

Quote:
Mja, dat gaat waarschijnlijk wel werken. Maar alles dichtgooien op IP lijkt mij om kortstondig pottenkijkers buiten te houden afdoende? Of voorziet dit juist in dynamische IP's ofzo?

Voor thuis is dit handig ja, maar de meeste tijd ben ik dat niet dus dan is het handig dat er een mogelijkheid is om in te loggen ;-)

Quote:
Daarbij, stel dat je dadelijk een complete applicatie hebt die zo werkt, en je hebt dan AJAX-calls enzo... dat wordt op den duur een behoorlijke puinzooi?

Waarom zou dat een puinzooi zijn? Het gaat er om dat je zo eenvoudig één of meerder pagina's kan afschermen.

Quote:
En dan, stel dat je sessie expired (standaard na ca. 24 minuten) en je submit dan een zwik werk, dan wil je eigenlijk dat je sessie onder water doorstart zonder dat je je werk kwijt bent.

Dat zal niet heel snel gebeuren. Daarnaast als je formulieren waar je een halfuur mee bezig bezig om in te vullen zou ik sowieso tussentijds opslaan.

Quote:
een prepared statement met hierin een $_SESSION geconcateneerd? errrr

:-)

Quote:
waarom een unset en daarna een assignment? doe de assignment meteen?

Ik sommige gevallen gebeurt het wel eens dat een sessie niet goed wordt overschreven. Hiermee voorkom je dat dus. Meer uit voorzorg dus.

Quote:
$timenow en $hashtime zullen meestal dezelfde waarde hebben, houd het op 1 variabele?

Ze zijn het zelfde, maar ik zie nu inderdaad de verwarring. Ik zal dit oplossen.

Quote:
heb je al gekeken of je access table niet langzaan volloopt op deze manier?

Het scheelt dat er niet dagelijks verschillende mensen inloggen, maar ja er worden al snel meerdere hashes opgeslagen. Opzich is dit niet echt een probleem.

Quote:
implicaties van rowCount() > 0 tov rowCount() = 1 al bekeken?

Nee, wat bedoel je hiermee? Ik doe altijd > 0. Dat is een gewoonte ;-)

Quote:
misschien is het ook handig om de sessies zelf op te slaan in de database?

Waarom zou je dit willen?

Quote:
je gebruikt nergens session_regenerate_id(), waarom (niet)?

Nee, waarom zou je die willen gebruiken?

Quote:
waar wordt $notes gebruikt?

Om meldingen weer te geven ;-)

Quote:
dat hele INSERT-gedoe, je doet in wezen 2x nagenoeg hetzelfde, kun je dat niet inkorten? het enige wat verschilt is de conditie vooraf, en de actie achteraf

Ja klopt helemaal. Ziet er inderdaad niet logisch uit. Ik zal hierna kijken.

Quote:
zou het record niet gelocked moeten worden tijdens het inspecteren en bijwerken?

Geen idee? Inprincipe bestaat deze maar één keer en hij wordt nooit bijgewerkt, maar een nieuwe aangemaakt. Dus ik zou denken nee.
Gewijzigd op 11/11/2019 12:54:24 door Michael -
 



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.