C # / PHP Как создать API, которым нельзя злоупотреблять - PullRequest
0 голосов
/ 11 июля 2020

Я делаю многопользовательскую игру Unity с сетевой системой Mirror. Я хочу хранить данные игроков, такие как инвентарь, текущее местоположение и т. Д. c. в базе данных (MySQL).

У меня есть HTTPS-защищенный сервер, клиент Unity и этот код для:

a) генерации подписи для запроса (C#)

    private const string SECRET_KEY_ALPHA = "alpha";
    private const string SECRET_KEY_BETA = "beta";

    private List<string> requestData;
    private string signature;

    public SignatureGenerator(List<string> requestData)
    {
        this.requestData = requestData;
    }

    public string GenerateSign()
    {
        this.signature = "";

        string bodyString = "";
        foreach(string dataPart in this.requestData)
        {
            bodyString += (dataPart + ".");
        }

        bodyString = EncryptMD5(bodyString);
        bodyString += SECRET_KEY_ALPHA;
        bodyString = EncryptSHA1(bodyString);

        this.signature = EncryptHmac(bodyString);

        return this.signature;
    }

    private String EncryptHmac(string combined)
    {
        Encoding ascii = Encoding.ASCII;
        HMACSHA256 hmac = new HMACSHA256(ascii.GetBytes(SECRET_KEY_BETA));
        return Convert.ToBase64String(hmac.ComputeHash(ascii.GetBytes(combined)));
    }

    private String EncryptMD5(string data)
    {
        using(MD5 md5 = MD5.Create())
        {
            byte[] dataBytes = Encoding.UTF8.GetBytes(data);
            byte[] md5Bytes = md5.ComputeHash(dataBytes);
            return BitConverter.ToString(md5Bytes).Replace("-", String.Empty);
        }
    }

    private String EncryptSHA1(string data)
    {
        using (SHA1Managed sha1 = new SHA1Managed())
        {
            var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(data));
            var sb = new StringBuilder(hash.Length * 2);

            foreach (byte b in hash)
            {
                sb.Append(b.ToString("X2"));
            }

            return sb.ToString();
        }
    }

б) проверка подписи на сервере

define('SECRET_KEY_ALPHA', 'alpha');
define('SECRET_KEY_BETA', 'beta');

class SignatureVerifier
{
    private $bodyString;
    private $providedSignature;
    private $result;

    /**
     * SignatureVerifier constructor.
     * @param $bodyString
     * @param $providedSignature
     */
    public function __construct($bodyString, $providedSignature)
    {
        $this->bodyString = $bodyString;
        $this->providedSignature = $providedSignature;
    }

    public static function generateBodyString($dataArray)
    {
        $result = '';
        foreach ($dataArray as $data)
        {
            $result .= ($data . '.');
        }
        return $result;
    }

    public function verify()
    {
        $generatedSign = sha1(md5($this->bodyString), SECRET_KEY_ALPHA);
        $generatedHmac = hash_hmac('sha256', $generatedSign, SECRET_KEY_BETA);

        $this->result = ($generatedHmac == $this->providedSignature);
    }

    public function success()
    {
        return $this->result;
    }
}

А что меня в этом не устраивает? У меня есть тело и подпись, так что мне еще нужно?

Моя проблема в том, что кто-то может поймать этот запрос (POST & знаки) и начать рассылать спам с этим запросом, чтобы получить некоторые элементы.

То, что я пробовал:

  • Добавить метку времени в подпись

Результат: запрос не будет выполнен, потому что мне придется отправлять и получать запросы быстрее, чем за секунду.

  • Добавить токен в запрос, то есть одноразовое использование (после создания нового использования)

Результат: если кто-то решит продать свой товар на рынке (веб-сайт) - токен изменится, и вся система будет повреждена, потому что игра использовала, а не работала, токен.

Резюме: чего я ожидаю?

Я ожидаю безопасного API использование клиента (Unity, C# игра) и сервера (Apache, PHP), которым нельзя злоупотреблять (рассылка спама с перехваченными запросами) и которые безопасны, поэтому я могу использовать его для управления инвентарем в игре, войдя в систему из игры эт c.

Надеюсь я вам предоставил все необходимые данные для решения моей проблемы. Если нужно еще что-то - комментарии.

Заранее спасибо за помощь.

1 Ответ

0 голосов
/ 12 июля 2020

Я выяснил, что может быть полезным. Сожалею, что не подумал об этом.

Дата истечения срока (метка времени)!

Включите в свой запрос И метку времени подписи, которая будет определять дату истечения срока действия запроса . Затем в сценарии PHP проверьте подпись и отметку времени (используйте один и тот же часовой пояс в обеих службах). Если текущая временная метка больше, чем указанная в запросе - отклонить запрос.

Определите, сколько времени должно быть истекло. Дата. Я рекомендую сделать несколько тестовых запросов, чтобы узнать, как долго игра связывается с API. Затем вовремя добавляйте к нему небольшую сумму (на случай более длительного запроса) и наслаждайтесь своим более защищенным API.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...