Prevention of time-based SQL injection attacks
package main
import (
"database/sql"
"github.com/gin-gonic/gin"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "user:password@/dbname")
if err != nil {
panic(err)
}
defer db.Close()
router := gin.Default()
router.GET("/user/:id", func(c *gin.Context) {
id := c.Param("id")
var username string
row := db.QueryRow("SELECT username FROM users WHERE id = " + id)
row.Scan(&username)
c.JSON(200, gin.H{
"user": username,
})
})
router.Run(":8080")
}
In the above code, the application is vulnerable to time-based SQL injection attacks. The vulnerability lies in the route handler for "/user/:id". The application takes a user ID from the URL parameter and directly concatenates it into a SQL query without any sanitization or parameterization.
An attacker could exploit this vulnerability by injecting a time-based SQL command, such as
1 OR SLEEP(5)=0 --
, as the user ID. This would cause the application to execute the SQL query
SELECT username FROM users WHERE id = 1 OR SLEEP(5)=0 --
, delaying the response by 5 seconds and confirming the presence of a SQL injection vulnerability.
The application is also vulnerable to other forms of SQL injection, as it does not sanitize or parameterize the user input in any way. This could allow an attacker to manipulate the SQL query to extract, modify, or delete data from the database.
package main
import (
"database/sql"
"github.com/gin-gonic/gin"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", "user:password@/dbname")
if err != nil {
panic(err)
}
defer db.Close()
router := gin.Default()
router.GET("/user/:id", func(c *gin.Context) {
id := c.Param("id")
var username string
// Use prepared statement
stmt, err := db.Prepare("SELECT username FROM users WHERE id = ?")
if err != nil {
panic(err)
}
// Execute the prepared statement with the provided id
err = stmt.QueryRow(id).Scan(&username)
if err != nil {
panic(err)
}
c.JSON(200, gin.H{
"user": username,
})
})
router.Run(":8080")
}
The original code was vulnerable to Time-based SQL Injection attacks because it concatenated the 'id' parameter directly into the SQL query. This could allow an attacker to inject malicious SQL code into the query, causing a delay in the execution of the queries or executing a heavy query that generates a time delay.
The fixed code uses a prepared statement to prevent SQL injection. Instead of concatenating the 'id' directly into the SQL query, it binds the 'id' to a placeholder in the query (
?
). This ensures that the 'id' is treated strictly as a value, not part of the SQL command, thus preventing SQL injection.
The 'id' parameter is obtained from the request context using
c.Param("id")
. It's important to validate and sanitize this 'id' parameter before using it in the query. This code assumes that such validation and sanitization are done before this point. If not, you should add appropriate validation and sanitization code.
To prevent time-based attacks, you should also limit the execution time of SQL queries. This can be done using database-specific features or libraries. Regularly updating and patching the database and database driver can also help to fix any known vulnerabilities.