Prevention of LDAP injection attacks
package main
import (
"github.com/gin-gonic/gin"
"gopkg.in/ldap.v2"
"log"
)
func main() {
r := gin.Default()
r.GET("/search", func(c *gin.Context) {
username := c.Query("username")
l, err := ldap.Dial("tcp", "localhost:389")
if err != nil {
log.Fatal(err)
}
defer l.Close()
searchRequest := ldap.NewSearchRequest(
"dc=example,dc=com",
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=organizationalPerson)(uid=" + username + "))",
[]string{"dn", "cn", "givenName", "sn"},
nil,
)
sr, err := l.Search(searchRequest)
if err != nil {
log.Fatal(err)
}
for _, entry := range sr.Entries {
log.Println(entry.DN)
}
})
r.Run()
}
The above code is an example of an LDAP injection vulnerability in a Go application using gin framework. The application is set up to search for a user in an LDAP directory using a username passed as a query parameter.
The vulnerability lies in the following line of code:
"(&(objectClass=organizationalPerson)(uid=" + username + "))"
username
from the query parameters into the LDAP query without any sanitization or encoding. This means that if the username parameter contains any special characters used in LDAP queries, it could modify the query to return unintended results or perform unauthorized actions.admin*)(uid=*))(|(uid=*
which would modify the query to return all users instead of just the admin user. This is known as an LDAP injection attack.
package main
import (
"github.com/gin-gonic/gin"
"gopkg.in/ldap.v2"
"log"
"net/url"
)
func main() {
r := gin.Default()
r.GET("/search", func(c *gin.Context) {
username := c.Query("username")
// Validate and sanitize user input
username = url.QueryEscape(username)
l, err := ldap.Dial("tcp", "localhost:389")
if err != nil {
log.Fatal(err)
}
defer l.Close()
// Use parameterized queries
searchRequest := ldap.NewSearchRequest(
"dc=example,dc=com",
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=organizationalPerson)(uid=" + ldap.EscapeFilter(username) + "))",
[]string{"dn", "cn", "givenName", "sn"},
nil,
)
sr, err := l.Search(searchRequest)
if err != nil {
log.Fatal(err)
}
for _, entry := range sr.Entries {
log.Println(entry.DN)
}
})
r.Run()
}
The updated code includes several changes to mitigate the risk of LDAP injection:
1. Validate and sanitize user input: The 'username' parameter is sanitized using the
url.QueryEscape
function. This function encodes special characters in the 'username' parameter, which helps prevent LDAP injection attacks.
2. Use parameterized queries: The 'username' parameter is no longer concatenated directly into the LDAP query string. Instead, the
ldap.EscapeFilter
function is used to escape any special characters in the 'username' parameter. This function replaces special characters with their escaped equivalents, which prevents these characters from modifying the LDAP query.
3. Limit privileges and implement secure coding practices: Although not shown in the code, it's recommended to ensure that the LDAP user account used by the application has limited privileges and only has access to the necessary LDAP resources. Additionally, following secure coding practices such as input validation, output encoding, and parameterized queries can help minimize the risk of injection vulnerabilities.
4. Regularly update dependencies and perform security testing: Keeping the dependencies, such as the 'ldap' package, up to date can help benefit from any security patches or fixes. Regularly performing security testing, including penetration testing and code reviews, can help identify and address any potential vulnerabilities in the application.