0

I need to prevent a user to create any input containing any quotes or brackets

    if(strpos($str, '"') !== false ||
    strpos($str, "'") !== false ||
    strpos($str, "<") !== false ||
    strpos($str, ">") !== false ||
    strpos($str, "(") !== false ||
    strpos($str, ")") !== false ||
    strpos($str, "{") !== false ||
    strpos($str, "}") !== false){
        echo "input is not allowed";
    }

1 - is there a shorter way to write this
2 - is this an enough safe way to sanitize inputs before place them inside a mysql database (using prepared statements)

qadenza
  • 9,025
  • 18
  • 73
  • 126
  • 1
    "2 - is this an enough safe way to sanitize inputs before place them inside a mysql database" NO! Read about prepared statements – Sindhara Dec 11 '20 at 19:05
  • @kuh-chan - I use prepared statements of course, but still don't need quotes and brackets inside the database – qadenza Dec 11 '20 at 19:07
  • 1
    For 2 look at [this](https://stackoverflow.com/questions/60174/how-can-i-prevent-sql-injection-in-php). – sticky bit Dec 11 '20 at 19:09
  • @qadenza If you do not need those characters I could recommend to use [CHECK constraint](https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html) or [triggers](https://dev.mysql.com/doc/refman/8.0/en/trigger-syntax.html) – Luuk Dec 11 '20 at 19:13
  • @Luuk - I don't need those characters but I need to say the user that he needs to remove those characters because some of the input can be his username or password – qadenza Dec 11 '20 at 19:16
  • @qadenza: A good [note](http://www.sussex.ac.uk/its/help/faq?faqid=839) on the screen about which characters should be sufficient. Implementing the check database-side will REALLY prevent those characters from entering the database. – Luuk Dec 11 '20 at 19:22
  • This kind of code, regardless of the intent, makes it look like you're trying to prevent XSS or SQL injection using the ham-fisted, completely unreliable method of just not allowing certain characters. Why are you forbidding single quotes? Do you want someone with an apostrophe in their name being forbidden from expressing their name properly? – tadman Dec 11 '20 at 19:24
  • 1
    Remember that "sanitizing" is generally for cosmetic things, like trimming excess spaces or removing non-UTF-8 characters, not things like injection or escaping protection. Each context you use this data in has wildly different constraints and threat vectors. Use the escaping method for any given context *if* and *when* you're in that context, be it HTML, JSON, SQL or otherwise. – tadman Dec 11 '20 at 19:26
  • In your question, you should specify the purpose of "prevent(ing) a user to create any input containing any quotes or brackets". – AbsoluteBeginner Dec 11 '20 at 19:28
  • @tadman - can you give me any example where a database is attacked by a string `not-containing` quotes and brackets – qadenza Dec 11 '20 at 19:29
  • Some of the vectors involve using things that are quotes as far as MySQL is concerned, but aren't quotes as far as `"` is concerned, so-called "Unicode smuggling". Tools like [sqlmap](http://sqlmap.org) have a huge bag of tricks that involve working around naïve SQL injection protection like stripping characters. The only reliably safe way is *placeholder values*. – tadman Dec 11 '20 at 19:32
  • This code is effectively worthless. It will reject `James O'Malley` but not `James O‘Malley` or `“Eat My Shorts”` or `⋜Ha!⋝`. – tadman Dec 11 '20 at 19:36
  • @tadman - placeholder value - i suppose it can also be compromised - using brutal force (guessing) - for example – qadenza Dec 11 '20 at 19:37
  • How could a placeholder value be brute forced or compromised? It will *only* ever go to where it's intended to go, and will never run arbitrary SQL commands. The way the MySQL protocol is structured these values are sent over separately from the SQL statement itself, there is no way they can get confused with SQL code. – tadman Dec 11 '20 at 19:38
  • @tadman - `$sql = "insert into table (name) values(:abc)"` - `:abc` could be guessed - isn't it? – qadenza Dec 11 '20 at 19:42
  • 1
    So what? That doesn't help an attacker. If they can `$_POST` something, and you put that something in the `:abc` placeholder, then that's all they can do: Exactly what you allow them to. They can't put in arbitrary SQL. The name of the placeholder is largely irrelevant, even if you do `execute($_POST)` and just hope for the best. – tadman Dec 11 '20 at 19:43
  • @tadman - but the value you placed inside `:abc` is later placed into a table during `execute()` proccess – qadenza Dec 11 '20 at 19:45
  • Which is what you've allowed them to do by virtue of your `execute()` call. If you don't want them to have that control, don't take their input or provide a binding for the input to go. The name of the placeholder doesn't really matter, what does matter is what you bind that placeholder to, and you have *full* control over that. – tadman Dec 11 '20 at 19:46
  • @tadman - I don't have full control - because I must bind the value of users input and not any other value – qadenza Dec 11 '20 at 19:50
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/225840/discussion-between-tadman-and-qadenza). – tadman Dec 11 '20 at 19:52

2 Answers2

3
  1. Yes, using Regex:

    $str = 'Test {';
    $exp = '/[\"\\\'\<\>\(\)\{\}]/';
    if (preg_match($exp, $str)) {
      die("Input is not allowed");
    }
    
  2. No. You should take a look at PreparedStatements.

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Daniel
  • 1,426
  • 1
  • 11
  • 24
1

Try it this way.

$pattern = array('/[^0-9a-z]+/i', '/[^0-9a-z]+(?=$)/i');
$replacement = array('', '');
$subject = trim(str_replace(" ", "", $str));

$new_str= filter_var(preg_replace($pattern, $replacement, $subject), FILTER_SANITIZE_STRING);

What ever that's not in the pattern will be removed...

Everything good
  • 321
  • 4
  • 10