Door Joost Schellevis

Redacteur

Sql-injectie en xss: de beste verdediging

Inleiding

Het is je misschien opgevallen dat we op Tweakers.net de laatste tijd nogal vaak over datalekken schrijven. Recent behandelden we nog beveiligingsproblemen op de websites van het Spoorwegmuseum, een aantal supermarkten, Kluwer en Tivoli. De genoemde beveiligingslekken hebben één ding gemeen: ze zijn allemaal veroorzaakt door sql-injectie.

Sql-injectie is een van de aanvalsmethoden die een hacker kan gebruiken als gebruikersinvoer op een website niet met voldoende zorg wordt behandeld. Ook cross site scripting wordt daardoor veroorzaakt. Deze problemen zijn al jaren bekend, maar toch blijken er keer op keer websites kwetsbaar voor te zijn.

Dat het een groot probleem is, blijkt ook uit de top-10 van beveiligingsrisico's die het Open Web Application Security Project opstelde. Injecties, waaronder die van sql, staan op de eerste plaats.

Veel ontwikkelaars lijken dus niet of niet goed genoeg te weten wat sql-injectie is en hoe het kan worden voorkomen. Vandaar dat we het in dit artikel nog één keer uitleggen: wat zijn deze problemen, hoe worden ze veroorzaakt en hoe kunnen ze worden voorkomen?

We richten ons in dit artikel vooral op de talen PHP en MySQL, hoewel het probleem ook bij andere programmeertalen en databasesoftware speelt. PHP en MySQL treffen we echter het meest aan bij datalekken waarbij sql-injectie een rol speelt.

Bron: XKCD.

Sql-injecties en xss

Om uit te leggen wat sql-injectie is, is enige kennis van programmeertalen nodig. Programmeertalen maken gebruik van strings - simpel gezegd: een verzameling karakters in een bepaalde volgorde. Strings die veranderd kunnen worden, worden variabelen genoemd.

Veel ontwikkelaars maken gebruik van variabele strings om database-opdrachten samen te stellen. Daardoor kan zo'n opdracht dynamisch worden aangepast, bijvoorbeeld als een gebruiker een bepaalde pagina wil opvragen. Voor een inlogsysteem waarbij gebruikersnaam en wachtwoord moeten worden gecontroleerd, zou je bijvoorbeeld de volgende serie opdrachten kunnen gebruiken:

Een normale gebruiker vult gewoon zijn gebruikersnaam en wachtwoord in om in te loggen. In de eerste twee statements wordt uitgelezen wat deze gebruiker heeft ingevoerd. In de derde opdracht (die hier voor de leesbaarheid op twee regels staat) wordt, aan de hand van de invoer, een string met een sql-opdracht samengesteld. De laatste twee opdrachten voeren deze query uit en controleren of de invoer het gewenste resultaat oplevert.

Een kwaadwillende gebruiker doet het anders. Stel dat die kwaadwillende gebruiker wil inloggen met de username 'Joost', dan hoeft hij in het loginveld enkel Joost' -- in te voeren om MySQL om de tuin te leiden. Dat is een sql-injectie.

Het invoerveld $username is namelijk bedoeld voor pure data, maar door de apostrof toe te voegen, worden de twee koppeltekens door MySQL geïnterpreteerd als een deel van de opdracht, om precies te zijn: "dit is het einde van de opdracht; negeer de rest van de regel." Het gedeelte van de opdracht waarin wordt gecontroleerd of het wachtwoord bij deze user correct is opgegeven, wordt zo overgeslagen. Als we aannemen dat er maar één username 'Joost' is - en dat wordt vrijwel altijd door de database afgedwongen - bevestigt de laatste opdracht uit het codeblok altijd dat naam en wachtwoord bij elkaar horen. Het wachtwoord is dan echter niet daadwerkelijk gecontroleerd.

