Lichen5221 / Report-Daily

記錄每日上課內容與作業。
0 stars 0 forks source link

2021-06-16 #55

Open Lichen5221 opened 3 years ago

Lichen5221 commented 3 years ago

修正偽造身份問題:給予通行證

index.php

<?php
  require_once("conn.php");
  require_once("utils.php");

$username = NULL;
if(!empty($_COOKIE['token'])) {
    $user = getUserFromToken($_COOKIE['token']);
    $username = $user['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 $row['nickname'];?>
                        </span>
                        <span class="card__time">
                            <?php echo $row['created_at'];?>
                        </span>
                    </div>
                    <p class="card__content"><?php echo $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 getUserFromToken($token) {
    global $conn;
     $sql = sprintf(
        "select username from tokens where token = '%s'",
        $token
     );
     $result = $conn -> query($sql);
     $row = $result -> fetch_assoc();
     $username = $row['username'];

     $sql = sprintf(
        "select * from users where username = '%s'",
        $username
     );
     $result = $conn -> query($sql);
     $row = $result -> fetch_assoc();
     return $row;
   }
 ?>

handle_login.php

<?php
   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 = sprintf(
     "select * from users where username='%s' and password='%s'",
     $username,
     $password
   );

   $result = $conn->query($sql);
   if (!$result) {
    die($conn->error);
   }

   if ($result -> num_rows) { 
    $token = randomToken();
    $sql = sprintf(
      "insert into tokens(token, username) values('%s', '%s')",
      $token,
      $username
    );
    $conn->query($sql);
    if (!$result) {
      die($conn->error);
    }

    $expire = time() + 3600 * 24 * 30;
    setcookie("token", $token, $expire);
    header("Location: index.php");
   } else {
    header("Location: login.php?errCode=2");
   }
 ?>

logout.php

<?php
   require_once('conn.php');

   $token = $_COOKIE['token'];
   $sql = sprintf(
      "delete from tokens where token = '%s'",
      $token
   );
   $conn -> query($sql);

   setcookie("token", "", time() - 3600);
   header("Location: index.php");
 ?>

handle_add_comment.php

<?php
   require_once('conn.php');
   require_once('utils.php');

   if (
     empty($_POST['content'])
   ) {
     header('Location: index.php?errCode=1');
     die('資料不齊全');
   }

   $user = getUserFromToken($_COOKIE['token']);
   $nickname = $user['nickname'];
   $content = $_POST['content'];

   $sql = sprintf(
     "insert into comments(nickname, content) values('%s', '%s')",
     $nickname,
     $content
   );

   $result = $conn->query($sql);
   if (!$result) {
     die($conn->error);
   }

   header("Location: index.php");
 ?>

建立 token 的資料庫,從 token 拿到 username ,再去對應 nickname。

有了隨機 token 後,就無法猜到其他帳號的 token ,也就無法偽造身份。

Lichen5221 commented 3 years ago

防止身份偽造: PHP 內建的通行證

SESSION 的使用,在每個有使用 SESSION 的檔案中,第一行都要加上 session_start(); 確保 SESSION 開啟。

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 $row['nickname'];?>
                        </span>
                        <span class="card__time">
                            <?php echo $row['created_at'];?>
                        </span>
                    </div>
                    <p class="card__content"><?php echo $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 = sprintf(
     "select * from users where username='%s' and password='%s'",
     $username,
     $password
   );

   $result = $conn->query($sql);
   if (!$result) {
    die($conn->error);
   }

   if ($result->num_rows) {
    $_SESSION['username'] = $username;
    header("Location: index.php");
   } else {
    header("Location: login.php?errCode=2");
   }
 ?>

logout.php

<?php
   session_start();
   session_destroy();
   header("Location: index.php");
 ?>

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;
   }
 ?>

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 = sprintf(
     "insert into comments(nickname, content) values('%s', '%s')",
     $nickname,
     $content
   );

   $result = $conn->query($sql);
   if (!$result) {
     die($conn->error);
   }

   header("Location: index.php");
 ?>

老師真是用心良苦,為了要讓我們知道 Cookie 跟 SESSION 背後的機制,特地弄了上面那一次,的確是有比較懂了,感謝老師。

Lichen5221 commented 3 years ago

明文密碼

這件事第一次聽說,非常酷。

原來資料庫不能直接傳密碼給我的原因,是因為他也不知道我的密碼!

所以可以直接傳密碼給我的網站是有漏洞可鑽囉?

只要給你密碼的網站都有資安風險!(亂下結論)

這部分我想要明天再看了。