{"id":3958,"date":"2026-09-01T17:16:09","date_gmt":"2026-09-01T17:16:09","guid":{"rendered":"https:\/\/hackagora.com\/?p=3958"},"modified":"2026-09-15T11:18:26","modified_gmt":"2026-09-15T11:18:26","slug":"sql-injection-sqli-types-exploitation-and-security-best-practices","status":"publish","type":"post","link":"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/","title":{"rendered":"SQL Injection (SQLi): Types, Exploitation and Security Best Practices"},"content":{"rendered":"\n<figure class=\"wp-block-image alignright size-full is-resized\"><img decoding=\"async\" src=\"https:\/\/hackagora.com\/wp-content\/uploads\/2026\/06\/sqli.svg\" alt=\"SQL Injection (SQLi): Types, Exploitation and Security Best Practices\" class=\"wp-image-3452\" style=\"width:281px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>SQL injection (SQLi)<\/strong> is one of the best-known vulnerabilities in web applications. Yet it remains a relevant threat in modern environments. Although frameworks, ORMs and data access libraries have significantly reduced the number of manually constructed SQL queries, they have not eliminated the risk altogether.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It is precisely because this threat remains underestimated that it is worth revisiting it in detail. In this article, we explore the fundamental principles of SQL injection as well as exploitation techniques. We also detail the different types of SQL injection, provide concrete examples of exploitation and outline the prevention strategies to be implemented.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Comprehensive Guide to SQL Injection (SQLi)<\/h2>\n\n\n<div class=\"wp-block-aioseo-table-of-contents\"><ul><li><a class=\"aioseo-toc-item\" href=\"#what-is-sql-injection\">What is SQL injection?<\/a><ul><li><a class=\"aioseo-toc-item\" href=\"#how-does-sql-injection-work\">How does SQL injection work?<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#how-a-query-becomes-vulnerable-to-an-sql-injection\">How a query becomes vulnerable to an SQL injection<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#what-are-the-potential-consequences-of-an-sqli-attack\">What are the potential consequences of an SQLi attack?<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#sql-injection-and-nosql-injection-what-are-the-differences\">SQL injection and NoSQL injection: what are the differences?<\/a><\/li><\/ul><\/li><li><a class=\"aioseo-toc-item\" href=\"#where-to-look-for-sql-injections\">Where to Look for SQL Injections?<\/a><ul><li><a class=\"aioseo-toc-item\" href=\"#url-parameters-and-forms\">URL parameters and forms<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#searches-filters-sorting-and-dashboards\">Searches, filters, sorting and dashboards<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#apis-and-json-or-xml-bodies\">APIs and JSON or XML bodies<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#graphql-and-resolvers\">GraphQL and resolvers<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#http-headers-and-cookies\">HTTP headers and cookies<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#stored-data-and-second-order-scenarios\">Stored data and second-order scenarios<\/a><\/li><\/ul><\/li><li><a class=\"aioseo-toc-item\" href=\"#how-to-detect-an-sql-injection\">How to Detect an SQL Injection?<\/a><ul><li><a class=\"aioseo-toc-item\" href=\"#mapping-controllable-inputs\">Mapping controllable inputs<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#establish-a-baseline-response\">Establish a baseline response<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#search-for-a-syntax-error\">Search for a syntax error<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#compare-true-and-false-conditions\">Compare true and false conditions<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#search-for-a-time-series-channel\">Search for a time series channel<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#understanding-errors-correctly\">Understanding errors correctly<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#confirm-the-context-and-the-dbms\">Confirm the context and the DBMS<\/a><\/li><\/ul><\/li><li><a class=\"aioseo-toc-item\" href=\"#example-of-an-sqli-analysis\">Example of an SQLi Analysis<\/a><ul><li><a class=\"aioseo-toc-item\" href=\"#identification-of-the-context-and-confirmation-of-the-sql-injection-vulnerability\">Identification of the context and confirmation of the SQL injection vulnerability<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#choosing-the-exploitation-channel\">Choosing the exploitation channel<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#sqli-impact-assessment\">SQLi impact assessment<\/a><\/li><\/ul><\/li><li><a class=\"aioseo-toc-item\" href=\"#types-and-techniques-for-exploiting-sql-injections\">Types and Techniques for Exploiting SQL Injections<\/a><ul><li><a class=\"aioseo-toc-item\" href=\"#in-band-sql-injection\">In-band SQL injection<\/a><ul><li><a class=\"aioseo-toc-item\" href=\"#union-based-sql-injection\">UNION-based SQL injection<\/a><ul><\/ul><\/li><li><a class=\"aioseo-toc-item\" href=\"#error-based-sql-injection\">Error-based SQL Injection<\/a><\/li><\/ul><\/li><li><a class=\"aioseo-toc-item\" href=\"#blind-sql-injection\">Blind SQL Injection<\/a><ul><li><a class=\"aioseo-toc-item\" href=\"#boolean-based-blind-sql-injection\">Boolean-based blind SQL injection<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#time-based-blind-sql-injection\">Time-based blind SQL injection<\/a><\/li><\/ul><\/li><li><a class=\"aioseo-toc-item\" href=\"#out-of-band-sql-injection\">Out-of-Band SQL injection<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#stacked-queries\">Stacked Queries<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#second-order-sql-injection\">Second-Order SQL injection<\/a><\/li><\/ul><\/li><li><a class=\"aioseo-toc-item\" href=\"#advanced-techniques-for-exploiting-sql-injection-vulnerabilities\">Advanced Techniques for Exploiting SQL Injection Vulnerabilities<\/a><ul><li><a class=\"aioseo-toc-item\" href=\"#reading-and-writing-files\">Reading and writing files<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#remote-code-execution-rce-via-sql-injection\">Remote code execution (RCE) via SQL injection<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#bypassing-wafs\">Bypassing WAFs<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#privilege-escalation\">Privilege escalation<\/a><\/li><\/ul><\/li><li><a class=\"aioseo-toc-item\" href=\"#how-to-prevent-sql-injection-attacks\">How to Prevent SQL Injection Attacks?<\/a><ul><li><a class=\"aioseo-toc-item\" href=\"#use-prepared-statements\">Use prepared statements<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#implement-input-validation\">Implement input validation<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#avoid-insecure-dynamic-query-construction\">Avoid insecure dynamic query construction<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#securing-stored-procedures-and-database-side-logic\">Secure stored procedures and database-side logic<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#apply-the-principle-of-least-privilege\">Apply the principle of least privilege<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#disable-dangerous-database-features\">Disable dangerous database features<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#implement-secure-error-handling\">Implement secure error handling<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#carry-out-continuous-security-testing\">Carry out continuous security testing<\/a><\/li><\/ul><\/li><li><a class=\"aioseo-toc-item\" href=\"#conclusion\">Conclusion<\/a><\/li><\/ul><\/div>\n\n\n<h2 id=\"what-is-sql-injection\" class=\"wp-block-heading\">What is SQL injection?<\/h2>\n\n\n\n<h3 id=\"how-does-sql-injection-work\" class=\"wp-block-heading\">How does SQL injection work?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">SQL, which stands for Structured Query Language, is the language used to interact with many relational database management systems. MySQL, MariaDB, PostgreSQL, Microsoft SQL Server, Oracle Database and SQLite all implement SQL, with differences in syntax, functions and architecture.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Applications rely on these databases to store user accounts, business information, content, orders, access rights, billing data, configurations and even the secrets required for them to function.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When a user views a resource, performs a search, generates a report or logs in, the backend frequently needs to read or modify this data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An example of a legitimate query might be:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT id, username, role\nFROM users\nWHERE username = 'john';<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The structure of the query is defined by the developer. The value \u2018<code>john<\/code>\u2019 represents a piece of data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An SQL injection occurs when this separation breaks down and user-controlled input can alter the syntax sent to the SQL engine.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The key point, therefore, is not so much whether the input contains special characters, but rather whether the application enforces a robust boundary between the SQL code and the data. An apostrophe is perfectly legitimate in a piece of data such as \u2018<code>O\u2019Connor<\/code>\u2019. It only becomes dangerous when it is introduced into a query via concatenation, which allows it to alter the syntactic context.<\/p>\n\n\n\n<h3 id=\"how-a-query-becomes-vulnerable-to-an-sql-injection\" class=\"wp-block-heading\">How a query becomes vulnerable to an SQL injection<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s consider a simplified PHP implementation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$username = $_GET&#91;'username'];\n\n$query = \"SELECT id, username, role\n          FROM users\n          WHERE username = '\" . $username . \"'\";<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">With a normal value, such as \u2018<code>john<\/code>\u2019, the resulting query matches the developer\u2019s intention:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT id, username, role\nFROM users\nWHERE username = 'john';<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">However, the DBMS is unaware of the origin of the various characters in this string. It does not know that some come from the code and others from an HTTP request.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the user is able to close the string and enter a new expression, the engine will parse the whole thing as a single SQL statement.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, an input such as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>' OR '1'='1<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">can then lead to:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT id, username, role\nFROM users\nWHERE username = '' OR '1'='1';<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The added condition is true for all rows. The behaviour of the query has therefore been altered by a piece of data that should have remained a simple value.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The same vulnerability may exist without an apostrophe. In a numerical context:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$query = \"SELECT * FROM products WHERE id = \" . $_GET&#91;'id'];<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">the input:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>42 OR 1=1<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">can directly produce:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT * FROM products WHERE id = 42 OR 1=1;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">These two examples illustrate why an SQLi payload is never one-size-fits-all. The auditor must first understand the exact context of the input.<\/p>\n\n\n\n<h3 id=\"what-are-the-potential-consequences-of-an-sqli-attack\" class=\"wp-block-heading\">What are the potential consequences of an SQLi attack?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The impact of an SQL injection varies considerably. In a relatively limited scenario, the attacker may alter a filter to display additional data. In other situations, they may bypass authentication logic, read data belonging to other accounts, or access information that was never intended to be exposed by the application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Where the vulnerable query permits write operations, SQLi may enable data to be modified or deleted. Excessive privileges can further widen the impact: access to administrative tables, DBMS management functions, reading or writing files, invoking privileged procedures, or even interacting with the operating system.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It is, however, important to reason carefully. The existence of an SQLi does not automatically mean that all these actions are feasible. An application account strictly limited to read-only access on a few views does not present the same risks as an account with administrative privileges. A DBMS hosted in a managed service does not expose the same primitives as an older instance installed with a permissive configuration on the same server as the web application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The role of a penetration test is precisely to establish this distinction between theoretical impact and demonstrable impact.<\/p>\n\n\n\n<h3 id=\"sql-injection-and-nosql-injection-what-are-the-differences\" class=\"wp-block-heading\">SQL injection and NoSQL injection: what are the differences?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">SQL injections target relational systems and their query languages. Non-relational databases, such as MongoDB, may be vulnerable to other forms of injection when user input alters the structure of a filter, a query document or an expression interpreted by the backend.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A NoSQL injection therefore does not necessarily involve single quotes, UNION operators or SQL comments. The syntax depends on the technology and API used. Nevertheless, both types share a fundamental cause: untrusted data is allowed to influence the logic of an operation intended for the data engine.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This conceptual similarity should not lead to them being confused. The detection methods, exploitation techniques, syntax and specific preventative measures differ.<\/p>\n\n\n\n<h2 id=\"where-to-look-for-sql-injections\" class=\"wp-block-heading\">Where to Look for SQL Injections?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">An SQLi vulnerability can occur wherever user-controlled data influences an SQL operation. Limiting your focus to login forms or \u2018id\u2019 parameters leaves a significant portion of the attack surface unaddressed.<\/p>\n\n\n\n<h3 id=\"url-parameters-and-forms\" class=\"wp-block-heading\">URL parameters and forms<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Query string parameters are easy to change and provide obvious test cases:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>GET \/product?id=42 HTTP\/1.1\nHost: application.example<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">But data from a <code>POST<\/code> form, a path such as <code>\/users\/42<\/code>, a multipart form or hidden parameters is just as interesting. The name of the parameter may provide a functional clue, but never proves that it reaches a database.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The auditor therefore observes the behaviour.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Does changing a value alter the number of results?<\/li>\n\n\n\n<li>Does a non-existent value produce a different response?<\/li>\n\n\n\n<li>Does the field appear to control a filter, a search, a sort or an object selection?<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">These clues help to prioritise the tests.<\/p>\n\n\n\n<h3 id=\"searches-filters-sorting-and-dashboards\" class=\"wp-block-heading\">Searches, filters, sorting and dashboards<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Search engines often generate complex dynamic queries. A page may combine a keyword, a category, a price range, a status, a sort order and pagination. Each option may be implemented differently.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An example query might be:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT id, name, price\nFROM products\nWHERE name LIKE '%$search%'\nAND category = '$category'\nORDER BY $sort\nLIMIT $limit;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">\u2018<code>search<\/code>\u2019 and \u2018<code>category<\/code>\u2019 are values. \u2018<code>sort<\/code>\u2019 is a structural element. \u2018<code>limit<\/code>\u2019 may be a numerical expression, the configurability of which depends on the driver and the chosen structure. A single feature may therefore have several distinct injection contexts.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Reporting interfaces, CSV or PDF export functions and administrative dashboards warrant particular attention. They frequently combine multiple filters, aggregations and sorts, sometimes implemented using raw SQL for reasons of performance or flexibility.<\/p>\n\n\n\n<h3 id=\"apis-and-json-or-xml-bodies\" class=\"wp-block-heading\">APIs and JSON or XML bodies<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">An API that receives:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"category\": \"laptop\",\n  \"minPrice\": 500,\n  \"sort\": \"price\"\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">is not protected simply by using JSON. If the backend concatenates \u2018<code>category<\/code>\u2019, \u2018<code>minPrice<\/code>\u2019 or \u2018<code>sort<\/code>\u2019 into a query, the same risk applies.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">APIs can even increase the attack surface because they expose rich objects: nested filters, arrays of identifiers, multiple sort parameters, advanced searches, optional fields and batch operations. The transport format is just one layer. What matters is the transformation carried out between the structured input and the query sent to the DBMS.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The same reasoning applies to XML. Checks for SQL injection must be applied at the time the query is constructed, not just when the document is parsed.<\/p>\n\n\n\n<h3 id=\"graphql-and-resolvers\" class=\"wp-block-heading\">GraphQL and resolvers<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">GraphQL is not a form of SQL, and a GraphQL query is not automatically converted into an SQL query. The risk arises when the resolver uses client-controlled arguments to construct an operation on a relational database.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s consider, for example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>query {\n  products(category: \"laptop\") {\n    id\n    name\n    price\n  }\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The resolver receives <code>category<\/code>. If it calls an ORM correctly, the value will generally be parameterised. If it constructs a raw query to handle a complex filter, it may reintroduce an SQLi vulnerability.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The chain to be analysed is therefore as follows: the GraphQL value enters a resolver, may pass through several services or helpers, and then reaches an SQL sink. It is at this sink, and in the way the query is constructed, that the vulnerability lies.<\/p>\n\n\n\n<h3 id=\"http-headers-and-cookies\" class=\"wp-block-heading\">HTTP headers and cookies<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Some applications log or process the <code>User-Agent<\/code>, <code>Referer<\/code>, <code>X-Forwarded-For<\/code>, business headers or tracking identifiers in a database. A backend system may also use a cookie to retrieve a session, a preference or a campaign.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">These values can be manipulated by the client. An attacker can send their own headers and modify their cookies, even when the browser would normally generate them automatically. They must therefore be treated as untrusted input.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Header-based SQLi attacks are particularly common in logging or analytics components that have been developed quickly and are mistakenly regarded as internal. They can be difficult to detect because the HTTP entry point and the SQL processing are far apart in the architecture.<\/p>\n\n\n\n<h3 id=\"stored-data-and-second-order-scenarios\" class=\"wp-block-heading\">Stored data and second-order scenarios<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Data may be entered securely into the database but then reused in a dangerous way. For example, the registration process uses:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>INSERT INTO companies(name) VALUES (?);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The value is set correctly. Later, a reporting tool retrieves \u2018<code>name<\/code>\u2019 and constructs:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$sql = \"SELECT * FROM invoices\n        WHERE company_name = '\" . $storedName . \"'\";<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The database is treated here as a trusted source, even though it contains data that originally came from the user. The vulnerability does not exist at the time of storage; it arises when the data is reused.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This scenario illustrates why data security is not an absolute property. Data that is secure in one context can become dangerous in another if interpreted differently.<\/p>\n\n\n\n<h2 id=\"how-to-detect-an-sql-injection\" class=\"wp-block-heading\">How to Detect an SQL Injection?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Testing for SQLi effectively does not involve sending a long list of random payloads. The aim is to gradually build up a hypothesis about the query, obtain a reproducible signal, and then choose the most appropriate technique.<\/p>\n\n\n\n<h3 id=\"mapping-controllable-inputs\" class=\"wp-block-heading\">Mapping controllable inputs<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The first step is to identify the data likely to reach the backend: URL parameters, path segments, form bodies, JSON, XML, cookies, headers, stored fields, filters, sorting criteria and pagination parameters.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In a white-box context, this mapping can be supplemented by an analysis of SQL sources and sinks within the code.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The auditor does not necessarily test all inputs with the same level of rigour. Parameters that drive a search, object selection, export or reporting query are often more likely to interact with a data layer than values that are purely displayed on the client side.<\/p>\n\n\n\n<h3 id=\"establish-a-baseline-response\" class=\"wp-block-heading\">Establish a baseline response<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Before modifying a request, it is useful to assess its normal behaviour: HTTP status code, approximate size, characteristic content, number of results, response time, redirects and key JSON elements.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s consider:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>GET \/products?id=42 HTTP\/1.1\nHost: application.example<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The baseline response then allows us to compare very similar variations. Without a baseline, a difference observed following a payload may be mistakenly attributed to an SQL injection, when in fact it stems from a cache, missing data or normal business behaviour.<\/p>\n\n\n\n<h3 id=\"search-for-a-syntax-error\" class=\"wp-block-heading\">Search for a syntax error<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In a supposed textual context, a character such as <code>'<\/code> may cause an error. In a numerical context, an unexpected operator may have a different effect. The aim of this step is not to draw immediate conclusions, but to determine whether the syntax of the input appears to be recognised by an SQL interpreter.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A change in the HTTP status code, an exception, a different number of results or a blank page may all be clues. A stack trace mentioning an SQL driver is particularly informative, but a properly configured application should not expose this level of detail.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The hypothesis must then be confirmed with tests that produce predictable results.<\/p>\n\n\n\n<h3 id=\"compare-true-and-false-conditions\" class=\"wp-block-heading\">Compare true and false conditions<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In a digital context, a simple pair can be:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>42 AND 1=1<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">then:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>42 AND 1=2<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If the first response consistently replicates the normal behaviour and the second produces a different result, this strongly suggests an injection. The same principle can be adapted to a string context whilst adhering to the syntax of the presumed query.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This method is particularly useful because it does not necessarily depend on a visible SQL error. It demonstrates that a condition introduced by the user directly influences the result of the query.<\/p>\n\n\n\n<h3 id=\"search-for-a-time-series-channel\" class=\"wp-block-heading\">Search for a time series channel<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If no difference in content is apparent, the auditor may look for a controlled delay. MySQL and MariaDB, for example, have <code>SLEEP()<\/code>, PostgreSQL has <code>pg_sleep()<\/code>, and SQL Server has <code>WAITFOR DELAY<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A slow query does not constitute proof. Response time depends on the network, server load, third-party services and many other factors. The test must therefore compare several control queries with several queries that are expected to cause a delay significantly greater than normal background noise.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The next step is to make this delay conditional. If the server only waits when the SQL expression is true, the time becomes an oracle that can be used to extract information.<\/p>\n\n\n\n<h3 id=\"understanding-errors-correctly\" class=\"wp-block-heading\">Understanding errors correctly<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Errors can be useful in a number of ways. A syntax error suggests a context. An <code>ORDER BY<\/code> error can help determine the number of columns. A conversion error may reveal that a column expects a numeric type.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A distinction must be made between these errors and genuine error-based extraction. In the latter case, the auditor forces the DBMS to generate an error whose message contains data from a subquery. The error then becomes a channel for data exfiltration rather than merely an indication of the structure.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The availability of this technique depends heavily on the engine, its version and the way in which the application propagates or masks exceptions.<\/p>\n\n\n\n<h3 id=\"confirm-the-context-and-the-dbms\" class=\"wp-block-heading\">Confirm the context and the DBMS<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Once the signal has been confirmed, the auditor seeks to identify the underlying engine. Version functions, error messages, comment syntax, timing functions and behaviour in response to certain constructs all provide clues.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Fingerprinting must avoid jumping to conclusions. For example, <code>@@version<\/code> exists in several engines. A single positive test may therefore not be sufficient to distinguish MySQL from SQL Server. Ideally, several primitives should be cross-referenced, or an identifiable version string should be retrieved where the output channel permits.<\/p>\n\n\n\n<h2 id=\"example-of-an-sqli-analysis\" class=\"wp-block-heading\">Example of an SQLi Analysis<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s consider a catalogue application that exposes:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>GET \/products?category=laptops HTTP\/1.1\nHost: shop.example\nCookie: session=...<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The page returns a list of products belonging to the \u2018<code>laptops<\/code>\u2019 category. The auditor knows neither the SQL query, nor the number of columns, nor the DBMS. They only have the HTTP behaviour to go on.<\/p>\n\n\n\n<h3 id=\"identification-of-the-context-and-confirmation-of-the-sql-injection-vulnerability\" class=\"wp-block-heading\">Identification of the context and confirmation of the SQL injection vulnerability<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The first step is to establish the reference response: status 200, response length, number of products displayed and a few static strings.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The auditor then replaces the category with a non-existent value to verify the expected behaviour when the query returns no rows.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Finally, they test a single apostrophe:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>laptops'<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Let us assume that, on this occasion, the application returns a generic error with a 500 status code. This indication is interesting but insufficient.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The auditor therefore seeks to construct two queries that differ only in terms of a logical condition. In the hypothetical context of a string, they adapt the values so that the syntax remains valid and compare a true condition with a false condition.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The true condition returns the normal list, whilst the false condition returns an empty list. After several repetitions, the behaviour remains consistent. The vulnerability is now much more credible: a user-injected SQL expression alters the result of the query.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This step is essential. It prevents a one-off error from being misinterpreted as an SQLi and provides a method that may still prove useful if direct techniques fail.<\/p>\n\n\n\n<h3 id=\"choosing-the-exploitation-channel\" class=\"wp-block-heading\">Choosing the exploitation channel<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The auditor then seeks to determine whether the result of the query is displayed directly. As the page displays products, a <code>UNION<\/code> attack is a natural candidate.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">He progressively tests <code>ORDER BY 1<\/code>, <code>ORDER BY 2<\/code> and subsequent positions. The first three positions are accepted, whilst the fourth triggers an error response. The original query therefore appears to return three columns.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">He confirms this hypothesis with a query containing three <code>NULL<\/code> values. The query is accepted. By then replacing each <code>NULL<\/code> with a test string, he observes that the second and third positions accept text, but that only the second appears in the HTML.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">At this stage, several facts have been established: the point is injectable, the injection is likely to be within a string, the query returns three columns, and the second column constitutes a usable display channel.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The next step is to identify the DBMS. A test using a specific function returns a PostgreSQL version string. The auditor can then use PostgreSQL syntax for the subsequent steps rather than blindly trying MySQL, SQL Server or Oracle functions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">They retrieve the name of the current database and a few table names visible via the metadata. A business table containing user accounts appears. The auditor does not need to extract the full contents: rather, they are seeking to determine which columns exist and whether sensitive information is actually accessible to the application account.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Suppose they identify <code>id<\/code>, <code>email<\/code>, <code>password_hash<\/code> and <code>role<\/code>. The presence of <code>password_hash<\/code> already indicates that the SQL account used by the catalogue can access data that likely exceeds the functional requirements of a public product page. A test record or a value belonging to a demonstration account may be sufficient to prove unauthorised access.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The test therefore reveals two distinct issues: the SQLi itself and insufficient separation of privileges, since the account used by the catalogue component can read an authentication table.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If the <code>UNION<\/code> query had failed because the results were not displayed, the auditor could have reverted to the previously confirmed Boolean method. If the content had been exactly the same, a timing channel could have been investigated.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The methodology therefore involves prioritising the most direct and least resource-intensive channel, then switching to blind techniques only when necessary.<\/p>\n\n\n\n<h3 id=\"sqli-impact-assessment\" class=\"wp-block-heading\">SQLi impact assessment<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Once the ability to read sensitive data has been demonstrated, it would be technically possible to continue the enumeration. This does not mean that it is appropriate to do so. A penetration test must produce sufficient evidence to enable the risk to be assessed and remedied, not to maximise the amount of data exfiltrated.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Instead, the auditor examines the account\u2019s privileges. Can it write data? Can it create objects? Does it have privileged functions?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In our scenario, let us assume that the role is restricted to <code>SELECT<\/code> operations across several schemas. The impact remains high because sensitive data is accessible, but the likelihood of database modification or direct RCE is significantly reduced.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This conclusion is more useful than a generic statement such as \u2018an SQLi can lead to RCE\u2019. The report may explain that the vulnerability allows arbitrary extraction of data readable by the account, that this account has excessive scope relative to the public function being tested, but that no possibility of writing or system execution has been identified within the authorised context.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The scenario also provides a more precise remedy. The <code>category<\/code> value must be configured in the query, but the account used by the catalogue must also be reviewed to ensure it can only access the tables or views that are strictly necessary. Correcting the code removes the root cause; the principle of least privilege reduces the impact of any potential future vulnerability.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">During the retest, the auditor will replay both the true and false conditions, verify that strings containing SQL characters are treated as plain values, and then confirm that the account or data layer no longer unnecessarily exposes authentication objects.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This practical example summarises the reasoning to be applied throughout this guide: verify before exploiting, identify the context before selecting payloads, use the simplest channel, limit access to data to what is strictly necessary, and assess the impact based on the capabilities actually demonstrated.<\/p>\n\n\n\n<h2 id=\"types-and-techniques-for-exploiting-sql-injections\" class=\"wp-block-heading\">Types and Techniques for Exploiting SQL Injections<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The categories of SQLi primarily describe the channel used to obtain information or maximise the impact. A single vulnerability can sometimes be exploited in several ways.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">When results are displayed directly, an in-band technique is generally more effective than a blind injection. When the application returns nothing useful, a Boolean, temporal or out-of-band technique becomes necessary.<\/p>\n\n\n\n<h3 id=\"in-band-sql-injection\" class=\"wp-block-heading\">In-band SQL injection<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">An in-band SQL injection occurs when the same application channel is used both to send the payload and to retrieve useful data or clues.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The two most common types are UNION-based and error-based injections.<\/p>\n\n\n\n<h4 id=\"union-based-sql-injection\" class=\"wp-block-heading\">UNION-based SQL injection<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>UNION<\/code> operator allows you to combine the results of several <code>SELECT<\/code> queries. A valid query such as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT name, price\nFROM products;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">can be combined with:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT username, email\nFROM users;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">provided that both results have the same number of columns and that the corresponding data types are compatible.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In an SQLi attack, the aim is to use this mechanism to make the result of a manipulated query be processed as if it were part of the original result.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Suppose that a category feature constructs:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT name, description, price\nFROM products\nWHERE category = '$category';<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The auditor cannot begin effectively with an arbitrary UNION SELECT statement. They must first determine the number of columns, which positions are suitable for text, and which are actually displayed in the response.<\/p>\n\n\n\n<h5 id=\"aioseo-determining-the-number-of-columns-using-order-by\" class=\"wp-block-heading\">Determining the number of columns using ORDER BY<\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">In many DBMSs, ORDER BY 1, ORDER BY 2 or ORDER BY 3 are used to specify the columns in the result set by their position. The auditor can gradually increase this value:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>' ORDER BY 1 --\n' ORDER BY 2 --\n' ORDER BY 3 --\n' ORDER BY 4 --<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">When the position exceeds the number of columns, the engine may generate an error. The application does not necessarily display the SQL message; a different generic response, a 500 status code or the absence of a result may be sufficient to identify the threshold.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If `<code>ORDER BY 3<\/code>` remains valid but `<code>ORDER BY 4<\/code>` consistently results in different behaviour, the original query likely returns three columns.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This technique must be adapted to the context. The comment used after the payload depends, in particular, on the DBMS and the expected syntax. In MySQL, the sequence <code>--<\/code> must be followed by a valid space character; the <code>#<\/code> character is also supported as an end-of-line comment.<\/p>\n\n\n\n<h5 id=\"aioseo-finding-out-the-number-of-columns-using-union-select-null\" class=\"wp-block-heading\">Finding out the number of columns using UNION SELECT NULL<\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">Another method is to increase the number of NULL values until a compatible query is obtained:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>UNION SELECT NULL<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">then:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>UNION SELECT NULL,NULL<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">and so on.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>NULL<\/code> is useful because it can be converted to many SQL data types. It therefore maximises the chances of the query succeeding once the correct number of columns has been reached, without yet knowing the type of each column.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An error with two values followed by a successful result with three suggests that the original result contains three columns.<\/p>\n\n\n\n<h5 id=\"aioseo-identifying-columns-that-support-text\" class=\"wp-block-heading\">Identifying columns that support text<\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">The number of columns is not sufficient. If the auditor wishes to retrieve a username, a database version or a metadata string, they must find a column that accepts text data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For a three-column result, they can try the following in turn:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>UNION SELECT 'test',NULL,NULL\nUNION SELECT NULL,'test',NULL\nUNION SELECT NULL,NULL,'test'<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">A conversion error may indicate that the position being tested corresponds to an integer, a date or another incompatible type. If the query is successful, the column is likely compatible with a string.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This step must be distinguished from a second question: is the column actually visible? An application may retrieve four columns but then use only two of them in its HTML template or JSON response. A column may therefore be technically compatible without constituting an exploitable exfiltration channel.<\/p>\n\n\n\n<h5 id=\"aioseo-identifying-the-columns-that-are-actually-displayed\" class=\"wp-block-heading\">Identifying the columns that are actually displayed<\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">A simple technique involves injecting a recognisable string into each compatible column and checking where it reappears in the response. If <code>HACKAGORA_TEST_47<\/code> appears in a product title, a JSON field or an HTML attribute, that position provides an output channel.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Sometimes, several legitimate results may obscure the row added by the UNION, or the application may only process the first record. In this case, the auditor may seek to alter the original part of the query so that only the results from the second selection are retained. This adjustment depends on the context and must remain non-destructive.<\/p>\n\n\n\n<h5 id=\"aioseo-fingerprinting-using-union\" class=\"wp-block-heading\">Fingerprinting using UNION<\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">Once a visible text column has been identified, the channel can be used to identify the DBMS. Depending on the engine, expressions such as the following are relevant:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>SELECT @@version;<\/code> for MySQL or SQL Server,<\/li>\n\n\n\n<li><code>SELECT version();<\/code> for PostgreSQL,<\/li>\n\n\n\n<li>or querying <code>v$version<\/code> for Oracle.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">In a <code>UNION<\/code> context, these expressions must be inserted into the correct number of columns and in a compatible position. Obtaining a version string then allows functions, comments, concatenation and enumeration techniques to be adapted accordingly.<\/p>\n\n\n\n<h5 id=\"aioseo-listing-metadata-using-union\" class=\"wp-block-heading\">Listing metadata using UNION<\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">Many databases expose metadata via <code>information_schema<\/code>. Where permissions allow, a query such as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT table_name\nFROM information_schema.tables;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">can reveal tables. The auditor can then examine the columns of an object of interest:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT column_name\nFROM information_schema.columns\nWHERE table_name = 'users';<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The aim is not necessarily to extract all the data. In penetration testing, a few representative data points are often sufficient to demonstrate that an SQL account can access a sensitive table that should never have been exposed via the vulnerable feature.<\/p>\n\n\n\n<h5 id=\"aioseo-concatenate-several-values-into-a-single-column\" class=\"wp-block-heading\">Concatenate several values into a single column<\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">An interface may display only a single text column. The auditor can then concatenate several fields to retrieve them together. MySQL offers the following options:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>CONCAT(username, ':', email)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">PostgreSQL and Oracle commonly use:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>username || ':' || email<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">SQL Server can use the <code>+<\/code> operator or other concatenation functions, depending on the data types and version.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This difference demonstrates once again why the fingerprinting stage is not merely a cosmetic exercise. It enables the selection of methods that are compatible with the actual engine.<\/p>\n\n\n\n<h4 id=\"error-based-sql-injection\" class=\"wp-block-heading\">Error-based SQL Injection<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">The term \u2018error-based\u2019 is often used to refer to any exploit that takes advantage of an SQL error. It is useful to distinguish between errors that help to understand the query and those that are actually used to extract data.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An error caused by:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ORDER BY 10<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">may reveal that the query contains fewer than ten columns. An impossible conversion may indicate the expected data type. A syntax error message may reveal the database engine. This information facilitates analysis, but the data being sought is not yet contained within the error message.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In an error-based SQLi in the strictest sense, the attacker forces the DBMS to perform an invalid operation, the error message for which incorporates a value from a subquery. The conceptual mechanism is as follows: the database calculates a piece of information; this information is used in a context that deliberately triggers an exception; and the error message is then returned to the application.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An error of the type:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Cannot convert value 'production_database' ...<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">can therefore reveal `production_database`, even though the feature never displays the SQL result directly.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The specific techniques vary greatly between databases and versions. They may also be rendered ineffective by error handling that replaces SQL exceptions with a generic message. This measure significantly reduces the amount of information available, but obviously does not fix the SQLi itself.<\/p>\n\n\n\n<h3 id=\"blind-sql-injection\" class=\"wp-block-heading\">Blind SQL Injection<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A blind injection occurs when the query is manipulable but the application returns neither the SQL result nor, in most cases, a directly exploitable error message. The attacker must therefore deduce the information by observing a stable side effect.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The two most common channels are differences in content or behaviour, and response time.<\/p>\n\n\n\n<h4 id=\"boolean-based-blind-sql-injection\" class=\"wp-block-heading\">Boolean-based blind SQL injection<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Let us assume that an endpoint returns \u2018Product available\u2019 when its query finds a record, and \u2018Product not found\u2019 otherwise.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An input:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>42 AND 1=1<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">retains the normal result, whereas:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>42 AND 1=2<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">makes the product disappear. The application has just provided a clue: it indirectly answers an SQL query with \u2018true\u2019 or \u2018false\u2019.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The next step is to replace <code>1=1<\/code> with a condition based on actual data. In MySQL, for example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>LENGTH(DATABASE()) = 10<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">allows you to check whether the name of the current database contains ten characters. Once the length has been determined, an expression such as:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SUBSTRING(DATABASE(),1,1) = 'a'<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">allows you to test the first position.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A naive approach would try all possible characters in turn. This quickly becomes computationally expensive. An efficient blind extraction relies instead on binary search. Rather than checking whether the character is a, then b, then c, the auditor compares its numerical value against a threshold. Each check eliminates approximately half the possibilities.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With a space of 128 values, seven queries are theoretically sufficient to isolate a value, since 2^7 = 128. Automated tools use this type of optimisation to significantly reduce the number of queries required.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In a real-world application, true and false are not always represented by explicit messages. The signal may be a JSON field, a difference in the number of results, a redirect, a change in length of a few bytes, or the presence of an HTML element. The auditor must verify that this signal is reproducible and that it does not depend on volatile data, a cache or any other business mechanism.<\/p>\n\n\n\n<h4 id=\"time-based-blind-sql-injection\" class=\"wp-block-heading\">Time-based blind SQL injection<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">When the content of the response remains the same, the auditor can use time as a indicator. The primitives are engine-specific:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>SLEEP(5)<\/code> in MySQL or MariaDB,<\/li>\n\n\n\n<li><code>pg_sleep(5)<\/code> in PostgreSQL,<\/li>\n\n\n\n<li>and <code>WAITFOR DELAY '0:0:5';<\/code> in SQL Server.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Inducing a fixed delay demonstrates, above all, that a timing function is achievable. To extract data, this delay must be made conditional. The logic becomes: if an expression is true, wait; otherwise, respond normally.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The auditor can thus test the length of a string, and then each of its characters. Binary search remains relevant: the delay is simply the medium used to represent the true or false bit.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The main challenge is noise. A server may respond in 200 ms and then 900 ms without any SQLi being involved. Tests must therefore use a delay significantly greater than the usual variance and be repeated. The auditor compares several test queries with several queries intended to trigger the delay.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A time-based exploit can also generate a significant load, particularly if each query imposes a delay of several seconds. In a production environment, confirming that the oracle allows internal data to be tested is often sufficient. Extracting long strings simply because the technique allows it may be unnecessarily intrusive.<\/p>\n\n\n\n<h3 id=\"out-of-band-sql-injection\" class=\"wp-block-heading\">Out-of-Band SQL injection<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Some applications execute the query asynchronously or neutralise any exploitable differences in content and timing. It may nevertheless be possible to trick the DBMS into initiating a network interaction with an infrastructure controlled by the auditor.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An out-of-band SQLi attack then uses another channel \u2013 typically DNS or HTTP \u2013 to confirm the exploit or transmit data. Conceptually, the database may be tricked into performing a name resolution where the name contains an extracted value:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>production-db.audit.example<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The test DNS server receives the request and allows the data to be observed without it passing through the application\u2019s HTTP response.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This technique depends on several prerequisites. The DBMS must have a network primitive that can be used in the context of the injection, the SQL account must have the necessary permissions, and the environment must allow outbound traffic. Strict segmentation and egress filtering can therefore block this channel even if the SQLi vulnerability itself exists.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This distinction is important for impact analysis: a primitive documented in an engine does not mean that it is accessible in the audited environment.<\/p>\n\n\n\n<h3 id=\"stacked-queries\" class=\"wp-block-heading\">Stacked Queries<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A <code>UNION<\/code> injection adds a second <code>SELECT<\/code> statement to the result of the original query. Stacked queries, also known as batched or piggy-backed queries, aim to complete the existing statement and then execute a new, independent statement.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Take, for example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT * FROM products WHERE id = 42;\nUPDATE audit_marker SET checked = 1 WHERE id = 99999;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The second statement is no longer limited to the form of a SELECT. Depending on the privileges, it could be an UPDATE, a stored procedure call or another statement supported by the engine.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Support does not depend solely on the DBMS. The driver or application API may prohibit multiple statements within a single call, or require an explicit option. Two applications using the same underlying technology may therefore offer different capabilities.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In penetration testing, verification should prioritise an operation with no lasting business impact. A controlled delay or a harmless query is preferable to modifying data when the mere support for stacked queries is sufficient to demonstrate the expansion of the exploitation scope.<\/p>\n\n\n\n<h3 id=\"second-order-sql-injection\" class=\"wp-block-heading\">Second-Order SQL injection<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Second-order injection occurs when malicious data is stored without causing any immediate effect, and is then reused later in a vulnerable query.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The point of entry and the point of execution may be very far apart. A company name is stored today via a parameterised query. An internal export retrieves it the next day and concatenates it into an SQL filter. The first component is not vulnerable; the second is.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This scenario is particularly difficult to detect using a conventional dynamic scanner. The response to the registration request is perfectly normal and no errors are displayed. It is necessary to understand the data\u2019s lifecycle, identify the features that re-read it, and test the subsequent sinks.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Administration interfaces, reports, exports, scheduled tasks, batch processing and synchronisations are common locations for this type of data reuse. Developers sometimes mistakenly assume that database data is implicitly reliable in these contexts.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The security rule must be phrased differently: data must be used securely in every context in which it is interpreted, regardless of its immediate source.<\/p>\n\n\n\n<h2 id=\"advanced-techniques-for-exploiting-sql-injection-vulnerabilities\" class=\"wp-block-heading\">Advanced Techniques for Exploiting SQL Injection Vulnerabilities<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Beyond the scenario described above, certain techniques make it possible to extend access well beyond the initial point of entry. It all depends, then, on the privileges of the database and the underlying infrastructure.<\/p>\n\n\n\n<h3 id=\"reading-and-writing-files\" class=\"wp-block-heading\">Reading and writing files<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Some DBMSs provide functions for interacting with the file system. If the privileges granted to the database are too high, an attacker could exploit this to read sensitive server files or write arbitrary content to the disk.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">MySQL, for example, provides the <code>LOAD_FILE()<\/code> function:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT LOAD_FILE('\/etc\/passwd');<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It is also possible to write files using:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT 'malicious content' INTO OUTFILE '\/var\/www\/html\/shell.php';<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">SQL Server, for its part, exposes stored procedures that are equally dangerous for interacting with the operating system. This ability to interact with the file system significantly increases the severity of an SQL injection, as it can grant access to configuration files, application secrets, SSH keys, source code, backups or server scripts.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the most vulnerable environments, the ability to write to files can lead to the server being completely compromised.<\/p>\n\n\n\n<h3 id=\"remote-code-execution-rce-via-sql-injection\" class=\"wp-block-heading\">Remote code execution (RCE) via SQL injection<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">In some cases, an SQL injection can go beyond simply compromising the database and lead to remote code execution (RCE) on the underlying operating system. This generally occurs when:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>the database is running with excessive privileges;<\/li>\n\n\n\n<li>dangerous stored procedures are enabled;<\/li>\n\n\n\n<li>file writing is permitted;<\/li>\n\n\n\n<li>functions for executing external commands are accessible.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">SQL Server, for example, exposes the stored procedure <code>xp_cmdshell<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>EXEC xp_cmdshell 'whoami';<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Using an SQL injection, an attacker can thus plant a web shell, write malicious scripts to an accessible directory, trigger system functions, or execute external binaries.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A successful RCE can then be used to completely compromise the server, establish persistence, move laterally across the internal network, deploy ransomware, or exfiltrate data on a large scale. Whilst current hardening practices generally disable these dangerous functions by default, poorly secured configurations and legacy environments continue to expose this type of high-risk attack vector.<\/p>\n\n\n\n<h3 id=\"bypassing-wafs\" class=\"wp-block-heading\">Bypassing WAFs<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Many organisations deploy WAFs (Web Application Firewalls) to detect and block malicious SQL injection payloads. However, attackers regularly attempt to bypass them using obfuscation techniques: payload encoding, case manipulation, inline comments, whitespace, fragmentation of SQL syntax, or the use of alternative operators and functions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Example of a reformatted payload designed to evade signature-based detection:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>UN\/**\/ION SEL\/**\/ECT<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">URL encoding, or even double encoding, is also used to conceal malicious input before it reaches the backend. As many WAFs rely heavily on pattern matching and signature-based detection, an incorrectly configured rule set may fail to detect a heavily obfuscated payload. A WAF remains a valuable defence mechanism, but should never be regarded as a substitute for secure request handling via parameterised queries.<\/p>\n\n\n\n<h3 id=\"privilege-escalation\" class=\"wp-block-heading\">Privilege escalation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The severity of an SQL injection depends largely on the privileges assigned to the compromised database account. Excessive permissions significantly widen the attack surface and allow for deeper compromise. An attacker typically seeks to escalate their privileges to access restricted tables, execute administrative functions, interact with the file system, compromise other services, or move laterally within the infrastructure.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An application running under a database account with excessive privileges may thus inadvertently expose administrative stored procedures, database management functions, capabilities to interact with the operating system, or sensitive internal schemas. In some environments, credentials that have been extracted can even be used to compromise other systems connected to the same infrastructure.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Inadequate separation of privileges remains one of the most significant factors determining the severity of an SQL injection exploit. Even a relatively simple vulnerability can become critical if the underlying database account has excessive permissions.<\/p>\n\n\n\n<h2 id=\"how-to-prevent-sql-injection-attacks\" class=\"wp-block-heading\">How to Prevent SQL Injection Attacks?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Preventing an SQL injection attack relies on a combination of best development practices, secure database configuration, restricted privileges and regular security testing. As the vulnerability stems from a lack of separation between user data and executable SQL statements, an effective mitigation strategy must cover every stage of interaction with the database.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Modern frameworks and libraries offer more secure mechanisms, but poorly secured implementations, legacy code and hand-crafted queries continue to leave applications vulnerable.<\/p>\n\n\n\n<h3 id=\"use-prepared-statements\" class=\"wp-block-heading\">Use prepared statements<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Prepared statements remain the most effective defence against SQL injection. Unlike dynamically constructed queries, they separate the query structure from the data provided by the user: the application sends the query template and the parameters separately to the database engine, which then consistently treats the input as data and never as a command.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Example of an insecure construction:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$query = \"SELECT * FROM users WHERE id = \" . $_GET&#91;'id'];<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Secure version with parameter binding:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$stmt = $pdo->prepare(\"SELECT * FROM users WHERE id = ?\");\n$stmt->execute(&#91;$id]);<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">As the engine strictly separates the SQL logic from the supplied value, an injected payload can no longer alter the structure of the query. Prepared statements are widely supported by modern database languages, frameworks and drivers. This is a basic defence against SQL injection.<\/p>\n\n\n\n<h3 id=\"implement-input-validation\" class=\"wp-block-heading\">Implement input validation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Input validation reduces the attack surface by filtering out unexpected or malformed data before it reaches the application logic or the database. An application should validate: the data type, the expected format, the length, the permitted characters and the accepted values.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A numeric parameter should only accept numeric values; an email field should enforce a valid email format. A whitelist approach (defining what is valid) is generally more secure than a blacklist approach (attempting to block what is dangerous).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Be careful, however: input validation must never be regarded as sufficient protection on its own. An attacker can often bypass weak filtering or blacklist-based protection. It must therefore complement, rather than replace, prepared queries and secure query handling.<\/p>\n\n\n\n<h3 id=\"avoid-insecure-dynamic-query-construction\" class=\"wp-block-heading\">Avoid insecure dynamic query construction<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Unsecure dynamic construction remains one of the main causes of SQL injection: it occurs whenever a developer generates an SQL query by concatenating strings, using direct interpolation, or relying on untrusted variables. A typical example:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>$query = \"SELECT * FROM products WHERE category = '\" . $category . \"'\";<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Here, a malicious input can directly alter the structure and logic of the generated query. Things to avoid: direct string concatenation, raw SQL interpolation, dynamically assembled SQL fragments, insecure query builders, or the execution of user-supplied SQL.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If dynamic generation is still necessary, prioritise parameterised queries, strict validation checks and secure query-building mechanisms.<\/p>\n\n\n\n<h3 id=\"securing-stored-procedures-and-database-side-logic\" class=\"wp-block-heading\">Secure stored procedures and database-side logic<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">When implemented correctly, stored procedures can reduce the risk of injection by encapsulating business logic within predefined routines, thereby limiting direct interaction between user input and dynamically generated SQL.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">However, they are not inherently secure: a procedure that constructs dynamic SQL itself remains vulnerable. This is particularly the case with statements such as <code>EXEC(@query)<\/code> or <code>sp_executesql<\/code>, if the attacker\u2019s input is incorporated without parameterisation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A secure stored procedure should: use parameter binding, avoid executing unsecured dynamic SQL, restrict unnecessary privileges, and limit the administrative functionality exposed. Database-side logic must follow the same security principles as application code.<\/p>\n\n\n\n<h3 id=\"apply-the-principle-of-least-privilege\" class=\"wp-block-heading\">Apply the principle of least privilege<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The impact of an SQL injection depends largely on the privileges of the compromised database account. An application should never connect using an administrator account unless absolutely necessary: the account used must have only the permissions that are strictly necessary.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An application that requires only read access should not have file system privileges, administrative permissions, schema modification rights, or the ability to execute commands.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Restricting privileges significantly reduces the potential impact of a successful exploit: even if the query is compromised, limited permissions can prevent privilege escalation, access to the file system, database modification, remote code execution, or lateral movement within the infrastructure. This is one of the most effective ways to contain an exploit.<\/p>\n\n\n\n<h3 id=\"disable-dangerous-database-features\" class=\"wp-block-heading\">Disable dangerous database features<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Many DBMSs provide advanced features capable of interacting with the operating system or the file system. If these remain enabled unnecessarily, an attacker may exploit them during an attack: command execution procedures, file read\/write functions, external network communication, and extended administrative procedures.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">SQL Server, for example, exposes <code>xp_cmdshell<\/code>, whilst MySQL exposes <code>LOAD_FILE()<\/code>. If the application does not require these functions, they must be disabled or strictly restricted. Reducing the attack surface at the database level limits post-exploitation opportunities and significantly mitigates the severity of an SQL injection.<\/p>\n\n\n\n<h3 id=\"implement-secure-error-handling\" class=\"wp-block-heading\">Implement secure error handling<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Error messages that are too detailed provide the attacker with valuable information during an exploit: database type and version, table names, query structure, server file paths, and internal application logic.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An application should never return a raw database error to the end user. Instead, display a generic message on the front end, and keep detailed logs reserved for internal monitoring. An error such as \u2018Unknown column \u201cusername\u201d in \u201cwhere clause\u201d\u2019 should never be displayed on the client side.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Poor error handling directly facilitates error-based attacks by exposing backend information that an attacker can exploit to refine their payloads and map the database. Secure logging and monitoring remain essential for detecting suspicious behaviour without exposing sensitive information.<\/p>\n\n\n\n<h3 id=\"carry-out-continuous-security-testing\" class=\"wp-block-heading\">Carry out continuous security testing<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Preventing SQL injection cannot rely solely on best practices implemented at the start of a project. Regular security testing is essential to detect new vulnerabilities, risky code changes and changes to the attack surface.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The most effective approaches combine: manual security audits, penetration testing, secure code reviews and automated vulnerability scans.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">These tests must also cover APIs, mobile backends, administration interfaces, third-party integrations and legacy components. Integrating these tests into CI\/CD pipelines enables vulnerabilities to be detected earlier in the development cycle and reduces the risk of an exploitable flaw reaching production.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As SQL injection remains one of the most dangerous and persistent web vulnerabilities, continuous security validation remains a cornerstone of any modern application security programme.<\/p>\n\n\n\n<h2 id=\"conclusion\" class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">SQL injection (SQLi) remains one of the most critical and widespread web vulnerabilities. It still features in the <a href=\"https:\/\/top10.owasp.org\/2025\/\" target=\"_blank\" rel=\"noopener\">OWASP Top 10<\/a> today and is listed as <a href=\"https:\/\/cwe.mitre.org\/data\/definitions\/89.html\" target=\"_blank\" rel=\"noopener\">CWE-89<\/a>, proof of its persistence.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It always stems from the same flaw: the lack of separation between the structure of a query and the data provided by the user. Whether the exploit involves a visible error, Boolean behaviour, a response delay or an external network channel, the underlying mechanism remains the same. This is why prepared queries, combined with a strict principle of least privilege, remain the most reliable defence, whether ORM is used or not.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It is important to bear in mind, however, that an application may appear to be protected by a modern framework whilst remaining vulnerable as soon as a developer introduces a fragment of unparameterised dynamic SQL. Consequently, prevention cannot rely solely on the choice of tools: it requires constant vigilance, regular testing and, above all, a clear understanding\u2014such as that developed in this guide\u2014of the actual mechanism behind each exploitation technique.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>SQL injection (SQLi) is one of the best-known vulnerabilities in web applications. Yet it remains a relevant threat in modern environments. Although frameworks, ORMs and data access libraries have significantly reduced the number of manually constructed SQL queries, they have not eliminated the risk altogether. It is precisely because this threat remains underestimated that it [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3452,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[19,24],"tags":[41,39,40,38],"class_list":["post-3958","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-applications","category-guides","tag-best-practices","tag-flaws-attacks","tag-owasp-top-10","tag-pentest"],"blocksy_meta":{"styles_descriptor":{"styles":{"desktop":"","tablet":"","mobile":""},"google_fonts":[],"version":8}},"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"What is an SQL injection? This article explains how SQLi works, the types of attacks, exploitation techniques, and security best practices to prevent the risks\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Eli T.\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"en_US\" \/>\n\t\t<meta property=\"og:site_name\" content=\"HackAgora \u2013 Expose. Understand. Defend.\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"SQL Injection (SQLi): Types, Exploitation and Security Tips\" \/>\n\t\t<meta property=\"og:description\" content=\"What is an SQL injection? This article explains how SQLi works, the types of attacks, exploitation techniques, and security best practices to prevent the risks\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/hackagora.com\/wp-content\/uploads\/2026\/06\/logo_hackagora_agora_color.svg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/hackagora.com\/wp-content\/uploads\/2026\/06\/logo_hackagora_agora_color.svg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"313\" \/>\n\t\t<meta property=\"og:image:height\" content=\"122\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2026-09-01T17:16:09+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2026-09-15T11:18:26+00:00\" \/>\n\t\t<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n\t\t<meta name=\"twitter:title\" content=\"SQL Injection (SQLi): Types, Exploitation and Security Tips\" \/>\n\t\t<meta name=\"twitter:description\" content=\"What is an SQL injection? This article explains how SQLi works, the types of attacks, exploitation techniques, and security best practices to prevent the risks\" \/>\n\t\t<meta name=\"twitter:image\" content=\"https:\/\/hackagora.com\/wp-content\/uploads\/2026\/06\/logo_hackagora_agora_color.svg\" \/>\n\t\t<script type=\"application\/ld+json\" class=\"aioseo-schema\">\n\t\t\t{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"BlogPosting\",\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/sql-injection-sqli-types-exploitation-and-security-best-practices\\\/#blogposting\",\"name\":\"SQL Injection (SQLi): Types, Exploitation and Security Tips\",\"headline\":\"SQL Injection (SQLi): Types, Exploitation and Security Best Practices\",\"author\":{\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/author\\\/traorea_hg\\\/#author\"},\"publisher\":{\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/#organization\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/hackagora.com\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/sqli.svg\",\"width\":885,\"height\":659,\"caption\":\"sql injection\"},\"datePublished\":\"2026-09-01T17:16:09+00:00\",\"dateModified\":\"2026-09-15T11:18:26+00:00\",\"inLanguage\":\"en-US\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/sql-injection-sqli-types-exploitation-and-security-best-practices\\\/#webpage\"},\"isPartOf\":{\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/sql-injection-sqli-types-exploitation-and-security-best-practices\\\/#webpage\"},\"articleSection\":\"Applications, Guides, best practices, flaws &amp; attacks, owasp top 10, pentest, Facultatif\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/sql-injection-sqli-types-exploitation-and-security-best-practices\\\/#breadcrumblist\",\"itemListElement\":[{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/#listItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/hackagora.com\\\/en\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/category\\\/applications\\\/#listItem\",\"name\":\"Applications\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/category\\\/applications\\\/#listItem\",\"position\":2,\"name\":\"Applications\",\"item\":\"https:\\\/\\\/hackagora.com\\\/en\\\/category\\\/applications\\\/\",\"nextItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/sql-injection-sqli-types-exploitation-and-security-best-practices\\\/#listItem\",\"name\":\"SQL Injection (SQLi): Types, Exploitation and Security Best Practices\"},\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/#listItem\",\"name\":\"Home\"}},{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/sql-injection-sqli-types-exploitation-and-security-best-practices\\\/#listItem\",\"position\":3,\"name\":\"SQL Injection (SQLi): Types, Exploitation and Security Best Practices\",\"previousItem\":{\"@type\":\"ListItem\",\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/category\\\/applications\\\/#listItem\",\"name\":\"Applications\"}}]},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/#organization\",\"name\":\"HackAgora\",\"description\":\"Expose. Understand. Defend.\",\"url\":\"https:\\\/\\\/hackagora.com\\\/en\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/hackagora.com\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/logo_hackagora_agora_color.svg\",\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/sql-injection-sqli-types-exploitation-and-security-best-practices\\\/#organizationLogo\",\"width\":313,\"height\":122},\"image\":{\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/sql-injection-sqli-types-exploitation-and-security-best-practices\\\/#organizationLogo\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/author\\\/traorea_hg\\\/#author\",\"url\":\"https:\\\/\\\/hackagora.com\\\/en\\\/author\\\/traorea_hg\\\/\",\"name\":\"Eli T.\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/sql-injection-sqli-types-exploitation-and-security-best-practices\\\/#authorImage\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/748941d304278b11e857c7ae5582eefefe0689f1b0642e56a2eda7b98bae722b?s=96&d=mm&r=g\",\"width\":96,\"height\":96,\"caption\":\"Eli T.\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/sql-injection-sqli-types-exploitation-and-security-best-practices\\\/#webpage\",\"url\":\"https:\\\/\\\/hackagora.com\\\/en\\\/sql-injection-sqli-types-exploitation-and-security-best-practices\\\/\",\"name\":\"SQL Injection (SQLi): Types, Exploitation and Security Tips\",\"description\":\"What is an SQL injection? This article explains how SQLi works, the types of attacks, exploitation techniques, and security best practices to prevent the risks\",\"inLanguage\":\"en-US\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/#website\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/sql-injection-sqli-types-exploitation-and-security-best-practices\\\/#breadcrumblist\"},\"author\":{\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/author\\\/traorea_hg\\\/#author\"},\"creator\":{\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/author\\\/traorea_hg\\\/#author\"},\"image\":{\"@type\":\"ImageObject\",\"url\":\"https:\\\/\\\/hackagora.com\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/sqli.svg\",\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/sql-injection-sqli-types-exploitation-and-security-best-practices\\\/#mainImage\",\"width\":885,\"height\":659,\"caption\":\"sql injection\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/sql-injection-sqli-types-exploitation-and-security-best-practices\\\/#mainImage\"},\"datePublished\":\"2026-09-01T17:16:09+00:00\",\"dateModified\":\"2026-09-15T11:18:26+00:00\"},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/#website\",\"url\":\"https:\\\/\\\/hackagora.com\\\/en\\\/\",\"name\":\"HackAgora\",\"description\":\"Expose. Understand. Defend.\",\"inLanguage\":\"en-US\",\"publisher\":{\"@id\":\"https:\\\/\\\/hackagora.com\\\/en\\\/#organization\"}}]}\n\t\t<\/script>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"SQL Injection (SQLi): Types, Exploitation and Security Tips","description":"What is an SQL injection? This article explains how SQLi works, the types of attacks, exploitation techniques, and security best practices to prevent the risks","canonical_url":"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"BlogPosting","@id":"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/#blogposting","name":"SQL Injection (SQLi): Types, Exploitation and Security Tips","headline":"SQL Injection (SQLi): Types, Exploitation and Security Best Practices","author":{"@id":"https:\/\/hackagora.com\/en\/author\/traorea_hg\/#author"},"publisher":{"@id":"https:\/\/hackagora.com\/en\/#organization"},"image":{"@type":"ImageObject","url":"https:\/\/hackagora.com\/wp-content\/uploads\/2026\/06\/sqli.svg","width":885,"height":659,"caption":"sql injection"},"datePublished":"2026-09-01T17:16:09+00:00","dateModified":"2026-09-15T11:18:26+00:00","inLanguage":"en-US","mainEntityOfPage":{"@id":"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/#webpage"},"isPartOf":{"@id":"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/#webpage"},"articleSection":"Applications, Guides, best practices, flaws &amp; attacks, owasp top 10, pentest, Facultatif"},{"@type":"BreadcrumbList","@id":"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/hackagora.com\/en\/#listItem","position":1,"name":"Home","item":"https:\/\/hackagora.com\/en\/","nextItem":{"@type":"ListItem","@id":"https:\/\/hackagora.com\/en\/category\/applications\/#listItem","name":"Applications"}},{"@type":"ListItem","@id":"https:\/\/hackagora.com\/en\/category\/applications\/#listItem","position":2,"name":"Applications","item":"https:\/\/hackagora.com\/en\/category\/applications\/","nextItem":{"@type":"ListItem","@id":"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/#listItem","name":"SQL Injection (SQLi): Types, Exploitation and Security Best Practices"},"previousItem":{"@type":"ListItem","@id":"https:\/\/hackagora.com\/en\/#listItem","name":"Home"}},{"@type":"ListItem","@id":"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/#listItem","position":3,"name":"SQL Injection (SQLi): Types, Exploitation and Security Best Practices","previousItem":{"@type":"ListItem","@id":"https:\/\/hackagora.com\/en\/category\/applications\/#listItem","name":"Applications"}}]},{"@type":"Organization","@id":"https:\/\/hackagora.com\/en\/#organization","name":"HackAgora","description":"Expose. Understand. Defend.","url":"https:\/\/hackagora.com\/en\/","logo":{"@type":"ImageObject","url":"https:\/\/hackagora.com\/wp-content\/uploads\/2026\/06\/logo_hackagora_agora_color.svg","@id":"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/#organizationLogo","width":313,"height":122},"image":{"@id":"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/#organizationLogo"}},{"@type":"Person","@id":"https:\/\/hackagora.com\/en\/author\/traorea_hg\/#author","url":"https:\/\/hackagora.com\/en\/author\/traorea_hg\/","name":"Eli T.","image":{"@type":"ImageObject","@id":"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/#authorImage","url":"https:\/\/secure.gravatar.com\/avatar\/748941d304278b11e857c7ae5582eefefe0689f1b0642e56a2eda7b98bae722b?s=96&d=mm&r=g","width":96,"height":96,"caption":"Eli T."}},{"@type":"WebPage","@id":"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/#webpage","url":"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/","name":"SQL Injection (SQLi): Types, Exploitation and Security Tips","description":"What is an SQL injection? This article explains how SQLi works, the types of attacks, exploitation techniques, and security best practices to prevent the risks","inLanguage":"en-US","isPartOf":{"@id":"https:\/\/hackagora.com\/en\/#website"},"breadcrumb":{"@id":"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/#breadcrumblist"},"author":{"@id":"https:\/\/hackagora.com\/en\/author\/traorea_hg\/#author"},"creator":{"@id":"https:\/\/hackagora.com\/en\/author\/traorea_hg\/#author"},"image":{"@type":"ImageObject","url":"https:\/\/hackagora.com\/wp-content\/uploads\/2026\/06\/sqli.svg","@id":"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/#mainImage","width":885,"height":659,"caption":"sql injection"},"primaryImageOfPage":{"@id":"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/#mainImage"},"datePublished":"2026-09-01T17:16:09+00:00","dateModified":"2026-09-15T11:18:26+00:00"},{"@type":"WebSite","@id":"https:\/\/hackagora.com\/en\/#website","url":"https:\/\/hackagora.com\/en\/","name":"HackAgora","description":"Expose. Understand. Defend.","inLanguage":"en-US","publisher":{"@id":"https:\/\/hackagora.com\/en\/#organization"}}]},"og:locale":"en_US","og:site_name":"HackAgora \u2013 Expose. Understand. Defend.","og:type":"article","og:title":"SQL Injection (SQLi): Types, Exploitation and Security Tips","og:description":"What is an SQL injection? This article explains how SQLi works, the types of attacks, exploitation techniques, and security best practices to prevent the risks","og:url":"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/","og:image":"https:\/\/hackagora.com\/wp-content\/uploads\/2026\/06\/logo_hackagora_agora_color.svg","og:image:secure_url":"https:\/\/hackagora.com\/wp-content\/uploads\/2026\/06\/logo_hackagora_agora_color.svg","og:image:width":313,"og:image:height":122,"article:published_time":"2026-09-01T17:16:09+00:00","article:modified_time":"2026-09-15T11:18:26+00:00","twitter:card":"summary_large_image","twitter:title":"SQL Injection (SQLi): Types, Exploitation and Security Tips","twitter:description":"What is an SQL injection? This article explains how SQLi works, the types of attacks, exploitation techniques, and security best practices to prevent the risks","twitter:image":"https:\/\/hackagora.com\/wp-content\/uploads\/2026\/06\/logo_hackagora_agora_color.svg"},"aioseo_meta_data":{"post_id":"3958","title":"SQL Injection (SQLi): Types, Exploitation and Security Tips","description":"What is an SQL injection? This article explains how SQLi works, the types of attacks, exploitation techniques, and security best practices to prevent the risks","keywords":null,"keyphrases":{"focus":{"keyphrase":"sql injection","score":0,"analysis":[]},"additional":[]},"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_custom_url":null,"og_image_custom_fields":null,"og_image_url":null,"og_image_width":null,"og_image_height":null,"og_video":"","og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_image_url":null,"twitter_title":null,"twitter_description":null,"schema_type":"default","schema_type_options":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"BlogPosting","isEnabled":true},"graphs":[]},"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":"-1","robots_max_videopreview":"-1","robots_max_imagepreview":"large","priority":null,"frequency":"default","local_seo":null,"limit_modified_date":false,"ai":{"faqs":[],"keyPoints":[],"schemas":[],"titles":[],"descriptions":[],"socialPosts":{"email":{"subject":"","preview":"","content":""},"linkedin":[],"twitter":[],"facebook":[],"instagram":[]}},"breadcrumb_settings":null,"seo_analyzer_scan_date":null,"created":"2026-09-15 08:57:06","updated":"2026-09-15 11:51:00","focus_keyword":"sql injection","additional_keywords":null,"truseo_locale":null},"aioseo_breadcrumb":"<div class=\"aioseo-breadcrumbs\"><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/hackagora.com\/en\/\" title=\"Home\">Home<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">\u00bb<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\t<a href=\"https:\/\/hackagora.com\/en\/category\/applications\/\" title=\"Applications\">Applications<\/a>\n\t\t<\/span><span class=\"aioseo-breadcrumb-separator\">\u00bb<\/span><span class=\"aioseo-breadcrumb\">\n\t\t\tSQL Injection (SQLi): Types, Exploitation and Security Best Practices\n\t\t<\/span><\/div>","aioseo_breadcrumb_json":[{"label":"Home","link":"https:\/\/hackagora.com\/en\/"},{"label":"Applications","link":"https:\/\/hackagora.com\/en\/category\/applications\/"},{"label":"SQL Injection (SQLi): Types, Exploitation and Security Best Practices","link":"https:\/\/hackagora.com\/en\/sql-injection-sqli-types-exploitation-and-security-best-practices\/"}],"_links":{"self":[{"href":"https:\/\/hackagora.com\/en\/wp-json\/wp\/v2\/posts\/3958","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hackagora.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hackagora.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hackagora.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hackagora.com\/en\/wp-json\/wp\/v2\/comments?post=3958"}],"version-history":[{"count":10,"href":"https:\/\/hackagora.com\/en\/wp-json\/wp\/v2\/posts\/3958\/revisions"}],"predecessor-version":[{"id":3968,"href":"https:\/\/hackagora.com\/en\/wp-json\/wp\/v2\/posts\/3958\/revisions\/3968"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/hackagora.com\/en\/wp-json\/wp\/v2\/media\/3452"}],"wp:attachment":[{"href":"https:\/\/hackagora.com\/en\/wp-json\/wp\/v2\/media?parent=3958"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hackagora.com\/en\/wp-json\/wp\/v2\/categories?post=3958"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hackagora.com\/en\/wp-json\/wp\/v2\/tags?post=3958"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}