Er kunnen natuurlijk ook andere opdrachten aan de query worden toegevoegd. Via sql-injectie kunnen zo complete databases worden geplunderd of gemanipuleerd. Dat is geen theoretisch probleem: het gebeurt dagelijks. Het misbruiken van sql-injectie is simpeler dan op het eerste gezicht lijkt, want er zijn kant-en-klare tools die het zware werk doen.

Bij die tools zijn het invoeren van een url en een paar drukken op de knop voldoende: de software gaat dan op zoek naar kwetsbaarheden en, indien aanwezig, slurpt deze desgewenst de hele database leeg. De effectiviteit verschilt van geval tot geval, maar over het algemeen geldt: als een website lek is, is het gebruiken van deze software kinderlijk eenvoudig.

Cross site scripting

Cross site scripting - vaak afgekort tot xss - is een vergelijkbaar probleem, dat opduikt wanneer user-input wordt verwerkt in de html-output. Een simpel voorbeeld is bij slecht gebouwde zoekmachines te zien. Als een gebruiker daar <script>alert('hoi');</script> als zoekterm invoert, wordt er niet op die term gezocht, maar wordt het javascript uitgevoerd: er verschijnt een pop-up.

Een kwaadwillende kan een url zo opstellen dat een argeloze gebruiker die erop klikt, ongewild een script laat uitvoeren. Dat script heeft dan toegang tot alle gegevens waar die gebruiker toegang toe heeft. Zo kunnen bijvoorbeeld cookies worden gestolen. Soms kunnen ook variabelen worden gebruikt die aan andere gebruikers worden getoond. Als een forum bijvoorbeeld niet goed is beveiligd, kan een kwaadwillende een script in een posting opnemen, maar ook bijvoorbeeld in zijn username.

Xss kan ook worden misbruikt om beveiligingsproblemen in browsers te misbruiken, bijvoorbeeld door een Flash- of javascript-kwetsbaarheid te injecteren. Vooral input die aan andere gebruikers wordt getoond is daarvoor gevoelig.

Vertrouw nooit een gebruiker

"Het probleem is dat het al bij de start misgaat", zei HP-beveiligingsonderzoeker Alexander Hoole op de RSA Conference, een beveiligingsconferentie die eind februari in San Francisco van start ging. Hoewel sql-injectie vrij eenvoudig te voorkomen is, ontbreekt bij programmeurs toch vaak de benodigde kennis: "In leerboeken staat het al fout."

mysql_real_escape_string

De belangrijkste les is: wantrouw alle data die van de gebruiker afkomstig is. Het beste is om altijd aan te nemen dat een gebruiker te kwader trouw is - de kans dat een van de bezoekers dat ook daadwerkelijk ís, is gezien het grote aantal datalekken redelijk groot.

Om te voorkomen dat MySQL-opdrachten in een variabele worden verstopt, kan in PHP de functie mysql_real_escape_string worden gebruikt. Die zorgt ervoor dat bepaalde karakters, waarmee het onderscheid tussen data en MySQL-code worden gemaakt, onschadelijk worden gemaakt. Dit noemt men 'escaping': voor een teken als een apostrof wordt dan een backslash geplaatst, zodat dat teken door MySQL als data wordt gezien, en niet als deel van de query.

Deze opdracht zou voldoende moeten zijn om sql-injecties af te vangen. Het is van belang mysql_real_escape_string op het allerlaatste moment toe te passen: zo wordt voorkomen dat andere, latere bewerkingen nog onverwachte en mogelijk schadelijke resultaten opleveren.

htmlspecialchars

Een vergelijkbare functie is er in php voor het bewerken van user-input voordat deze in html wordt getoond: met htmlspecialchars worden karakters als '<', '>' en aanhalingstekens vervangen door html-entiteiten, zodat ze door de browser niet als onderdeel van de html-code worden verwerkt. Dit geldt voor alle input die van gebruikers afkomt en niet alleen voor invoervelden die zichtbaar zijn voor de gebruiker. Xss-scripts zijn hiermee effectief tegen te gaan.

