У меня есть веб приложение, которое представляет из себя небольшую игрушку по типу Blum. Т. к. я являюсь новичком в этой сфере, все расчёты, связанные с важными переменными происходят со стороны клиента.
Пример:
startGameButton.addEventListener("click", () => {
if (tokens !== 0) {
tokens -= 1;
updateUserData();
scoreElement.textContent = `Ð ${score}`;
startMenu.style.display = "none";
gameContainer.classList.remove("hidden");
totalScoreDisplay.classList.add("hidden");
highlightRandomDots();
clearTimeout(gameTimer);
clearInterval(countdownTimer);
startCountdown(30);
} else {
tokensDis.classList.add("red");
setTimeout(() => {
tokensDis.classList.remove("red");
}, 500);
}
});
В этом куске кода критическая переменная это tokens. При нажатии на кнопку start со стороны клиента у пользователя отнимается один токен и кол-во общих токенов отправляется в бд с помощью updateUserData(), данные считываются с помощью функции fetchUserData();
function fetchUserData() {
if (isUpdating) return;
fetch(`../getUserData.php?username=${username}&inviter_id=${inviter_id}`)
.then(response => response.json())
.then(data => {
tokens = data.tokens;
coins = data.coins;
claimed1 = data.claimed1;
claimed2 = data.claimed2;
farming_final_time = String(data.farming_final_time);
invites = data.invites;
tokensDis.textContent = `️ ${tokens}`;
totalScoreDisplay.textContent = `Ð ${coins}`;
if (claimed1) {
document.getElementById('claim').classList.add("claimed");
document.getElementById('claim').disabled = true;
}
checkFarming();
checkInvites();
})
.catch(error => console.error('Error:', error));
}
function updateUserData() {
isUpdating = true;
if (invites != 0) {
document.getElementById('splash-screen').style.display = 'none';
tokens = parseInt(tokens, 10) + 20*invites;
invites = 0;
}
const data = {
username: username,
tokens: tokens,
coins: coins,
claimed1: claimed1,
claimed2: claimed2,
farming_final_time: farming_final_time,
invites: invites,
};
fetch('../updateUserData.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => {
if (data.status === 'success') {
console.log('User data updated successfully');
} else {
console.error('Error updating user data:', data.message);
}
})
.catch(error => console.error('Error:', error));
isUpdating = false;
}
Вот серверный код
<?php
include 'config.php';
// Получение данных из входного JSON
$data = json_decode(file_get_contents('php://input'), true);
// Проверка, что все ключи существуют в данных
if (!isset($data['username'], $data['tokens'], $data['coins'], $data['claimed1'], $data['claimed2'], $data['farming_final_time'], $data['invites'])) {
echo json_encode(["status" => "error", "message" => "Incomplete data"]);
exit();
}
$username = $data['username'];
$tokens = $data['tokens'];
$coins = $data['coins'];
$claimed1 = $data['claimed1'];
$claimed2 = $data['claimed2'];
$farming_final_time = $data['farming_final_time'];
$invites = $data['invites'];
// Обновление данных пользователя
$sql = "UPDATE users SET tokens = ?, coins = ?, claimed1 = ?, claimed2 = ?, farming_final_time = ?, invites = ? WHERE username = ?";
$stmt = $conn->prepare($sql);
if (!$stmt) {
echo json_encode(["status" => "error", "message" => $conn->error]);
exit();
}
$stmt->bind_param("iiissss", $tokens, $coins, $claimed1, $claimed2, $farming_final_time, $invites, $username);
if ($stmt->execute()) {
echo json_encode(["status" => "success"]);
} else {
echo json_encode(["status" => "error", "message" => $stmt->error]);
}
$stmt->close();
$conn->close();
?>
В ходе изучения темы я понял, что это очень небезопасный метод, пользователь может отправлять в базу данных любые данные, которые он захочет (накручивать токены и тд) с помощью консоли браузера, путём изменения переменной на стороне клиента и отправкой в базу с помощью php скрипта. Такой вопрос, как мне максимально обезопасить эту процедуру? Чтобы если пользователь пытался накрутить токены, сервер не давал отправить эти данные в базу данных.