Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: PHP: Tietojen lähettäminen tietokantaan, ilman muokkauksia

Sivun loppuun

AbuRamal [13.04.2021 17:00:56]

#

Voin heti alkuun todeta, etten ole perehtynyt PHP tai muuhunkaan backendiin nettisivuissa. Ongelma on typerä, mutta ehkä täällä joku osaa neuvoa.

Eli olen tehnyt javascriptillä eräänlaisen pelin. Pelin päätteeksi pelaaja voi lähettää pisteensä pistetaulukkoon MySQL tietokantaan. Käytännössä tämä järjestelmä toimii siten, että pisteet kirjoitetaan javascriptistä HTML formiin, joka lähetetään nappia painamalla PHP:n käsiteltäväksi. Ongelmana on kuitenkin se, että mm. selaimen devauskonsolista voi muokata HTML:ää tai javascriptiä ja näin muokata pisteitään.

Miten ongelmaa kannattaisi lähestyä? Tuskin ainakaan bäkkärissä olevalla PHP voi tarkastaa, onko jotain muokattu frontissa. Pelin pitäisi ilmeisesti jotenkin suoraan siirtää tiedot tietokantaan siten, että niitä ei voida muokata HTML:n tai javascriptin kautta.

PHP:tä joudun käyttämään, koska käyttämälläni alustalla se on ainoa käytettävissä oleva backend kieli.

noutti [13.04.2021 18:05:55]

#

Et oikein mitenkään. Lähes kaikki mitä teet frontissa voidaan muokata, kun se tulee backendiin. Itseasiassa ei nyt suorilta käsin tule juuri yhtään tilannetta, jossa fronttia ei pysty manipuloimaan. Viimeistään Postmanilla esimerkiksi pystyy tekemään lähes mitä tahansa.

Kysymyksen asettelusi on siis hieman väärä. Oikea ongelma on se, että miten pystyt lähettämään backendiin tavaraa, joka on suurella todennäköisyydellä validia.

Ratkaisuja voisi olla muutama, mutta yksikään niistä ei ole 100% validi.

Jos haluaisin nopeasti jonkun järjestelmän tällä stackilla tehdä etenisin näin:

1. Käyttäjä tulee sivulla. Backendiin generoidaan satunnainen avain, joka lähetetään fronttiin siten, että sen arvo asetetaan formin inputiin, joka on asetettu hiddeniksi.
2. Tämän jälkeen käyttäjä pelaa peliä ja saavuttaa pisteensä
3. Pisteet asetetaan formiin hiddeniksi jonkun salausalgoritmin avulla, jonka avaimena tuo backendissa oleva avain on.
4. Backendissä kyseinen salattu avain puretaan ja saadaan pistemäärä, joka tallennetaan tietokantaan, jossa tuo satunnainen avain on jo valmiina odottamassa käyttäjän nimeä ja pisteitä.

Tämä ei tietenkään estä edelleenkään sitä, että asiaan vihkiytynyt kaveri ei pystyisi heittelemään omia pisteitään perus POST pyynnöillä, mutta lisää vaikeusastetta tällaisten väärinkäytösten toteuttamiseen. Esimerkiksi CryptoJS tarjoaa fronttiin muutamia algoritmeja asioiden piilotteluun.

AbuRamal [13.04.2021 18:14:56]

#

Juu tuo kysymyksen asettelu oli hieman kömpelö, anteeksi siitä.

Kiitos vastauksestasi, varmaan omaan ratkaisuuni paras vaihtoehto on juuri tuo minkä esittelit. Kyse ei onneksi ole elintärkeästä datasta.

noutti [13.04.2021 18:24:33]

#

Jos on mahdollista niin voit myös päästä helpommalla siten, että injektoit dynaamisia piilotettuja hidden fieldejä formiin satunnaisilla arvoilla vaikka sen kaksikymmentä kappaletta, joista ainoastaan yhdessä on se pistemäärä. Ratkaisuja on monia, kun jäin oikein miettimään. Mutta alleviivaan, että yksikään ei ole immuuni väärinkäytöksille. Mutta ei kannata siitä ainakaan helppoa tehdä. Mielikuvitus rajana!

