dan zal dat enkel kunnen als je nog niet gestemd hebt (button die de request laat starten is enkel dan zichtbaar). Maar als iemand nu in de broncode kijkt en die vult dit in z'n adresbalk ik:
www.mijnsite.com/poll_stemmen.php
dan zal deze nogmaals kunnen stemmen.
Nu is mijn vraag:
Is er een methode om te zorgen dat enkel dmv een AJAX request die pagina aangeroepen mag worden? Of is het echt noodzakelijk om alle controles (lid ingelogd, bestaat de poll, heb je al gestemd op die poll) opnieuw te doen? Of is er een andere manier?
Dus ik moet een sessie aanmaken als er op de button geklikt en op http://www.mijnsite.com/poll_verwerk.php controleren of deze sessie wel degelijk bestaat. Nu vormt het aanmaken van die sessie een probleem omdat de button Javascript meteen activeert en er dus geen tijd is voor nog PHP.
session_start();
if( isset( $_SESSION['voted'] ) && $_SESSION['voted'] == 1 ) {
echo 'sorry, je kan maar één keer stemmen';
} else {
//de hele vote verwerking code
//vergeet niet om $_SESSION['voted'] = 1; te doen als de verwerking compleet is.
}
Maar als men dan de browser afsluit is de sessie weg en kan met nog steeds / opnieuw het trucje uithalen. Dus ik denk dat dit geen goede oplossing is. Is er dus een andere oplossing? Of zie ik wat over het hoofd?
Zou je niet iets met headers kunnen doen. Ik heb geen flauw idee, maar misschien verschilt er iets aan de headers die mee worden gestuurt als AJAX een request uitvoert, of als je er rechstreeks heen gaat?
Voldermort, denk eens logisch na. Wat bewaard data langer dan een sessie.... idd een cookie en als je wilt dat het echt uniek wordt moet je met mysql werken en/of leden.
@Grayen: Geen idee. En daarbij kan men door snel even een programmaatje te schrijven de headers zelf bepalen (ok, er zijn niet velen die het ook echt zullen doen, maar je hebt er altijd die zo zot zijn het te doen).
@Stijn: Een cookie kan men verwijderen. Zal dus inderdaad toch database worden (controle of je de poll bestaat en daarna controle of je reeds gestemd hebt).
Het waren nu net die 2 dingen die ik wou proberen voorkomen:
- Geen extra data wegschrijven, niet naar de database en niet naar een bestand.
- Geen queries om dingen te controleren (Bestaat de poll wel? Heb je al gestemd?).
Maar aangezien het niet mogelijk is te controleren of de request van AJAX komt of dat de bezoeker het url in z'n adresbalk heeft ingevuld zonder gebruik te maken van 1 van deze 2 technieken heb ik gebruik gemaakt van de 2e.
Een random getal generen met Javascript tussen 1 en 1 000 000 000 000. Dan doe ik een request naar sessie.php die de key in een sessie stopt. Dan doe ik pas de request naar poll_verwerk.php (waarbij ik de key ook meestuur) en die controleert:
1) Bestaat de sessie?
2) Zoja, heeft de sessie de correcte waarde (vergelijkt de sessiewaarde met de meegestuurde waarde).
3) Zoja, dan is de request dmv AJAX gebeurt.
Maak een 'pollvote' een samengestelde sleutel van het pollid en de userid. Op die manier kan iemand nooit 2 keer stemmen op dezelfde poll omdat je dan 2 dezelfde primary keys hebt.
Wat betreft het "bestaat de poll wel" moet je dat gewoon controleren.
Nee, want dan zouden ze toch naar session.php kunnen gaan (ik neem aan dat je gegevens doorstuurt met een $_GET) en daar bijvoorbeeld session.php?key=101010 en dan hebben ze die sessie. Vervolgens gaan ze naar poll_verwerk.php?key=101010 en voila we kunnen gewoon stemmen . En wat de key is kunnen ze achterkomen door in de source te kijken. Kun je niet gewoon verbieden dan men rechtstreeks naar die bestanden gaat (denk aan .htaccess)?
Nog een mogelijkheid is proberen gebruik te maken van $_POST, die kunnen ze namelijk alleen doormiddel van een formulier creëren en als jij als ze al gestemd hebben ze geen formulier laat zien kunnen ze moeilijk nog eens stemmen.
AJAX POST request met bovenstaande gegenereerde key naar sessie.php
PHP:
Sessie.php ==> Kijk of er een key is meegestuurd. Zoja, maak de sessie met als value de key. Maak ook een cookie met de key. Over beide dient wel md5 en sha1 gegooit te worden.
Javascript:
AJAX request naar poll_verwerk.php
PHP:
poll_verwerk.php ==> Controleren of de sessie bestaat en gelijk is aan de waarde van de cookie. Aan het einde de sessie legen.
Maar het probleem hierbij is dat je dmv de source (het genereren van de key) en de cookie (gehashte waarde) een scriptje kan maken dat de md5 en sha1 van 1 tot 1 000 000 000 000 afgaat en die controleert met de cookie.
Deze optie kan dus niet. Is er geen andere optie?
Dat van die .htaccess vroeg ik me ook af. Ik denk van niet want JS laat dat bestand openen en aangezien JS client-side is, zal Apache dit behandelen als een nieuwe pagina die geopend wordt en niet als iets aparts. Dit DENK ik, mocht ik fout zijn en het inderdaad kunnen, laat het me dan weten.
Ik denk dat het het verstandigst is om gewoon te gaan werken met een extra query, want over hoeveel tijd hebben we het? 0,003 sec? Ik denk dat deze hele omweg meer tijd zal gaan kosten dan het uitvoeren van een enkele simpele query .
Je maakt het ietswat ingewikkeld. Ik weet niet wat de benchmarks zijn voor een ajax request naar een mysql server maar volgens mij duurd dit evenlang als je geen ajax zou gebruiken.
Ik zal eens zelf testen maar ik dacht zo dat je via $_SERVER['REQUEST_URI'] kijken of de URL in de adresbalk is ingevuld. Je moet dan na een succesvolle request in javascript die knop waarmee je kan voten uitschakelen anders kan met 2 of meerdere keren stemmen.
Hoe ook rekening met browsers waar JS is uitgeschakeld.
<?php
// index.php is de pagina waarvandaan het request word verzonden.
if(stristr($_SERVER['HTTP_REFERER'], 'index.php'))
{
# Poll updaten...
} else
{
# hack
}
?>
<?php
// index.php is de pagina waarvandaan het request word verzonden.
- Ga naar de poll.php pagina (waar het stemformulier staat).
- Ga daarna naar de poll_verwerk.php pagina.
Dan zal de REFERER toch ook poll.php zijn? Of ben ik nu fout?
Edit: Op php.net:
Citaat:
The address of the page (if any) which referred the user agent to the current page. This is set by the user agent. Not all user agents will set this, and some provide the ability to modify HTTP_REFERER as a feature. In short, it cannot really be trusted.
Dan kan men nog steeds hetzelfde trucje uithalen. Eerst naar de poll.php pagina (sessie krijgt de correcte waarde) en dan naar poll_verwerk.php (sessie heeft dan ook die correcte waarde).
Koppelen aan IP: Hoe moet ik dat dan doen? Vanals men op de button klikt wordt er meteen Javascript uitgevoerd (onclick), dus ik zou 2 requests moeten doen, maar dan kan men alsnog naar beide pagina's gaan.
Die poll is misschien niet zo belangrijk, maar als ik in andere onderdelen ook AJAX ga gebruiken wil ik niet dat iedereen door naar dat url te gaan een wijziging kan doen.
Ik heb lopen nadenken over jouw probleem en het enige antwoord waarop ik telkens kom is dat je persee die controlles moet uitvoeren. Want wat je met AJAX doet, moet je zien alsof jij een pagina bezoekt, alleen doet in dit geval de browser het. Bezoek jij een pagina op jouw site, dan worden ook eerst al deze controles uitgevoert, dus deze controles moeten ook worden uitgevoerd op de pagina die ajax voor je bezoekt. Je moet dus in gedachte houden dat de pagina die de browser voor je bezoekt gewoon exact hetzelfde is alsof jij een pagina zou bezoeken. De controles zijn dus noodzakelijk vanwege veiligheid van je site.