• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

System levelu, poziomu + SQL Injection

Object Storage Arubacloud
+1 głos
271 wizyt
pytanie zadane 23 września 2020 w PHP przez Kacperhehe Bywalec (2,930 p.)

Mam taki skrypt:

    // LEVEL SYSTEM
      if ($xp >= $_SESSION['xp_needed']) {
          $new_xp = $xp - $_SESSION['xp_needed'];
          $next_lvl = $_SESSION['lvl'] + 1;
          $xp_needed = $_SESSION['xp_needed'] + 100;
          $sql_next_lvl = "UPDATE users SET lvl='$next_lvl' WHERE id =  ".$_SESSION['id'];
          mysqli_query($db, $sql_next_lvl);
          $sql_xp_needed = "UPDATE users SET xp_needed='$xp_needed' WHERE id =  ".$_SESSION['id'];
          mysqli_query($db, $sql_xp_needed);
          $sql_lvl = "UPDATE users SET xp='$new_xp' WHERE id =  ".$_SESSION['id'];
          mysqli_query($db, $sql_lvl);

Wszystko fajnie działa dopóki XP zdobyte przez użytkownika nie przekroczy dwóch LVL
typu gdy potrzebuje 100 do następnego ale dostanie dla tego przykładu 1000 i to w rzeczywistości nam użytwkonik od razu przekroczy na tam jakiś 10 LVL.

Nie mam do tego w ogóle głowy :((

A i jeszcze pytanko co to do SQL Injection? W jaki sposób takie ataki są wykonywane z tego co widziałem każdy pokazywał przez jakiegoś Inputa na stronie, ale gdybym pozbył się wszystkich? To czy nadal byłbym zagrożony takim. Czy na jakieś innej zasadzie atakują? Bo ludzie mi mówili że taki zapis jest niebezpieczny.

2 odpowiedzi

+1 głos
odpowiedź 1 października 2020 przez VBService Ekspert (253,100 p.)
wybrane 5 października 2020 przez Kacperhehe
 
Najlepsza

Może Moja interpretacja, będzie dla Ciebie pomocna. wink

Tabela do testów:

CREATE TABLE `demo_game_level_system`.`users`
( 
  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `level` INT UNSIGNED NOT NULL,
  `xp_all` INT UNSIGNED NOT NULL,
  `xp_current` INT UNSIGNED NOT NULL,
  `xp_needed` INT UNSIGNED NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE = InnoDB;

INSERT INTO `users` (`id`, `level`, `xp_all`, `xp_current`, `xp_needed`) 
  VALUES (NULL, '1', '0', '0', '100');

index.php

<?php
    session_start();
    define('XP__NEEDED','100');

    //unset($_SESSION['id_user']);

    if (isset($_COOKIE["PHPSESSID"]) && isset($_SESSION['id_user'])) {
        if ($_SERVER["REQUEST_METHOD"] == "POST") {
            try {
                require_once('db_functions.php');
                $user_info = getUserInfo($_SESSION['id_user']);
                $xp_current = $_POST['xp_current'];

                foreach ($user_info as $data) {
                    $user_level = $data['level'];
                    $xp_all = $data['xp_all'];
                    $xp_needed = $data['xp_needed'];
                }

                if ($xp_current >= $xp_needed) {
                    $user_level += 1;
                    setUserInfo('level', $user_level, $_SESSION['id_user']);

                    $xp_all += $xp_current;
                    setUserInfo('xp_all', $xp_all, $_SESSION['id_user']);

                    $xp_current -= $xp_needed;
                    setUserInfo('xp_current', $xp_current, $_SESSION['id_user']);

                    $xp_needed = XP__NEEDED * $user_level;
                    setUserInfo('xp_needed', $xp_needed, $_SESSION['id_user']);
                }

                $user_info = getUserInfo($_SESSION['id_user']);
                $rows = showUserInfo($user_info);
            } catch (Exception $e) {
                echo $e->getMessage();
            }
        }
    } else {
        // Symulacja zalogowania się użytkownika do Twojego systemu
        // Uzytkownik zalogował się za pomocą formularza - prawidłowo
        $_SESSION['id_user'] = 1;

        try {
            require_once('db_functions.php');
            $user_info = getUserInfo($_SESSION['id_user']);
            $rows = showUserInfo($user_info);
        } catch (Exception $e) {
            echo $e->getMessage();
        }
    }
?>

<!-- Demo -->
<!DOCTYPE html>
<html>
    <head lang="pl">
        <meta charset="utf-8">

    <style>
        :root {
            --board-width: 20vw;
        }
        * {
            box-sizing: border-box;
        }
        thead tr {
            background-color: gray;
            color: white;
            font: 1em monospace;
        }
        thead th {
            padding: 0.5em;
        }
        tbody td {
            padding: 0.2em;
            text-align: center;
        }
        .game-board {
            width: var(--board-width);
            margin-top: 2em;
            padding: 0.2em;
            font: 1.1em monospace;
        }
        .game-board .playground {
            font: 0.8em bold monospace;
            padding: 0.2em;
            color: green;
            text-align: center;
        }
        .game-board .play-time {
            font-size: 4.1em;
        }
        .game-board button {
            width:  var(--board-width);
            cursor: pointer;
            box-shadow: 2px 2px 1px grey;
            font: 1.2em monospace;
            font-variant: small-caps;
        }
        .game-board button:active {
            transform: translateY(1px);
            box-shadow: none;
        }
    </style>
    </head>
    <body>
        <table>
            <thead>
                <tr><th colspan="5">Dane z bazy danych</th></tr>
                <tr>
                    <th>Użytkownik</th>
                    <th>Poziom</th>
                    <th>Punkty zdobyte</th>
                    <th>Punkty obecne</th>
                    <th>Punkty następny poziom</th>
                </tr>
            </thead>
            <tbody>
                <?php echo $rows; ?>
            </tbody>
        </table>
        <div class="game-board">
            <div>Punkty: <span id="user_points"></span></div>
            <div id="playground" class="playground play-time">0</div>
            <div><button id="play">Graj</button></div>
        </div>
        <form id="form" action="index.php" method="post">
            <input type="hidden" id="xp_current" name="xp_current" value="">
        </form>
    <script>
        const xp_current_db = document.getElementById('xp_current_db');
        const xp_needed = document.getElementById('xp_needed');
        const user_points = document.getElementById('user_points');
        const playground = document.getElementById('playground');
        const button_play = document.getElementById('play');

        const XP__NEEDED = xp_needed.textContent * 1;

        (setUserPoints = function(points = null) {
            if (points == null) {
                user_points.textContent = xp_current_db.textContent;
            } else {
                let calculate_user_points = user_points.textContent * 1;
                calculate_user_points += points;
                user_points.textContent = calculate_user_points;

                if (calculate_user_points >= XP__NEEDED) {
                    button_play.disabled = true;
                    playground.classList.remove('play-time');
                    playground.innerHTML = 'Gratulacje !<br>Przechodzisz na następny poziom.';

                    setTimeout(sendData, 2000, calculate_user_points);
                }
            }
        }).call(this)

        button_play.addEventListener('click', () => {
            const min = 1;
            const max = XP__NEEDED;
            const result = Math.floor(Math.random() * (max - min + 1) ) + min;
            playground.textContent = result;
            setUserPoints(result);
        })

        function sendData(points) {
            const form = document.getElementById('form');
            const input_xp_current = document.getElementById('xp_current');
            input_xp_current.value = points;
            form.submit();
        }
    </script>
    </body>
</html>

db_functions.php

<?php
    define('HOST','localhost');
    define('USER','root');
    define('PASS','');
    define('DB','demo_game_level_system');

    function connect($conn = null) {
        if ($conn == null) {
            $conn = mysqli_connect(HOST,USER,PASS,DB) or die("Błąd połączenia!");
            return $conn;
        } else {
            $conn->close();
        }
    }

    function showUserInfo($user_info) {
        foreach ($user_info as $row) {
            $rows = '<tr>'
                    .'<td>'.$row['id'].'</td>'
                    .'<td>'.$row['level'].'</td>'
                    .'<td>'.$row['xp_all'].'</td>'
                    .'<td id="xp_current_db">'.$row['xp_current'].'</td>'
                    .'<td id="xp_needed">'.$row['xp_needed'].'</td>'
                    .'</tr>';
        }

        return $rows;
    }

    function getUserInfo($id) {
        $conn = connect();

        $sql = 'SELECT id, level, xp_all, xp_current, xp_needed FROM users WHERE id = ?';
        $stmt = $conn->prepare($sql);
        $stmt->bind_param('i', $id);
        $stmt->execute();

        $res = $stmt->get_result();
        $stmt->close();
        connect($conn);

        return $res->fetch_all(MYSQLI_ASSOC);
    }

    function setUserInfo($key, $value, $id) {
        $conn = connect();

        $sql = 'UPDATE users SET '.$key.' = ? WHERE id = ?';
        $stmt = $conn->prepare($sql);
        $stmt->bind_param('ii', $value, $id);
        $stmt->execute();

        $stmt->close();
        connect($conn);
    }
?>

0 głosów
odpowiedź 29 września 2020 przez mtk3d Nałogowiec (46,690 p.)

Musisz lepiej wyjaśnić co ten kod ma robić, bo ciężko mi to zrozumieć z powyższego przykładu.

Co do SQLInjection, to wcale nie musisz mieć inputów żeby było możliwe jego przeprowadzenie.
Przy odpowiednim zmanipulowaniu parametrów, możesz wstrzyknąć własne zapytanie. Np.:

// Przyjmujemy że ktoś podmienił id w sesji na zapytanie
echo $_SESSION['id']; // Rezultat: 1 OR 1=1

$next_lvl = 2;
$query = "UPDATE users SET lvl='$next_lvl' WHERE id = ".$_SESSION['id'];

echo $query; // Rezultat: UPDATE users SET lvl='2' WHERE id = 1 OR 1=1

W powyższym przykładzie otrzymujemy zapytanie które zaktualizuje lvl na 2 dla wszystkich użytkowników w bazie.

Żeby tego uniknąć, użyj najlepiej PDO i bindowania wartości https://pl.wikibooks.org/wiki/PHP/Biblioteka_PDO

Podobne pytania

+1 głos
2 odpowiedzi 371 wizyt
pytanie zadane 11 sierpnia 2020 w PHP przez Bakkit Dyskutant (7,600 p.)
0 głosów
2 odpowiedzi 426 wizyt
pytanie zadane 1 września 2020 w PHP przez Kacperhehe Bywalec (2,930 p.)
+1 głos
1 odpowiedź 191 wizyt

92,555 zapytań

141,403 odpowiedzi

319,557 komentarzy

61,940 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...