Maar uiteindelijk is bescherming tegen kwaadaardige code, hoe noodzakelijk ook, niet genoeg. De website Just-Eat.nl, waar mensen eten kunnen laten thuisbezorgen, liet het bedrag dat mensen moesten betalen door de browser van de gebruiker uitrekenen. Vervolgens werd bedrag dat naar de server gestuurd in een verborgen html-invoer-veld. 'Onzichtbaar' is echter niet hetzelfde als 'niet aan te passen': gebruikers konden het bedrag zelf veranderen en hoefden bijvoorbeeld maar een paar cent voor een complete maaltijd te betalen. Just-Eat.nl vertrouwde erop dat de data van de gebruiker correct was - en dat is dus altijd fout.

Voorbereiding

Sql-query's kunnen ook eerst aan de server worden aangeboden om later pas van variabelen te voorzien; dat worden 'prepared statements' genoemd. Hiermee zorg je er voor dat de server precies weet welke variabelen op welke plek moeten staan, waarna de server op die plaatsen zelf de goede escaping en transformaties kan toepassen. Daarnaast zorgt dit bij herhaaldelijk gebruik van dezelfde query's voor prestatiewinst, omdat een deel van het werk van de databaseserver niet opnieuw hoeft te gebeuren.

In het geval van ons loginscript zou de sql-query er dan zo uitzien:

Prepared statement

Ook kun je de user-input onderwerpen aan bepaalde criteria. Als van een gebruiker een numerieke waarde wordt verwacht, bijvoorbeeld een id, controleer dan of de variabele inderdaad een getal is dat aan de eisen voldoet. Zo nee, dan is er waarschijnlijk wat aan de hand. Hiervoor kunnen bijvoorbeeld regular expressions worden gebruikt. Daarbij is whitelisting effectiever dan blacklisting: sta dus alleen bepaalde waarden toe, in plaats van dat je bepaalde waardes uitsluit.

Je eigen code testen kan ook veel problemen voorkomen. Gebruik bijvoorbeeld sqlmap om kwetsbaarheden te ontdekken. Om sql-injectie te voorkomen kan verder object-relational mapping worden gebruikt; onder php is dat bijvoorbeeld mogelijk met het Doctrine-framework. Ook andere ontwikkelframeworks bieden soms ingebouwde bescherming tegen sql-injectie, zoals bijvoorbeeld CodeIgniter. Voor Java is er het Hibernate-framework tegen sql-injectie en Apache Wicket tegen cross site scripting.

Het gebruik van mysql_real_escape_string, prepared statements en datatyping zorgt er alleen voor dat een gebruiker geen sql-query's kan injecteren; ze controleren niet of een ogenschijnlijk legitiem verzoek wel mag worden uitgevoerd. Als een gebruiker toegang heeft tot pagina.php?id=1, wil dat nog niet zeggen of hij ook pagina.php?id=2 zou moeten kunnen bezoeken. Zoals gezegd: er moet niet alleen op de technische geldigheid van een query worden gelet, maar ook op de inhoudelijke geldigheid.

Security through obscurity

Wat sowieso níet aan te raden is, is security through obscurity. Als je website bepaalde functionaliteit ondersteunt, is die functionaliteit per definitie kwetsbaar en moet je erop anticiperen dat deze uiteindelijk aangevallen zal worden.

Zo is het van belang om de database-account die voor een bepaalde transactie wordt gebruikt, niet te veel rechten toe te kennen. Voor het uitlezen van een nieuwsbericht is geen root-toegang tot de gehele database nodig, maar voldoet read-only toegang tot een deel van de database. Mocht er dan alsnog ergens een lek in de website zitten, dan zijn de gevolgen in elk geval beperkt.

Ook is het aan te raden om informatie alleen in een vanaf het web toegankelijke databaseserver op te slaan als dat strikt noodzakelijk is. Webwereld schreef enige tijd geleden over een vliegschool die zijn complete klantenadministratie op een webserver bijhield, waardoor talloze persoonsgegevens - van naw-gegevens tot BKR-noteringen - toegankelijk waren. Er is echter nauwelijks een reden te bedenken om zulke gegevens op een webserver op te slaan.

