Я делаю многопользовательскую игру 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.
Надеюсь я вам предоставил все необходимые данные для решения моей проблемы. Если нужно еще что-то - комментарии.
Заранее спасибо за помощь.