0

嘿,我是 PHP 新手,所以非常希望您能深入了解我是如何编程的,而且我在为会话问题提出解决方案时遇到了麻烦。

我正在为易货交易和本地贸易系统 ( LETS ) 编写脚本,我目前正在编写报价页面,用户可以在其中查看所有提供的产品/服务,然后单击产品/服务以获取更多详细信息。点击产品/服务后,他们可以出价。在 LETS 系统中,成员拥有时间/生活美元,他们可以通过与其他人进行交易来赚取收入。所以它的替代货币几乎是由工作的人创造的(不像我们目前政府使用的法定货币系统)。因此,如果用户拥有 Life Dollars,他们可以向提供其产品/服务的其他用户出价。

我在一个名为offers.php. 简而言之,将有 4 页由offers.php. 当用户最初查看报价部分 ( offers.php) 时,他们会看到所有报价,然后他们可以单击报价 ( offers.php?id=X),然后单击进行出价 ( offers.php?id=X&action=makebid),然后确认出价 ( offers.php?id=X&action=confirm)。

好的,所以我的会话的问题是:当用户从开始offers.php?id=X到结束时,会话工作。如果他们走他们认为应该没有问题的路线,他们将无法绕过我的验证。但是,如果用户点击说offers.php?id=100然后offers.php?id=200&confirm在浏览器地址栏中输入 URL,他们可以绕过我的验证,从而导致两次输入报价(如果他们已经提出报价)。当用户直接转到另一个时也会发生同样的情况offers.php?etcURL,但这不是什么大问题。我仍然想更正此问题,因为我担心何时将产品/服务页面粘贴到另一个网站上,因为这样会话将无法正常工作。我说的有道理吗?如果需要,我可以解释更多。我喜欢编程,所以尽可能丢掉任何提示/挑战。感谢您抽出宝贵的时间 :)

这是我的offers.php代码:

<?php

require_once('startsession.php');
require_once('dbconnect.php');

if (!isset($_SESSION['user_id'])) {
    echo '<p class="login">Please <a href="login.php">log in</a> to access this page.</p>';
    exit();
}

require_once('navmenu.php');

$dbc = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);

if (isset($_GET['id']) && $_GET['action'] == 'confirm') {

    $adid = $_GET['id'];
    $userid = $_SESSION['user_id'];
    $cost = $_SESSION['cost'];
    $sellerid = $_SESSION['seller_id'];

    //Check if bid was already made
    $query = "SELECT * FROM transactions WHERE ad_id = '$adid' AND buyer_id = '$userid'";
    $data = mysqli_query($dbc, $query);
    $row = mysqli_num_rows($data);

    if ($row == 1) {
        echo '<p>Bid has been made</p>';
    } else {
        //If bid doesnt already exist insert bid
        $query = "INSERT INTO transactions (ad_id, buyer_id, seller_id, cost, status) VALUES ('$adid', '$userid', '$sellerid', '$cost', 'O')";
        $data = mysqli_query($dbc, $query);
    }
} else if (isset($_GET['id']) && $_GET['action'] == 'makeoffer') {

    $adid = $_GET['id'];
    $userid = $_SESSION['user_id'];

    //Check if bid was already made
    $query = "SELECT * FROM transactions WHERE ad_id = '$adid' AND buyer_id = '$userid'";
    $data = mysqli_query($dbc, $query);
    $row = mysqli_num_rows($data);

    if ($row == 1) {
        echo '<p>You have already made a bid on this..</p>';
    } else {
        echo '<form method="post" action="offers.php?id=' . $adid . '&action=confirm">';
        echo '<p>You are about to bid 5 Life Dollars.';
        echo '<input type="submit" value="Confirm" name="submit" /></p>';
        echo '</form>';
    }
} else if (isset($_GET['id'])) {

    $userid = $_SESSION['user_id'];

    //Get ad details
    $adid = $_GET['id'];

    $query = "SELECT * from ads WHERE id = '$adid'";
    $data = mysqli_query($dbc, $query);

    $row = mysqli_fetch_array($data);

    //echo ad details
    echo '<p>' . $row['ad_name'] . '<br>' . $row['ad_desc'] . '<br>' . 'Cost: ' . $row['timedollars']
    . ' Time Dollars . ' . '<br>';

    //Set session seller and cost
    $sellerid = $row['seller_id'];
    $_SESSION['seller_id'] = $sellerid;
    $_SESSION['cost'] = $row['timedollars'];

    //Check to see if a bid was already made
    $query = "SELECT * FROM transactions WHERE ad_id = '$adid' and buyer_id = '$userid'";
    $data = mysqli_query($dbc, $query);
    $row = mysqli_num_rows($data);

    if ($row == 0 && $userid != $sellerid) {
        echo '<a href="offers.php?id=' . $adid . '&action=makeoffer">Make Bid</a></p>';
    } else if ($row == 1) {
        echo 'Already bidded';
    }
} else {

    //Get all ads/offers
    $query = "SELECT * FROM ads WHERE ad_type = 'O'";
    $data = mysqli_query($dbc, $query);

    //echo all ads
    while ($row = mysqli_fetch_array($data)) {
        echo '<p>' . '<a href="offers.php?id=' . $row['id'] . '">' . $row['ad_name'] . '</a>' . '<br>' . $row['ad_desc'] . '</p>';
    }
}