Tot slot

Uiteraard zijn er nog meer beveiligingproblemen waarbij input van anderen een rol speelt en waarbij input eveneens gevalideerd moeten worden. Zo is het uitwisselen van gegevens via bijvoorbeeld jsonp of xml-feeds een beveiligingsrisico: je moet jezelf er grondig van verzekeren dat de servers waarmee je communiceert, wel veilig zijn.

Ook zijn in dit artikel geen methoden behandeld om sql-injectie en cross site scripting in andere programmeertalen tegen te gaan. In andere talen spelen dezelfde problemen, maar zijn de gevolgen en de oplossingen soms heel verschillend. Zo is sql-injectie in ASP.NET wel een bestaand probleem, maar zijn er andere manieren om het af te vangen, bijvoorbeeld door het gebruik van Linq.

Voor de gemiddelde programmeur die echter even een PHP/MySQL-website in elkaar wil flansen - en daar zijn er nogal wat van - mag de les duidelijk zijn: wantrouw de gegevens die van de gebruiker afkomstig zijn, wees selectief met wat je in je database opslaat en hou rekening met het ergste. Een paranoïde programmeur heeft bijna altijd gelijk.

Reacties (259)

259
253
115
21
1
113
Wijzig sortering
Ik had toch liever gezien dat prepared statements eerder aan bod kwamen / als belangrijker / beter beschreven worden dan mysql_real_escape_string; sterker nog, eigenlijk zou het helemaal niet uitgelegd moeten worden (of slechts als een voetnoot) in de verschillende tutorials dat je een SQL statement gewoon kunt maken door je strings in je query te pleuren.

Prepared statements: 100% veilig, betere performance, en leesbaarder code. Ik begrijp niet waarom mensen nog anders zouden willen.
Door inderdaad met bind variabelen te werken, hoeft het sql statement niet steeds opnieuw geparsed te worden. Bij de meeste databases levert dit een behoorlijke performance winst op, omdat eigenlijk maar een paar verschillende queries vanuit de website afgevuurd worden, met alleen andere waarden voor de bind variabelen.
Ben het hier volledig mee eens. Het handmatig aan elkaar plakken van query strings is echt niet meer van deze tijd en is gewoon altijd gevaarlijk, ook al weten alle programmeurs die aan het project werken dat ze input sanitation moeten toepassen. Je kan gewoon niet 100% afvangen dat het ergens in een grote codebase niet een keer fout gaat. En waarom zou je überhaupt het risico willen lopen als het alternatief nog andere voordelen met zich mee brengt zoals betere performance.

In de tijd dat PHP5 net uit was kan ik me nog voorstellen dat er redenen waren om niet de mysqli interface te gebruiken (aangezien veel providers tergend traag zijn met het ondersteunen van nieuwe PHP versies), maar zo langzamerhand kan dat toch echt geen argument meer zijn. Als je nu nog steeds bij een host zit die alleen maar PHP4 draait dan is het echt tijd om te verhuizen naar een provider die security wat meer serieus neemt.
Even een ASP.Net aanvulling:

Als je om wat voor reden dan ook geen gebruik wilt maken van Linq2Sql of het entity framework (en daar kan ik er wel een paar van bedenken), kan je gewoon de Parameters property van de SqlCommand class gebruiken. Op deze manier word er in ieder geval gechecked op sql injection.

Je kan eventuele input encoden door de HttpUtility class te gebruiken, waarmee je in ieder geval heel eenvoudig XSS kan voorkomen. Het is niet altijd de mooiste manier. Als een aanvaller bijvoorbeeld een <script> block invoert in een veld wat anders direct naar je html gerenderd word, zal dit script block leesbaar worden weergegeven in je pagina... maar het word tenminste niet uitgevoerd en daar gaat het om!

[Reactie gewijzigd door Laurens-R op 19 maart 2012 12:04]

Goede aanvulling!

