0

这是一个简单的函数,它使用 AJAX 并在单击按钮时获取数据库中 id=219 的图像信息

任何加载此网页的人都可以通过转到源代码来更改 javascript 代码。然后通过单击按钮,他将运行修改后的代码(例如将 image_id 从 219 更改为 300)。所以他可以通过改变 image_id 来获取任何图像的信息

问题是如何防范客户端攻击或 XSS ?

function clicked () {
    var xhttp = new XMLHttpRequest () ;

    xhttp.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200){
            var obj = JSON.parse (this.responseText);
            alert (obj.description);
        }
    };

    xhttp.open ("POST","get_title_description.php", true);
    xhttp.setRequestHeader ("Content-type", "application/x-www-form-urlencoded");
    xhttp.send ("image_id=219") ;
}
4

1 回答 1

-1

您可以使用这样的东西来生成和验证 cookie:

define('COOKIE_TOKEN', 'my_token');

class BaseAuth
{
  protected $uid;

  private static function base64url_encode(string $s): string
  {
    return strtr($s,'+/=','-|_');
  }

  private static function base64url_decode(string $s): string
  {
    return strtr($s,'-|_','+/=');
  }

  // Encodes after encryption to ensure encrypted characters are URL-safe
  protected function token_encode(String $string): string
  {
    $iv_size = openssl_cipher_iv_length(TYPE_CRYPT);
    $iv = openssl_random_pseudo_bytes($iv_size);

    $encrypted_string = @openssl_encrypt($string, TYPE_CRYPT, SALT, 0, $iv);

    // Return initialization vector + encrypted string
    // We'll need the $iv when decoding.
    return self::base64url_encode($encrypted_string).'!'.self::base64url_encode(base64_encode($iv));
  }

  // Decodes from URL-safe before decryption
  protected function token_decode(String $string): string
  {
    // Extract the initialization vector from the encrypted string.
    list($encrypted_string, $iv) = explode('!', $string);
    $string = @openssl_decrypt(self::base64url_decode($encrypted_string), TYPE_CRYPT, SALT, 0, base64_decode(self::base64url_decode($iv)));
    return $string;
  }

  // performs log-out
  public function clear_cookie()
  {
    setcookie(COOKIE_TOKEN, '', time() - 300, '/api', '', FALSE, TRUE); // non-secure; HTTP-only
  }

  private function userIP(): string
  {
    return $_SERVER['REMOTE_ADDR'];
  }

  // validates Login token
  public function authorized(): bool
  {
    if(isset($_COOKIE[COOKIE_TOKEN]))
    {
      $stamp = time();
      $text = $this->token_decode($_COOKIE[COOKIE_TOKEN]);
      if($text != '')
      {
        $json = json_decode($text,TRUE);
        if(json_last_error() == JSON_ERROR_NONE)
        {
          if($json['at'] <= $stamp AND $json['exp'] > $stamp AND $json['ip'] == $this->userIP() AND $json['id'] != 0)
          {
            // check if user account is still active
            $res = $db->query("SELECT id,active,last_update,last_update > '".$json['last']."'::timestamptz AS expired FROM account WHERE id = ".$json['id']);
            $info = $db->fetch_assoc($res);
            if($info['active'] != 0)
            {
              if($info['expired'] == 0)
              {
                // extend the token lifetime
                $this->sendToken($info);
                $this->uid = $json['id'];
                return TRUE;
              }
            }
          }
        }
      }
      $this->clear_cookie();
    }
    return FALSE;
  }

  public function login(String $username, String $password): bool
  {
    $stm = $db-prepare("SELECT id,user_name AS username,user_pass,full_name,active,last_update,COALESCE(blocked_until,NOW()) > NOW() AS blocked 
      FROM account WHERE user_name = :user");
    $res = $stm->execute(array('user' => strtolower($json['username'])));
    if($res->rowCount())
    {
      $info = $db->fetch_assoc($res);
      if($info['active'] == 0)
      {
        // Account is disabled
        return FALSE;
      }
      elseif($info['blocked'] != 0)
      {
        // Blocked for 5 minutes - too many wrong passwords
        // extend the blocking
        $db->query("UPDATE account SET blocked_until = NOW() + INTERVAL 5 minute WHERE id = ".$info['id']);
        return FALSE;
      }
      elseif(!password_verify($password, $info['user_pass']))
      {
        // Wrong password OR username
        // block account
        $db->query("UPDATE account SET blocked_until = NOW() + INTERVAL 5 minute WHERE id = ".$info['id']);
        return FALSE;
      }
      else
      {
        unset($info['user_pass']);
        unset($info['blocked']);
        $this->sendToken($info);
        return TRUE;
      }
    }
  }
}

如果您不需要对用户进行身份验证和授权,而只需要随机的不可预测的图像 ID - 您可以简单地使用 UUID。

于 2020-03-23T09:09:48.423 回答