Open Lichen5221 opened 3 years ago
在人家網頁上執行 JS 語法。
(留言板的留言提交後會直接被執行)
可以使網頁癱瘓、跳到別的網頁,偷資料到自己的網頁等。
index.php
<?php
session_start();
require_once("conn.php");
require_once("utils.php");
$username = NULL;
if(!empty($_SESSION['username'])) {
$username = $_SESSION['username'];
}
$result = $conn -> query("SELECT * FROM comments order by id desc");
if(!$result) {
die('Error:' . $conn -> error);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>留言板</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header class="warning">
<strong> 警告!有資安漏洞! </strong>
</header>
<main class="board">
<div>
<?php if (!$username) { ?>
<a class="board__btn" href="register.php">註冊</a>
<a class="board__btn" href="login.php">登入</a>
<?php } else { ?>
<a class="board__btn" href="logout.php">登出</a>
<h3>歡迎!<?php echo $username; ?></h3>
<?php } ?>
</div>
<h1 class="board__title">Comments</h1>
<?php
if(!empty($_GET['errCode'])) {
$code = $_GET['errCode'];
$msg = 'Error';
if ($code === '1') {
$msg = '錯誤:資料不齊全';
}
echo '<h2 class="error">' . $msg . '</h2>';
}
?>
<?php if ($username) { ?>
<form class="board__new-comment-form"method="POST" action="handle_add_comment.php">
<textarea name="content" rows="5"></textarea>
<input class="board__submit-btn"type="submit" />
</form>
<?php } else { ?>
<h3>請登入發布留言</h3>
<?php } ?>
<div class="board__hr"></div>
<section>
<?php
while($row = $result -> fetch_assoc()) {
?>
<div class="card">
<div class="card__avatar">
</div>
<div class="card__body">
<div class="card__info">
<span class="card__author">
<?php echo escape($row['nickname']);?>
</span>
<span class="card__time">
<?php echo $row['created_at'];?>
</span>
</div>
<p class="card__content"><?php echo escape($row['content']); ?></p>
</div>
</div>
<?php } ?>
</section>
</main>
</body>
</html>
utils.php
<?php
require_once("conn.php");
function randomToken() {
$s = '';
for ($i = 1; $i <= 16; $i++) {
$s .= chr(rand(65, 90));
}
return $s;
}
function getUserFromUsername($username) {
global $conn;
$sql = sprintf(
"select * from users where username = '%s'",
$username
);
$result = $conn -> query($sql);
$row = $result -> fetch_assoc();
return $row;
}
function escape($str) {
return htmlspecialchars($str, ENT_QUOTES);
}
?>
只要是使用者可以填空的時候就要把所有全都用 escape 。
可以透過在留言板拼接 SQL 指令字串來盜取資料庫的內容。
index.php
<?php
session_start();
require_once("conn.php");
require_once("utils.php");
$username = NULL;
if(!empty($_SESSION['username'])) {
$username = $_SESSION['username'];
}
$stmt = $conn -> prepare('SELECT * FROM comments order by id desc');
$result = $stmt -> execute();
if(!$result) {
die('Error:' . $conn -> error);
}
$result = $stmt -> get_result();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>留言板</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<header class="warning">
<strong> 警告!有資安漏洞! </strong>
</header>
<main class="board">
<div>
<?php if (!$username) { ?>
<a class="board__btn" href="register.php">註冊</a>
<a class="board__btn" href="login.php">登入</a>
<?php } else { ?>
<a class="board__btn" href="logout.php">登出</a>
<h3>歡迎!<?php echo $username; ?></h3>
<?php } ?>
</div>
<h1 class="board__title">Comments</h1>
<?php
if(!empty($_GET['errCode'])) {
$code = $_GET['errCode'];
$msg = 'Error';
if ($code === '1') {
$msg = '錯誤:資料不齊全';
}
echo '<h2 class="error">' . $msg . '</h2>';
}
?>
<?php if ($username) { ?>
<form class="board__new-comment-form"method="POST" action="handle_add_comment.php">
<textarea name="content" rows="5"></textarea>
<input class="board__submit-btn"type="submit" />
</form>
<?php } else { ?>
<h3>請登入發布留言</h3>
<?php } ?>
<div class="board__hr"></div>
<section>
<?php
while($row = $result -> fetch_assoc()) {
?>
<div class="card">
<div class="card__avatar">
</div>
<div class="card__body">
<div class="card__info">
<span class="card__author">
<?php echo escape($row['nickname']);?>
</span>
<span class="card__time">
<?php echo $row['created_at'];?>
</span>
</div>
<p class="card__content"><?php echo escape($row['content']); ?></p>
</div>
</div>
<?php } ?>
</section>
</main>
</body>
</html>
handle_login.php
<?php
session_start();
require_once('conn.php');
require_once('utils.php');
if (
empty($_POST['username']) ||
empty($_POST['password'])
) {
header('Location: login.php?errCode=1');
die('資料不齊全');
}
$username = $_POST['username'];
$password = $_POST['password'];
$sql = "select * from users where username=?";
$stmt = $conn -> prepare($sql);
$stmt -> bind_param("s", $username);
$result = $stmt -> execute();
if (!$result) {
die($conn->error);
}
$result = $stmt -> get_result();
if ($result -> num_rows === 0) {
header("Location: login.php?errCode=2");
exit();
}
$row = $result -> fetch_assoc();
if(password_verify($password, $row['password'])) {
$_SESSION['username'] = $username;
header("Location: index.php");
} else {
header("Location: login.php?errCode=2");
}
?>
handle_register.php
<?php
session_start();
require_once('conn.php');
if (
empty($_POST['nickname']) ||
empty($_POST['username']) ||
empty($_POST['password'])
) {
header('Location: register.php?errCode=1');
die('資料不齊全');
}
$nickname = $_POST['nickname'];
$username = $_POST['username'];
$password = password_hash($_POST['password'],
PASSWORD_DEFAULT);
$sql =
"insert into users(nickname, username, password)
values(?, ?, ?)";
$stmt = $conn -> prepare($sql);
$stmt -> bind_param("sss", $nickname, $username, $password);
$result = $stmt -> execute();
if (!$result) {
$code = $conn -> errno;
if($code === 1062) {
header('Location: register.php?errCode=2');
}
die($conn->error);
}
$_SESSION['username'] = $username;
header("Location: index.php");
?>
handle_add_comment.php
<?php
session_start();
require_once('conn.php');
require_once('utils.php');
if (
empty($_POST['content'])
) {
header('Location: index.php?errCode=1');
die('資料不齊全');
}
$user = getUserFromUsername($_SESSION['username']);
$nickname = $user['nickname'];
$content = $_POST['content'];
$sql = "insert into comments(nickname, content)
values(?, ?)";
$stmt = $conn -> prepare($sql);
$stmt -> bind_param('ss', $nickname, $content);
$result = $stmt -> execute();
if (!$result) {
die($conn->error);
}
header("Location: index.php");
?>
加密 VS Hash
加密:一對一,可還原。(猜得到原密碼)
Hash:多對一,無法還原。(猜不到原密碼)
修正問題:使用 Hash
首先要注意該函式密碼產出位元數,如果資料庫一開始設置密碼可輸入的位元數太小會無法使用該函式。
handle_register.php
handle_login.php