De SqlCommand class gebruiken in combinatie met Parameters doet grofweg hetzelfde als de 'prepared statements' waarover gesproken wordt in het artikel; het houdt sql-injection tegen omdat de escaping geheel automatisch gaat. Het heet alleen 'parametrized queries' of 'parametrized statements'. Eventueel zou je ze in sommige situaties ook kunnen preparen, waardoor je exact hetzelfde krijgt. In elk geval bieden beide technieken een automatische bescherming tegen sql-injection.
Daarnaast natuurlijk een goed ingerichte database met stored procedures. Nog veiliger :)
Als extra: als je het Webforms framework van ASP.NET nog gebruikt:

De meeste controls al HTML escaping ingebakken. Als je de '.Text' eigenschap van een `<asp:TextBox>` aanpast, zal dit al geescaped eruit komen. Wat echter niet geescaped is, is de het `<asp:Label>` control. Hiermee kun je XSS mogelijk gemaakt hebben in de ASP.NET website.

Gebruik daarvoor `<asp:Label Mode="Encode">`, of gebruik de `HttpServerUtility.HtmlEncode` functie.

[Reactie gewijzigd door YaPP op 19 maart 2012 20:39]

Leuk artikel, de uitleg is makkelijk genoeg zodat het ruimte overlaat voor verder onderzoek.
Ik kan ook iedereen het boek Essential PHP Security aanbevelen. Hier staan veel tips in over hoe je als programmeur moet denken bij het maken van een veilige applicatie.
Maar pas op. Denk na het toepassen van beschreven maatregelen niet dat je website veilig is. Er zijn nog vele andere manieren waarop een website/database gehacked of gedefaced kan worden. Dan is dat boek van o'Reilly een aanrader.
Is inderdaad echt een aanrader. Het enige jammere vind ik de naam, beter was "Essential web application security" met als voetnoot, "explained using PHP". De taal is wat mij betreft van ondergeschikt belang, ook programmeurs die gebruik maken van een andere taal dan PHP zullen veel aan dit boek hebben.
Idd, veilig ben je nooit: Wij passen dit ook standaard toe (en nog wel meer), zijn uitermate strikt in acceptatie van externe scripts, hebben ook wel een goed geconfigureerde fail2ban, ssh (via ander poort) op gelimiteerde IP's, hard- en software firwall (csf),een rkhunter (doen!), fatsoenlijk user-beheer met weinig rechten en updaten apache/php/mysql/linux ongeveer om de week, maar toch nog een 0-day exploit via (waarschijnlijk) Apache opgelopen rond januari.

't is dat wij de logging op een externe server doen, anders hadden we het niet eens snel gemerkt dat er een keylogger (en nog wat meer rotzooi) was geinstalleerd op één van onze servers door een Koreaans IP-adres.

Maar goed, mocht je professionele aspiraties hebben en je de gevaren van (alleen al) sql-injection onderschat, reken dan maar op problemen in de nabije toekomst.
De database connectie die je gebruikt in je site moet je ook limiteren qua rechten. Een database connectie voor een website (inlog form, zoekopdrachten, etc) heeft echt geen DROP of DELETE rechten nodig.
Inderdaad: een nuttige uitbreiding op het artikel, maar zo zijn er nog, bvb dat de website laat uitschijnen dat user input enkel kan via invoervelden, maar ook de URL die geparsed wordt naar variabelen via $_GET kan door de gebruiker worden gewijzigd...

Ik vind het overall een zeer goed artikel, maar imho mag in de conclusie iets meer nadruk gelegd worden op het feit dat het hiermee niet gedaan is. De meeste reacties hier komen van mensen die dit reeds weten, maar het artikel heeft het meeste nut voor de beginnende programmeurs die online alles gaan leren.

Ik ben zelf geen beginner meer, maar ik vrees dat mijn applicaties niet volledig afgesloten zijn, ook al heb ik al specifieke boeken gelezen over de beveiliging van PHP-code...
Anoniem: 201824
@zkotz19 maart 2012 14:01
En een SELECT username LIMIT/TOP 1, scheelt misschien ook als je het over tabel inhoud op het scherm toveren hebt. Je maakt het denk ik wel wat lastiger daardoor, zo niet onmogelijk om een tabel uit te lezen.
Edit: parameters gebruiken is natuurlijk veel veiliger, zodat er geen select ster gedaan kan worden.

