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:
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.