2

For my application, written in PHP 5+, I have a common.php which is included from all other pages. Within that I have an include sanitize.php which aims to sanitise any input vars used in the URL. So, targetting $_GET[] values.

This is just to have one place where I can tidy any vars, if used, and use them in the code later.

There seems to be no tidy way, I've seen, to sanitise based on expected/desired inputs. The method I initially looked at was this sanitize.php having a foreach to loop through any vars, lookup the type of sanitization required, and then add the cleaned vars to a separate array for use within my code.

Instead of using PHP sanitization filters, to keep it standard, I thought I'd use regex. Types I want are alphaonly, alphanumeric, email, password. Although "password" would allow some special chars, I want to remove or even escape potentially "hazardous" ones like ' " to then be included into a mysql DB. We have a european userbase so different locales are possible, but I'm hoping that won't be too much of an issue.

Would this be a "good" solution to start from, or am I trying to reinvent the wheel?

Random Page

/mypage.php?c=userid&p=lkasjdlakjsdlakj&z=....
(use SANITIZED_SAFE_INPUT_VARS variable only)

sanitize.php

var aryAllowedGetParamNames = array(
    "c" => "alphaonly",         //login
    "p" => "alphaemail",        //password
    "e" => "email"              //email
    //...
);

var sanitizeTypes = array (
    "alphaonly" => "[a-zA-Z]",
    "alphanumeric" => "[a-zA-Z0-9]",
    "email" => "[a-zA-Z0-9]...etc"
);

var SANITIZED_SAFE_INPUT_VARS = array();

foreach ($_GET as $key => $value) { 
    //apply regex and add value to SANITIZED_SAFE_INPUT_VARS 
}

EDIT

There seems to be some opinion about the use of passwords in the URL. I'll explain in a little more detail. Instead of using a POST login prompt with username and password, I am using an ajax async call to _db_tryLogin.php with parameters for userid and password. The username is ALWAYS a 6-ALPHA-only text string, and the password is an md5 of what was typed. I'm aware of the opinions on MD5 not being "safe enough".

The JS currently MD5s the password and sends that to the _db_tryLogin.php.

-> async : _db_login.php?c=ABCDEF&p=SLKDauwfLKASFUWPOjkjafkKoAWOIFHF2733287

This will return an async response of "1" or "0". Both will cause the page to refresh, but if the _db_tryLogin.php page detects the password and userid matches one DB record, then session variables are set and the site knows the user is logged in.

I used MD5 for the async request just to quickly hash the password so it's not transmitted in plaintext.

The _db_tryLogin.php takes the password, which is md5(plainpass) adds a SALT and MD5s again, and then this is what is compared against the usertable in the DB.

DB password stored = md5(SALT.md5(plainpass))

Jammo
  • 1,838
  • 4
  • 25
  • 39
  • rather than going through a long tedious process of allowing certain chararacters, simply *disallow* (ie remove) characters you don't want to accept, such as non-alphanumeric or backtick characters etc. It may also save you a lot of efforts to use the PHP `strip_tags()` function. – Martin Apr 13 '17 at 17:18
  • You spent some thought on this. But it's generally considered the wrong approach. Instead of treating input as "hazardous", look at your database API usage not being that. Escaping and sanitizing is always context-specific; not a blanket security gizmo. – mario Apr 13 '17 at 17:25
  • What are you sanitising against? If you're [only] trying to protect your SQL database **you're doing it wrong, and should be looking into *Prepared Statements***. – Martin Apr 13 '17 at 17:27
  • @Martin My main agenda is preventing injection and the page using a variable that it knows is trusted – Jammo Apr 13 '17 at 17:35
  • @Jammo their point is that isn't enough and if you ever expect to find a job doing this, it won't be accepted as a method of programming in a secure environment – clearshot66 Apr 13 '17 at 17:45
  • @clearshot66 "expect to find a job doing this" isn't productive, but thanks, I have a job. I'm asking for a solution to the question I asked. – Jammo Apr 13 '17 at 17:47
  • @Jammo well I wouldn't show them you're doing this stuff if you're in any secure environment programming because this is asking to be broken into lol – clearshot66 Apr 13 '17 at 17:52
  • `or am I trying to reinvent the wheel?` this is what you are currently doing, yes. But this can be a useful stepping stone to learning, at least... – Martin Apr 13 '17 at 17:53
  • Am I the only one concerned about PASSWORDS being in a $_GET-variable, in plain text? – junkfoodjunkie Apr 13 '17 at 17:59
  • @junkfoodjunkie Apologies, password is NOT one of the vars I will be parsing from a URL, however for simplicity I will be adding password to the array list sanitize filter – Jammo Apr 13 '17 at 18:02
  • Okay - regardless - unless you're very good with returning proper information to the user, "sanitizing" passwords should just not be done. Doing that is just begging for messed up passwords, and users getting fed up for not being able to use their preferred password, and then just finding something that fits the bare minimum for the site. Just don't. However, use prepared statements for passing the content (that is, the password-hash, not the actual password) to the database. Same for other inputs. – junkfoodjunkie Apr 13 '17 at 18:04
  • Edited question showing more info regarding password – Jammo Apr 13 '17 at 18:16
  • Jammo, your approach to passwords is entirely inappropriate and can't be recommended. By anyone. Please take a browse of the [Crypto Stack Exchange](https://crypto.stackexchange.com/) and why on earth do you not use POST data with your ajax calls? Over a TLS connection this would at least mean there is some basic password protection. Also don't bother md5ing, as there are plenty of lookup tables meaning md5 does ***not*** obscure the original plaintext.... – Martin Apr 13 '17 at 20:54
  • Ok, noted. How would you recommend I setup this architecture for a "simple" login approach on php mysql when the box I'm working on has no https. It's a relatively small simple app and tool for employees; I'm not exactly needing to build a fortress, however I do want to do it right, taking into account the feedback I've had on this question – Jammo Apr 14 '17 at 09:12

