Numerotunnisteista merkkijonoihin

Minulla on työn alla pieni harrastekoodailuprojekti lautapelitapahtumien hallinnointiin. Siinä tapahtumilla on juokseva numerointi, jolla niihin viitataan: ensimmäinen tapahtuma aukeaa URLista index.php?e=1 ja niin edelleen. Projektia kanssani tekevä kaveri huomautti, että tässähän on ilmeinen ongelma: sovelluksella voi järjestää yksityisiä tapahtumia, mutta tuollaisilla ID-numeroilla mikään ei ole erityisen yksityistä, kun kokeilemalla on helppo käydä läpi numeroita ja katsoa, mitä löytyy.

Yksi tapa ratkaista tämä on generoida tapahtumille luontivaiheessa koodi, jota käytetään tunnisteena ja tallentaa se tietokantaan käyttöä varten. Tämä olisi toki ollut helppoa, mutta myös vähän tylsää. Päädyin toisenlaiseen ratkaisuun. Halusin jonkun koodauksen, joka tuottaisi pienistä kokonaisluvuista lyhyitä, sanotaan nelimerkkisiä tunnisteita, ja jossa tunnisteet olisi palautettavissa koodeiksi. Menetelmän pitää siis olla kaksisuuntainen, mutta samalla se ei saisi olla ihan ilmeinen, eikä tunnisteiden pitäisi olla helposti tulkittavissa.

Ratkaisu

Päädyin tällaiseen:

  1. Otetaan kirjaimisto, jossa ovat merkit A-Z, a-z ja 0-9.
  2. Alustetaan satunnaislukugeneraattori valitulla siemenarvolla.
  3. Sekoitetaan kirjaimistoa n kertaa, missä n on koodattava tunnistenumero.
  4. Otetaan kirjaimiston alusta 4 ensimmäistä merkkiä.

Toiseen suuntaan sitten tehdään samat alustukset ja sekoitetaan kirjaimistoa, kunnes sen alku vastaa purettavaa koodia. Sekoituskertojen määrästä selviää haettu numero.

Ensimmäinen ajatus oli käyttää satunnaislukugeneraattorin siemenenä jotain itse valittua numeroa, joka haettaisiin jostain asetustiedostosta (koska missään versionhallintaan säilötyssä tiedostossa se ei tietenkään ole), mutta keksin sitten, että numero voidaan generoida jostain palvelimen ominaisuudesta, kuten suoritettavan tiedoston polusta. Näin jokainen instanssi saa automaattisesti oman siemenarvonsa (haittapuolena siemenarvon vaihtaminen ei ole ihan helppoa).

Otan siis tiedoston polun $_SERVER['SCRIPT_FILENAME']-muuttujasta, lasken merkkien ASCII-arvot yhteen ja kerron sen vielä merkkijonon pituudella ihan huvin vuoksi.

Epäilemättä tällaisessa ratkaisussa, jossa tietty merkkijono koodautuu tietyksi numeroksi ja takaisin, on vaarana, että joku keksii, miten koodaus toimii. Olettaisin, ettei se kuitenkaan ole ihan helppoa: asiassa on jonkun verran muuttujia, joita ulkopuolisen on vaikea tietää. Pidemmän päälle edes haettua kohdenumeroa ei ole ihan helppo arvata, koska sovelluksen näkyvissä osissa näkee vain koodatun tunnisteen.

Sanoisin siis, että tämä vähintäänkin ajaa asiansa: tapahtumien läpikäyminen tunnisteita arvaamalla on vaadittuun tietoturvatasoon nähden aivan riittävän vaikeaa. En sitten tiedä, pystyisikö joku tekoälysovellus generoimaan oikeita tunnisteita, jos sille syöttäisi muutamia mallikappaleita, mutta en suoraan sanoen halua koskea tekoälyihin sen vertaa, että kysyisin (enkä erityisemmin halua, että kysyt puolestani, kiitos vain).

Koodia

function encodeID(int $id): string
{
  $alphabet = $this->getAlphabet();
  mt_srand($this->key_seed);
  for ($i = 0; $i < $id; $i++) {
    shuffle($alphabet);
  }
  $source = implode('', $alphabet);
  $key = substr($source, 0, 4);
  return $key;
}

function decodeID(string $key): int
{
  if (strlen($key) !== 4) {
    return 0;
  }
  $alphabet = array_merge(range('a', 'z'), range('A', 'Z'), range(0, 9));
  mt_srand($this->key_seed);
  $i = 0;
  do {
    $i++;
    shuffle($alphabet);
    $source = implode('', $alphabet);
  } while ($key !== substr($source, 0, 4));

  return $i;
}

function getAlphabet(): array
{
  return array_merge(range('a', 'z'), range('A', 'Z'), range(0, 9));
}

function createSeed(): int
{
  $path = str_replace('index.php', '', $_SERVER['SCRIPT_FILENAME']);
  $tokens = str_split($path, 1);
  return array_reduce($tokens, fn($c, $t) => $c + ord($t), 0) * strlen($path);
}

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *

This site uses Akismet to reduce spam. Learn how your comment data is processed.