[Reactie gewijzigd door Anoniem: 201824 op 19 maart 2012 14:28]

Volgensmij is het voorbeeldje met prepared statements niet goed, dat zou moeten zijn:

$stmt->bind_param('ss', $username, $password); $stmt->execute();

Tenzij de username een integer veld is, zoals bij ICQ

[Reactie gewijzigd door hafkensite op 19 maart 2012 08:24]

Correct, http://php.net/manual/en/mysqli-stmt.bind-param.php

Bizar dat de hier beschreven oplossingen al voldoende zouden moeten zijn: ik als 'scriptkiddie' heb een android programma in Google Play staan wat ook een PHP scriptje gebruikt voor trial verificatie. Ik laat de telefoon zijn ID sturen (OK, dat is inderdaad theoretisch aan te passen, maar da's wel erg moeilijk doen voor een programma van €1 ;)), en check vervolgens in mijn mysql database hoe lang die gebruiker nog het programma mag uitproberen gebaseerd op wanneer ie zich t eerst meldde.

Alles wat hier staat vond ik ook gewoon in de tutorials die ik heb gevolgd om mijn scriptje te maken, van de escape strings & prepared statements (ik gebruik ze beiden, dan moet t wel goed gaan ;)). Verder had ik ook zelf al bedacht dat whitelisten handig kan zijn, dus ik check met regex of het inderdaad een geldige android ID is door te kijken of de input gelijk is aan [0-F]{16}
Niks over CSRF tokens? :)

Edit:

Nou dan licht ik maar even toe,

Van http://www.squarefree.com.../web-developers.html#CSRF :

"A Cross-site request forgery hole is when a malicious site can cause a visitor's browser to make a request to your server that causes a change on the server. The server thinks that because the request comes with the user's cookies, the user wanted to submit that form."

Om dit tegen te gaan is het makkelijkste een zogenaamde CSRF token te genereren per formulier, deze dan te checken wanneer de formulier terugkomt. Zo is het zeker dat iemand op een andere site niet zomaar een request op jou site kan genereren.

Veel frameworks (bijv Django) hebben deze functionaliteit al ingebakken voor het gemak.

[Reactie gewijzigd door shadylog op 19 maart 2012 10:40]

Wat ik ook wel eens zie bij het gebruik van mysql_real_escape_string, is dat sommigen lijken te vergeten dat deze functie alleen van toepassing is op strings. Zodra je voor een query ints gaat escapen, zal deze methode niet goed werken.

voorbeeld:


$int = 3; // kan ook uit $_GET['id'] komen
mysql_query("SELECT * FROM user WHERE id = " . mysql_real_escape_string($int));


Hierboven is er nog niets aan de hand. Als ik er echter voor zorg dat ik 3 OR id = 4 invoer, zal dit niet ge-escaped worden. Het bevat namelijk geen gevaarlijke karakters.

offtopic:
Of wat YopY zegt, gebruik prepared statements. Dan heb je hier ook geen last van.

[Reactie gewijzigd door X_lawl_X op 19 maart 2012 12:00]

Maar dat heeft natuurlijk ook weer met input validatie te maken.
Overigens cast je dan je input naar het juiste type of knal hem door intval().
Een beetje zonde dat dit artikel totaal geen melding maakt van cross-site request forgery. Heb je een usersysteem dat hiervoor vatbaar is en waarbij gebruikers bijvoorbeeld hun emailadres of wachtwoord zonder problemen kunnen aanpassen, dan is de kans groot dat op kinderlijk eenvoudige wijze een (admin)account gekaapt kan worden en alle gegevens alsnog te benaderen zijn, ook al is de site bestand tegen XSS en injecties.

