Jump to content

Prevent Code Injection From Url


cbassett03

Recommended Posts

This is probably a broad question, but is there a way that I can prevent (or greatly reduce) code injection via someone typing in "parameters" into their address bar against a PHP script?

 

For example, preventing something like the known "1=1" injection that causes MySQL to return all values in a table.

 

Should I explicity check each variable to make sure it doesn't include "1=1" or something similar that would cause the database to return everything? I'm aware of htmlentities() function in PHP.

 

Just as an FYI, I generally send most of my data from HTML forms using the POST method, partially so the data and parameters are not shown to the user during transmission.

 

Any suggestions, or sites, that discuss PHP security? (I'd consider myself an intermediate PHP programmer at this point--I know my way around the language, but am getting more concerned with security as I move away from personal projects and into more "real-world" projects.)

Edited by cbassett03
Link to comment
Share on other sites

What you're talking about is input validation, but by the way of blacklisting. While input validation is necessary, doing so with a blacklist is not; You can never know every single instance of "bad" data, and even if you did it would be next to impossible managing the list every time a new attack form was found.

 

The better way to go about it is via white-listing, namely to allow only content you know is legal. Something which requires that you know exactly what kind of input you're getting, and all possible permutations of said content. Still quite a bit to keep track of, but far easier to manage than "everything bad", and the good list rarely changes.

To set up such a list you'll first and foremost need to sit down and formulate a rule for what you want to declare legal content, then you need to translate these rules into Regular Expressions1 or use the ctype_* () functions.

 

Now, since some of the good data might still pose a risk to external systems2 you still need to escape the output. This is done with the appropriate method for the target system, and only right before you send the data to said system.

Plenty of examples on this forum how to escape output, and as such a search is recommended.

 

For sites and places that discuss security, we got one right here. ;) Check the signatures of the Gurus and the other staff, quite a few of them have links to really good articles in them.

 

1 For some reason the forum software mangles "Expressions", thus foiled my attempt at making this link: http://www.regular-expressions.info/

2 Such as database engines, web browsers, e-mail servers/clients, and so forth.

Edited by Christian F.
Link to comment
Share on other sites

Just as an FYI, I generally send most of my data from HTML forms using the POST method, partially so the data and parameters are not shown to the user during transmission.

 

There is no difference between POST and GET data from a security standpoint. Do not thing that because the user does not see the value in the query string that they cannot modify the data. If you have a select list - do not assume that the value passed for that field was one of the ones that you defined for the list. Do not assume that a value you put into a hidden field is not going to be modified by the user. It is very easy for someone to create a modified form to send whatever data they want.

 

There are some tricks that I've seen used to try and prevent form submissions from external sources, but that only adds complexity with no real benefit. There are free tools available that allow a user to 'trap' http data being send from their computer and modify it before continuing on to the web server.

 

You need to validate and sanitize ALL data coming from the user: POST, GET, COOKIE, etc. Don't trust any of it. There is no way to cover absolutely every aspect of what you need to consider. You just need to stop and think about HOW each piece of data will be used and what you should expect the value to be. Here are some examples of the things I would consider:

 

With a select list the displayed label typically corresponds to an ID which will be the actual value passed and it is very common for that ID to correspond to an auto-increment integer in the DB. For any values that should be a integer ID you should always check for an integer or force the value to be an integer. Again, it depends on how it will be used.

 

SCENARIO #1

If the value is used to SELECT some data from the database (e.g. a search/filter) I may just force the value to be an integer by typecasting it as such or using intval(). If the value isn't even a number it will typically be converted to a 0. Auto-increment IDs always start as 1 by default. So, if the value is converted to a 0 (or some other integer that doesn't exist in the DB) then the worst that would happen is that the user would get no results or possible some invalid results - but since they purposefully tried to cheat the system I find that acceptable.

 

SCENARIO #2

Ok, let's say the value is used to SELECT data as above - but the ID is in a list of approved values that the user can select. In other words, there are values we don't want the user to be able to select. In that case (after forcing the value to an integer) I would want to do one of two things. 1) I could verify the value first by running a query to see if the passed value is in the list of approved IDs for the user. Or 2) I could adjust the query used to search the data to do that verification internally. I'm sure there are better ways, but here is a quick example:

 

Instead of this

SELECT *
FROM data_table
WHERE id = '$submittedID'

 

You could use this

SELECT *
FROM data_table
JOIN approved_ids
 ON data_table.id = approved_ids.id
AND approved_ids.user = '$thisUser'
WHERE id = '$submittedID'

 

Again, if the user submitted a non-approved ID then they just wouldn't get a result

 

SCENARIO #3:

Lastly, let's say that the value passed is used in the creation of a record, the value is required for the records and you must ensure it matches one of a list of existing IDs. For example, the record is for a car and the field is to select the make of the car. Then, in addition to checking or forcing it to be an integer you would want to do a DB check on the value to verify it is in the list of available IDs for makes of cars before trying to insert the record.

 

All of the above is just "off the top of my head" thoughts and does not represent everything to be considered or all possibilities. It is only meant to provide some advice on the thought process you would go through to determine what the right process is for your particular needs

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.