0

I have an swift 5 app that posts data to update a mysql table. It works fine except, users noticed that having an ampersand & in the description field would cause app update function to fail.

here is component struct

import Foundation

struct Component: Codable {

  var sku, qty, desc, condition: String

  enum CodingKeys: String, CodingKey {
    case sku = "Sku"
    case qty = "Qty"
    case desc = "Desc"
    case condition = "Condition"
  }
}

here is my swift 5 code to create the post parameters

    var newCompUpload = [Component]()
    newCompUpload.append(newComp)

    let jsonData = try! JSONEncoder().encode(newCompUpload) 
    let uploadData = String(data: jsonData, encoding: .utf8)!

    let defaults = UserDefaults.standard
    let UserID = defaults.integer(forKey: "UserID")

    let postParameters1 = "mode="+mode+"&ShipmentID="+self.ShipmentID
    let postParameters2 = "&Contents="+uploadData+"&UserID=\(UserID)"
    let postParameters = postParameters1 + postParameters2 // + postParameters3
    request.httpBody = postParameters.data(using: String.Encoding.utf8, allowLossyConversion: false)

Here is an example of request.httpBody with an ampersand which breaks the json

mode=saveContents&ShipmentID=8702&Contents=[{"Qty":"1","Sku":"54657","Desc":"test & test","Condition":""}]&UserID=1437

This looks like it should make it to the server ok. But it doesn't. The following is what appears to make it to the server in the raw $_POST['Contents'] parameter

[{"Qty":"1","Sku":"54657","Desc":"test  

Obviously broken json at the ampersand. I am not really sure what is breaking it, or if I can change anything in swift delivery to get it to transfer correctly

Dávid Pásztor
  • 51,403
  • 9
  • 85
  • 116
Mike Volmar
  • 1,927
  • 1
  • 22
  • 31
  • 1
    See https://medium.com/swift2go/building-safe-url-in-swift-using-urlcomponents-and-urlqueryitem-alfian-losari-510a7b1f3c7e – Alexander Oct 22 '19 at 18:06
  • 1
    Also, your request doesn't have an impotency token, so that'll probably screw you over soon if you don't fix it. https://www.youtube.com/watch?v=IP-rGJKSZ3s – Alexander Oct 22 '19 at 18:07
  • 1
    Does this help? https://stackoverflow.com/questions/26364914/http-request-in-swift-with-post-method – BallpointBen Oct 22 '19 at 18:07

2 Answers2

5

You just discovered 2 programming lessons first hand:

  1. Never trust user content in contexts that have technical significance (e.g. some characters have special meanings in the context of URLs). SQL injection attacks would never have existed if people just managed to get this into their heads.
  2. Don't create your own query params with string interpolation. It's really easy to get wrong. In your case, you forgot to URL encode your strings. Instead, you should just use a library, which will do it all correctly for you. In this case, Foundation has URLComonents built in, which you can use to properly encode and construct your data into a URL, instead of manually interpolating strings.
Alexander
  • 59,041
  • 12
  • 98
  • 151
0

for folks who find this thread, here is code changes that worked in swift 5 implementing accepted answer's recommendation to use URLComponents

var components = URLComponents(url: requestURL! as URL, resolvingAgainstBaseURL: false)!

    components.queryItems = [
        URLQueryItem(name: "mode", value: mode),
        URLQueryItem(name: "ShipmentID", value: self.ShipmentID),
        URLQueryItem(name: "Contents", value: uploadData),
        URLQueryItem(name: "UserID", value: UserID),
        URLQueryItem(name: "Sku", value: self.Sku)
    ]

    let query = components.url!.query
    request.httpBody = query!.data(using: String.Encoding.utf8, 
    allowLossyConversion: false)
Mike Volmar
  • 1,927
  • 1
  • 22
  • 31