The Alchemist [14.04.2021 07:44:31]

#

noutti kirjoitti:

Jos haluaisin nopeasti jonkun järjestelmän tällä stackilla tehdä etenisin näin:

1. Käyttäjä tulee sivulla. Backendiin generoidaan satunnainen avain, joka lähetetään fronttiin siten, että sen arvo asetetaan formin inputiin, joka on asetettu hiddeniksi.
2. Tämän jälkeen käyttäjä pelaa peliä ja saavuttaa pisteensä
3. Pisteet asetetaan formiin hiddeniksi jonkun salausalgoritmin avulla, jonka avaimena tuo backendissa oleva avain on.
4. Backendissä kyseinen salattu avain puretaan ja saadaan pistemäärä, joka tallennetaan tietokantaan, jossa tuo satunnainen avain on jo valmiina odottamassa käyttäjän nimeä ja pisteitä.

Kohdat 1) ja 3) ovat ristiriidassa keskenään. Avain ei ole backendissa vaan se on siinä HTML-lomakkeella, mistä sen voi kaivaa kuka tahansa. Se on siis täysin hyödytön, joten voit jättää avaimen ja pseudosalauksen kokonaan tekemättä. Näennäinen tietoturva on jopa huonompi vaihtoehto kuin tiedostettu nollatietoturva, koska silloin suljet silmäsi järjestelmän vioilta sen sijaan että ymmärtäisit järjestelmän olevan turvaton ja että mitä riskejä siihen liittyy.

Oikea vastaus on ettei ole mitään yksikäsitteistä tapaa varmistaa, että yksittäinen käyttäjältä (lue: selaimelta) tuleva arvo olisi totuudenmukainen.

Jos haluat varmistaa, että käyttäjän ilmoittama pistemäärä on oikeasti saavutettu pelaamalla, niin sinun täytyy tällöin ottaa ns. snapshotteja pelitilanteesta ja lähettää ne pistemäärän mukana palvelimelle. Näistä snapshoteista voit palvelimella regeneroida pelitilanteet uusiksi (pikakelauksena) ja varmistaa, että pistemäärä täsmää pelin oikeaan lopputulokseen.

Tällöinkään et tietenkään voi olla varma siitä, että peliä olisi oikeasti pelannut ihminen eikä selaimeen skriptaamalla toteutettu botti. Snapshottien arvoista voit toki päätellä tilastollisia menetelmiä käyttäen, kuinka todennäköistä on, että pelin on pelannut ihminen eikä tekoäly.

The Alchemist [14.04.2021 07:55:44]

#

noutti kirjoitti:

(13.04.2021 18:24:33): Jos on mahdollista niin voit myös päästä...

Minä en tajua, mikä ihmeen fetissi sinulla on näihin lomakekenttiin. Datan upottaminen lomakkeelle tekee väärinkäytöksistä paljon helpompaa, kun kuka tahansa jonne voi katsoa HTML-koodia ja tehdä sinne suoraan muutokset. Aavistuksen vaikeampaa asiasta tulee, kun arvot pidetään visusti JS-koodissa ja kommunikointi selaimen ja palvelimen välillä suoritetaan "lomakkeiden sijaan" AJAX-pyynnöillä.

Mutta tämäkin on lähinnä kosmeettinen muutos ja nojaa siihen seikkaan, että suurempi osa ihmisistä osaa lukea ja manipuloida HTML-lomaketta kuin väärentää AJAX-pyyntöjä. Jos HTML-lomakkeiden väärentämisen vaikeusaste on 1/10, niin ehdottamani ratkaisun vaikeusaste on ehkä 1,5/10.

Yhdistettynä aiemmin mainitsemaasi salausavaimeen vaikeusaste voi nousta parikin pinnaa.

_Pete_ [14.04.2021 08:26:17]

#

Tämä on kyllä sellainen ongelma johon pitäisi oitis puuttua myös eräässä suomen parhaassa peliprojektissa! Aluksi pitää selvittää luvat !!

