Your best and most secure option is to not allow SQL to be entered directly, but rather to be built from methods you expose to the client. Whenever you process any string data, check for injection to make sure the user is not attempting to bypass what controls you have in place. The end consumer should never invoke a simple SQL statement directly.
For example, using a table "Products" and exposing this to the customer for consumption, the methods might look like the following:
function GetAllProductsByAmount(topn:integer):tDataset;
//Returns all products sorted by amount, no more than topn.}
function GetAllProductsByName(topn:integer):tDataset;
//Returns all products sorted by name, no more than topn}
function FindProductByName(name:string):tDataset;
//returns all products which start with name}
The FindProductByName
function would have a check to insure that there are no extra quotes in the name, and if so to return an empty set. I also generally perform an automatic wildcard query if the first query results in no data.
For the download/upload logic, make sure that the entire request goes through your system. The storage point for the user files should be in a protected area that is NOT exposed to the outside world, but is only available to the inside. When a request for a protected resource comes in, you can check the credentials and if they are not correct refuse the file. If everything is ok, then you open and stream the file to the user. If your files are extremely large, then consider an FTP server with individual users so that each user has its own private directory. This does require more maintenance, but would allow users to download their data faster since the FTP server is tuned for just this kind of access. As noted in the comments below, FTP is not secure enough since the username and passwords are sent plain text.
For this type of application what I have traditionally done was create a session cookie that contains a guid on the server and marked that in a table along with the last valid access date/time (and IP Address). The only time the session cookie gets created is upon successful login. Each time I get a request, I verify that this cookie is available and still valid (I time mine out after say 30 minutes), I then update the time stamp of the last access. If a user logs off then I also delete their session cookie. Any request with an invalid session cookie redirects to the login page. This keeps things simple, and reduces the amount of data that needs to be looked up to just who is online in the last 30 minutes (or not logged out and not yet cleaned up). I automatically purge all invalid logins which have expired at each login/logout attempt.
For your webservice, you can do something simular. Have a LOGIN routine which returns a guid and require the guid to be passed at each request. If its not valid, then reject the request.