2 Answers2

1

What are you sanitising against? If you're [only] trying to protect your SQL database you're doing it wrong, and should be looking into Prepared Statements.

USER SUBMITTED DATA SHOULD NEVER BE TRUSTED. Accepted, yes, trusted - No.

Rather than going through a long tedious process of allowing certain chararacters, simply disallow (ie remove) characters you don't want to accept, such as non-alphanumeric or backtick characters etc. It may also save you a lot of efforts to use the PHP strip_tags() function.

1) Create your function in your include file. I would recommend creating it in an abstract Static Class, but that's a little beyond the scope of this answer.

2) Within this function/class method add your definitions for what bad characters you're looking for, and the data that these checks would apply to. You seem to have a good idea of your logic process, but be aware that there is no definitively correct code answer, as each programmers' needs from a string are different.

3) using the criteria defined in (2) you can then use the Regex to remove non-valid characters to return a "safe" set of variables.

example:

   // Remove backtick, single and double quotes from a variable.  
   // using PCRE Regex.
   $data = preg_relace("/[`"']/","",$data);

4) Use the PHP function strip_tags() to do just that and remove HTML and PHP code from a string.

5) For email validation use the PHP $email = filter_var($data, FILTER_SANITIZE_EMAIL); function, it will be far better than your own simple regex. Use PHP Filter Validations they are intended exactly for your sort of situation.

6) NEVER trust the output data, even if it passes all the checks and regexes you can give it, something may still get through. ALWAYS be VERY wary of user submitted data. NEVER trust it.

7) Use Prepared Statements for your SQL interactions.

8) As a shortcut for number types (int / float) you can use PHP type-casting to force a given varibles to being a certain type and destroying any chance of it being anything else:

$number = $_GET['number']; //can be anything.
$number = (int)$_GET['number']; //must be an integer or zero.

Notes:

  • Passwords should not be a-z only, but should be as many characters as you are able to choose from, the more the better.

  • If the efforts you are actioning here are for the case of protecting database security and integrity, you're doing it wrong, and should be using Prepared Statements for your MySQL interactions.

  • Stop using var to declare variables as this is from PHP4 and is VERY old, it is far better to use the Variable preconditional $ (such as $variable = true;) .

  • You state:

    We have a european userbase so different locales are possible

    To which I would highly recommend exploring PHP mb_string functions because natively PHP is not mutlibyte safe.

Community
  • 1
  • 1
Martin
  • 22,212
  • 11
  • 70
  • 132
1

I would to start just regex each variable , apply null if it doesn't match the requirements. Either test what it SHOULD have only, or what it shouldn't have, whichever is smaller:

$safeValue = (preg_match('/^[a-zA-Z0-9]{0,5}$/',$value) ? $value : "");

ALONG with prepared statements with parameter input aka

$query = "SELECT x FROM table WHERE id=?";
bind_param("si",$var,$var)

PHP also comes in with built filters, such as email and others). Example: filter_var($data, FILTER_SANITIZE_EMAIL)

http://php.net/manual/en/filter.filters.sanitize.php

Martin
  • 22,212
  • 11
  • 70
  • 132
clearshot66
  • 2,292
  • 1
  • 8
  • 17
  • applying `false` rather than null seems more logical, as then an `if` statement (`===`) can define it's failure to pass the regex intact. But this sort of detail is down to the OP I guess.... – Martin Apr 13 '17 at 17:49
  • @Martin generally later I use if($var != ""){ }, hence why. I empty it entirely. – clearshot66 Apr 13 '17 at 17:51