noutti [14.04.2021 09:56:18]

#

Minun fetissini juontaa juurensa siitä, että a) en näe tätä projektia sellaisena, joka vaarantaa ihmisten tietoturvan b) koodi on jo tehty siten, että formilla lähetetään eli se on valmis c) AP ei todennäköisesti vielä ole siinä pisteessä urallaan, että olisi järkevää piilottaa esimerkiksi auth-headeriin nuo tiedot esimerkiksi jollain tavalla. Toki on järkevintä hoitaa kaikki serveripuolella, mutta jos kysytään frontista lähtevän salauksen mahdollisuutta niin kannattaa tehdä siitä omaksutuilla työkaluilla vaikeasti murrettava.

Älä yritä the_alchemist päteä, kun varsin hyvin tiedät lähtötilanteen.

Metabolix [14.04.2021 10:24:13]

#

Kuten The Alchemist totesi, lomaketta ja JS:ää voi muokata ja salausavain on joka tapauksessa myös selaimessa. Ei kannata käyttää aikaa kikkailuun (kuten johonkin ylimääräisiin lomakkeen kenttiin), koska siihen todella helposti menee paljon aikaa ja hyöty on minimaalinen. Ongelmaa kannattaa lähestyä siltä kannalta, mitä ihmiset todennäköisesti osaavat eli millaisia väärinkäytöksiä halutaan estää.

HTML-lomakkeen muokkaus ennen lähetystä on helppoa (vaikka siinä olisi ylimääräisiä syötekenttiä), joten tietoja ei kannata laittaa HTML-lomakkeelle, vaan ne kannattaa lähettää suoraan JavaScriptilla. Tämä muutos ei ole kovin vaikea, tästä on myös koodivinkki.

Selaimen työkaluilla voi helposti katsoa lähetyksiä ja muokata ja lähettää uudestaan, joten jonkinlainen rajoitus tähän tarvitaan. Palvelin voisi antaa pelin alussa satunnaisen tunnuksen, jolla voi lähettää tasan yhden tuloksen jonkin kohtuullisen ajan kuluessa. Palvelin voisi myös tarkastaa, että pistemäärä on järkevä suhteessa käytettyyn aikaan.

Näiden toimien jälkeen huijaus vaatii jo JavaScriptin muokkaamista. Tässä tietysti ensimmäinen askel on julkaistun koodin obfuskointi jollain työkalulla, minkä jälkeen muokkaaminen on jo vaikeaa. (Tosin avoimen lähdekoodin tuotteessa tämä ei ole järkevää.) Salaus ei kannata, koska käyttäjä voi yhtä hyvin muuttaa JS-koodissa dataa jo ennen salausta tai vaikka muuttaa pelin koodista sitä kohtaa, jossa pistemäärä lasketaan. Ainakin jos itse haluaisin huijata JS-pelissä, helpoin huijauksen kohde olisi vaihtaa pistemäärän laskuun 1 pisteen tilalle 2 pistettä tai helpottaa peliä esimerkiksi estämällä oma häviö ennen tiettyä aikarajaa. Tällaisen huijauksen voi estää varmasti vain sillä, että pelin kulku tallennetaan ja tarkastetaan palvelimella. Riippuu pelistä, miten tämä onnistuu.

Jos peli on deterministinen (eli samat toiminnot johtavat aina samaan tulokseen) ja tarpeeksi kevyt, voi tallentaa lähtötilanteen (esim. satunnaislukujen siemenen) ja tallentaa käyttäjän siirrot ja näiden perusteella ajaa pelin uudestaan palvelimella. Tein tällä tavalla tuossa vuoden 2020 pelikilpailun Ravintoketju-pelissä, joka on vuoropohjainen ja ruudukossa pelattava ja sikäli helppo ajaa palvelimella.