Stuurt een site niet voor elke user bij elk formulier een hidden form input mee met een unieke waarde die wordt gecontroleerd, dan is de site vrijwel zeker vatbaar.

Ook zonder HTML-code kunnen er verder bij sites met een bijvoorbeeld een slecht forum/gastenboek gevaarlijke situaties ontstaan. Een link die begint met javascript: of een site waarbij de GET variabelen worden gebruikt om data te submitten. Dat laatste is vooral bij oude PHP-sites die gebruik maken van global vars, een img-tag is dan al genoeg.

[Reactie gewijzigd door BarôZZa op 19 maart 2012 09:39]

Ik gebruik zelf HTML Purifier
HTML Purifier is a standards-compliant HTML filter library written in PHP. HTML Purifier will not only remove all malicious code (better known as XSS) with a thoroughly audited, secure yet permissive whitelist, it will also make sure your documents are standards compliant, something only achievable with a comprehensive knowledge of W3C's specifications. Tired of using BBCode due to the current landscape of deficient or insecure HTML filters? Have a WYSIWYG editor but never been able to use it? Looking for high-quality, standards-compliant, open-source components for that application you're building? HTML Purifier is for you!
Wat wel interessant is, is dat er wel een manier is om mysql_real_escape_string() te bypassen. Dit werkt alleen in bepaalde situaties waarin SET NAMES is gebruikt om de encoding aan te passen. Met een bepaalde reeks karakters (BIG5 of GBK) kun je de escape omzeilen en gewoon injecteren. Dit geldt alleen op oude MySQL versies en is al in 2006 opgelost, (zie bijv: http://bugs.mysql.com/bug.php?id=8378). Als je UTF-8 hanteert is er niets aan de hand. Beter nog zijn toch prepared statements.

Op basis van de lekken van de afgelopen tijd kun je wel stellen dat dit toch nog steeds een vulnerability kan zijn, met het over het algemeen zorgwekkend serverbeheer..
1 2 3 ... 8

Op dit item kan niet meer gereageerd worden.

Tweakers maakt gebruik van cookies

Tweakers plaatst functionele en analytische cookies voor het functioneren van de website en het verbeteren van de website-ervaring. Deze cookies zijn noodzakelijk. Om op Tweakers relevantere advertenties te tonen en om ingesloten content van derden te tonen (bijvoorbeeld video's), vragen we je toestemming. Via ingesloten content kunnen derde partijen diensten leveren en verbeteren, bezoekersstatistieken bijhouden, gepersonaliseerde content tonen, gerichte advertenties tonen en gebruikersprofielen opbouwen. Hiervoor worden apparaatgegevens, IP-adres, geolocatie en surfgedrag vastgelegd.

Meer informatie vind je in ons cookiebeleid.

Sluiten

Toestemming beheren

Hieronder kun je per doeleinde of partij toestemming geven of intrekken. Meer informatie vind je in ons cookiebeleid.

Functioneel en analytisch

Deze cookies zijn noodzakelijk voor het functioneren van de website en het verbeteren van de website-ervaring. Klik op het informatie-icoon voor meer informatie. Meer details

janee

    Relevantere advertenties

    Dit beperkt het aantal keer dat dezelfde advertentie getoond wordt (frequency capping) en maakt het mogelijk om binnen Tweakers contextuele advertenties te tonen op basis van pagina's die je hebt bezocht. Meer details

    Tweakers genereert een willekeurige unieke code als identifier. Deze data wordt niet gedeeld met adverteerders of andere derde partijen en je kunt niet buiten Tweakers gevolgd worden. Indien je bent ingelogd, wordt deze identifier gekoppeld aan je account. Indien je niet bent ingelogd, wordt deze identifier gekoppeld aan je sessie die maximaal 4 maanden actief blijft. Je kunt deze toestemming te allen tijde intrekken.

    Ingesloten content van derden

    Deze cookies kunnen door derde partijen geplaatst worden via ingesloten content. Klik op het informatie-icoon voor meer informatie over de verwerkingsdoeleinden. Meer details

    janee