mysqli_close($dbc);
?>

enter code here
4

3 回答 3

2

这很复杂哈哈。

好的,因此减少“破解”您的网站的能力的一种简单方法是使用“发布”变量而不是“获取”变量。这样他们就不能只修改地址栏,他们必须发布他们的变量。

我会这样做的方式是将“事务”存储在数据库中。因此,您将拥有一个带有session_idaction或类似于列的表格。然后,当他们加载脚本的每个“页面”而不是从查询字符串中获取它们的位置时,您将在数据库中查询它们的 session_id 并从那里获取操作。然后,每次他们完成一个动作时,您都会更新数据库以说明他们现在所处的位置。

另一种方法是将操作放入 $_SESSION 变量并每次调用它。

于 2010-08-13T19:09:27.560 回答
1

我快速阅读了你的问题(它需要一些重大的编辑),而我突然想到的是......

我在一个名为 offer.php 的 PHP 页面上完成了所有这些工作。简单地说,将有4个页面由offers.php组成。当用户最初查看报价部分 (offers.php) 时,他们会看到所有报价,然后他们可以点击报价 (offers.php?id=X),然后点击进行出价 (offers.php?id= X&action=makebid) 然后确认出价 (offers.php?id=X&action=confirm)。

我想说在一个脚本中拥有这么多功能是一种主要的代码气味。

为什么不使用 4 个 PHP 脚本呢?

  • offers.php
  • an-offer.php
  • bid.php
  • confirm.php

附录

就像@Thomas Clayton 所说,您需要在POST这里使用一些请求。您正在使用请求修改服务器状态,这在很多方面GET都是教科书BAD ,这让我希望您使用 RegEx 来解析 HTML。(这也很糟糕)

阅读Wikipediaw3c 网站,了解 GET 如何成为一种安全方法。

GET阅读有关由于更改请求状态而被破坏的网站:

于 2010-08-13T19:08:30.830 回答
0

我绝对同意使用 POST。就像是:

<form method=POST action='offers.php'>
<input type=hidden name=id value=100>
<input type=hidden name=action value=confirm>

</form>

但是,请记住,这实际上并不能阻止某人伪造提交。它只是让这样做变得不那么方便了。

最后,我想说,如果这是用户无论如何都可以执行的操作,我不会花费大量精力来阻止它。也就是说,如果他们可以浏览该网站,找到 id 200,然后点击确认... 那么,这与手动将其输入地址栏有什么区别?只要它只影响他们的帐户,它就不是主要的安全问题。

正如我在评论中所说的那样,您更大的问题是通过在将 id 放入您的 sql 查询之前不转义 id 来邀请您进行 sql 注入。即使您执行以下操作:

$id = $_GET['id'] + 0

确保您有一个号码,而不是恶意文本。

要考虑的另一件事是使用 switch 语句而不是 if 语句。根据动作进行切换。它将更具可读性。

case ($action)
{
   'confirm':
      //do confirm stuff
      break;

   'makeoffer':
       // do offer stuff
       break;

   default:
      default stuff

}
于 2010-08-13T19:17:55.830 回答