Toinen vaihtoehto on tallentaa pelin aikana pelitilanteiden olennaisia tietoja ja arvioida palvelimella, onko peli voinut oikeasti mennä niin. Tämä voisi tulla kyseeseen vaikka jossain rallipelissä, jossa voisi tietää auton maksimikiihtyvyyden ja -nopeuden ja voisi laskea, onko edes mahdollista päästä tietyssä ajassa tietystä paikasta toiseen. Tässä pitää tietysti varmistaa, että arvio ei ole koskaan liian tiukka (että hylättäisiin oikeita tuloksia), ja toisaalta aina jää varaa tarkasti suunnitellulle huijaukselle, koska on olemassa jokin tarkastuksen rajoihin sopiva ”täydellinen suoritus”.

Tekoälyn käyttöä ei voi estää juuri mitenkään. Tilastollisesti voi jotain arvailla, mutta siinä on varmasti suuri väärän arvion mahdollisuus, ja silloinkin tekoälyn voi tehdä niin, että se ei pelaa peliä yksinään vaan vain auttaa joissain kriittisissä kohdissa.

Grez [14.04.2021 10:35:14]

#

noutti kirjoitti:

jos kysytään frontista lähtevän salauksen mahdollisuutta niin kannattaa tehdä siitä omaksutuilla työkaluilla vaikeasti murrettava.

Jos kysytään frontista lähtevän salauksen mahdollisuutta niin järkevää on todeta että frontissa ei ole mahdollista salata (käyttäjältä) mitään, mutta toimintaa voidaan obfuskoida (eli tehdä sen tulkinnasta työläämpää). Näin pysyy ymmärrys realiteeteista kunnossa.

The Alchemist [14.04.2021 11:21:25]

#

noutti kirjoitti:

Minun fetissini juontaa juurensa siitä, että a) en näe tätä projektia sellaisena, joka vaarantaa ihmisten tietoturvan b) koodi on jo tehty siten, että formilla lähetetään eli se on valmis c) AP ei todennäköisesti vielä ole siinä pisteessä urallaan, että olisi järkevää piilottaa esimerkiksi auth-headeriin nuo tiedot esimerkiksi jollain tavalla. Toki on järkevintä hoitaa kaikki serveripuolella, mutta jos kysytään frontista lähtevän salauksen mahdollisuutta niin kannattaa tehdä siitä omaksutuilla työkaluilla vaikeasti murrettava.

Ehdotit aika turhanpäiväistä näpertelyä, joka ei edes hidasta juurikaan edes varhaisteinejä, saati että estäisi heitä säätämästä pisteytyksen haluamakseen. Salausavaimella ei ole mitään merkitystä, jos lomaketta käyttäen voi muuttaa lähtöarvot haluamikseen.

Kun lähetettävät arvot siirretään lomakkeelta JS-koodiin eli "sovelluksen sisälle", niin vaikeusaste nousee välittömästi merkittävällä tavalla. Tällöin ns. hyökkääjän täytyy joko osata muokata sovelluksen lähdekoodia kohtalaisen monimutkaisella tavalla, tai vaihtoehtoisesti osata väärentää lähettävät HTTP-pyynnöt, mikä myös vaatii kehittynyttä ohjelmointitaitoa, varsinkin jos sovelluksen lähdekoodi on obfuskoitu / minimoitu. (Tarkoitan tilannetta, missä käytetään jonkinlaista salausmenetelmää sen sijaan, että lähetettäisiin kentät ja arvot selkokielisinä.)

Se, että sovellus on nyt tehty käyttämään tiedonvälitykseen HTML-lomakkeita, ei oikeastaan ole mikään pointti. Tämän kohdan muuttaminen on hyvin yksinkertaista, kunhan käyttää vähän aikaa ymmärtääkseen sen, miten lomakkeen lähettäminen ja ns. perinteinen AJAX-pyyntö eroavat toisistaan. On aika yksinkertaista lähettää "HTML-lomakkeelta näyttävä", dynaamisesti generoitu ns. AJAX-kutsu, jolloin backendin koodiin ei tarvitse koskea lainkaan, kun viestien formaatti pysyy samana.

Authorization-otsaketta ei tähän kannata sotkea, se ei liity asiaan mitenkään. Sillä voisi paremminkin korvata sessiotunnisteen sisältävän evästeen.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta