Lack of data validation - Swift

Lack of data validation - Swift

Need

Implementation of robust data validation mechanisms

Context

  • Usage of Swift for iOS and macOS app development
  • Usage of Foundation for building responsive and customizable web interfaces

Description

Non compliant code

        import Foundation

class User {
    var id: String
    var name: String
    var email: String

    init(id: String, name: String, email: String) {
        self.id = id
        self.name = name
        self.email = email
    }
}

func updateUser(id: String, name: String?, email: String?) {
    let user = User(id: id, name: name ?? "", email: email ?? "")
    // update user in database
}

// Usage
updateUser(id: "abc", name: "John", email: "john@example.com")
        
        

In this code, there is a User class with an id field that is a String. The updateUser function is used to update a user in the database. However, the function does not validate the id field before updating the user.

This means that an ID composed of only letters can be used to update a user, which may not be valid depending on the system's requirements. If the system expects IDs to be numeric or alphanumeric, using an ID composed of only letters could lead to unexpected behavior or errors.

Furthermore, if the system uses the ID to look up a user in the database, an invalid ID could lead to the wrong user being updated or no user being updated at all.

This lack of data validation can lead to data integrity issues and potential security vulnerabilities, as it could allow an attacker to manipulate the system by providing invalid data.

Steps

  • Implement server-side validation to ensure that only valid data is accepted.
  • Validate the input data on the client-side before sending it to the server.
  • Use appropriate data types for each field to prevent invalid data from being accepted.
  • Implement input sanitization to remove any potentially harmful characters from the input data.
  • Implement proper error handling to handle invalid data and provide meaningful error messages to the user.
  • Regularly update and patch the server-side code to address any newly discovered vulnerabilities.

Compliant code

        import Foundation

class User {
    var id: String
    var name: String
    var email: String

    init?(id: String, name: String, email: String) {
        // Validate ID
        let idRegex = "^[0-9]+$"
        let idTest = NSPredicate(format:"SELF MATCHES %@", idRegex)
        guard idTest.evaluate(with: id) else {
            return nil
        }
        
        // Validate name
        guard !name.isEmpty else {
            return nil
        }
        
        // Validate email
        let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\\\.[A-Za-z]{2,64}"
        let emailTest = NSPredicate(format:"SELF MATCHES %@", emailRegex)
        guard emailTest.evaluate(with: email) else {
            return nil
        }
        
        self.id = id
        self.name = name
        self.email = email
    }
}

func updateUser(id: String, name: String?, email: String?) {
    guard let user = User(id: id, name: name ?? "", email: email ?? "") else {
        print("Invalid data")
        return
    }
    // update user in database
}

// Usage
updateUser(id: "123", name: "John", email: "john@example.com")
        
        

The updated code now includes validation for the id, name, and email fields in the User class.

The id field is validated to ensure it only contains numbers. This is done using a regular expression (regex) that matches any string composed entirely of numbers. If the id does not match this pattern, the initializer returns nil, indicating that the creation of the User object failed due to invalid data.

The name field is validated to ensure it is not empty. If the name is empty, the initializer also returns nil.

The email field is validated using a regex that matches a typical email format. If the email does not match this pattern, the initializer returns nil.

In the updateUser function, the creation of the User object is now done using optional binding ( guard let). If the User initializer returns nil (which it will do if any of the data is invalid), the function prints an error message and returns early. This prevents the function from attempting to update the database with invalid data.

References