Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 398 Vote(s) - 3.51 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Why shouldn't I use mysql_* functions in PHP?

#11
PHP offers three different APIs to connect to MySQL. These are the [`mysql`][1](removed as of PHP 7), [`mysqli`][2], and [`PDO`][3] extensions.

The `mysql_*` functions used to be very popular, but their use is not encouraged anymore. The documentation team is discussing the database security situation, and educating users to move away from the commonly used ext/mysql extension is part of this (check *[php.internals: deprecating ext/mysql][4]*).

And the later PHP developer team has taken the decision to generate [**`E_DEPRECATED`**][5] errors when users connect to MySQL, whether through `mysql_connect()`, `mysql_pconnect()` or the implicit connection functionality built into `ext/mysql`.

**`ext/mysql`** was [**officially deprecated as of PHP 5.5**][6] and has been [**removed as of PHP 7**][7].

**See the Red Box?**

When you go on any `mysql_*` function manual page, you see a red box, explaining it should not be used anymore.

Why
---
-----
Moving away from `ext/mysql` is not only about security, but also about having access to all the features of the MySQL database.

`ext/mysql` was built for **MySQL 3.23** and only got very few additions since then while mostly keeping compatibility with this old version which makes the code a bit harder to maintain. Missing features that is not supported by `ext/mysql` include: (*[from PHP manual][6]*).

* [Stored procedures][8] (can't handle multiple result sets)
* [Prepared statements][9]
* Encryption (SSL)
* Compression
* Full Charset support

**Reason to not use `mysql_*` function**:

* Not under active development
* Removed as of PHP 7
* Lacks an OO interface
* Doesn't support non-blocking, asynchronous queries
* Doesn't support prepared statements or [parameterized queries][9]
* Doesn't support stored procedures
* Doesn't support multiple statements
* Doesn't support [transactions][10]
* Doesn't support all of the functionality in MySQL 5.1

[Above point quoted from Quentin's answer][11]

Lack of support for prepared statements is particularly important as they provide a clearer, less error prone method of escaping and quoting external data than manually escaping it with a separate function call.

See the [comparison of SQL extensions][12].

-----

**Suppressing deprecation warnings**

While code is being converted to `MySQLi`/`PDO`, `E_DEPRECATED` errors can be suppressed by setting `error_reporting` in **php.ini** to exclude `E_DEPRECATED:`

error_reporting = E_ALL ^ E_DEPRECATED

Note that this will also hide **other deprecation warnings**, which, however, may be for things other than MySQL. (*[from PHP manual][13]*)

The article *[PDO vs. MySQLi: Which Should You Use?][14]* by [**Dejan Marjanovic**][15] will help you to choose.

And a better way is `PDO`, and I am now writing a simple `PDO` tutorial.

------

<h2>A simple and short PDO tutorial</h2>

-----

<h3><span class="question">Q.</span> First question in my mind was: what is `PDO`?</h3>

<span class="answer">A.</span> “**PDO – PHP Data Objects** – is a database access layer providing a uniform method of access to multiple databases.”

>![alt text][16]

----
<h3>Connecting to MySQL </h3>

With `mysql_*` function or we can say it the old way (deprecated in PHP 5.5 and above)

$link = mysql_connect('localhost', 'user', 'pass');
mysql_select_db('testdb', $link);
mysql_set_charset('UTF-8', $link);

With `PDO`: All you need to do is create a new `PDO` object. The constructor accepts parameters for specifying the database source `PDO`'s constructor mostly takes four parameters which are `DSN` (data source name) and optionally `username`, `password`.

Here I think you are familiar with all except `DSN`; this is new in `PDO`. A `DSN` is basically a string of options that tell `PDO` which driver to use, and connection details. For further reference, check [PDO MySQL DSN](

[To see links please register here]

).

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');

**Note:** you can also use `charset=UTF-8`, but sometimes it causes an error, so it's better to use `utf8`.

If there is any connection error, it will throw a `PDOException` object that can be caught to handle `Exception` further.

**Good read**: [Connections and Connection management ¶][17]

You can also pass in several driver options as an array to the fourth parameter. I recommend passing the parameter which puts `PDO` into exception mode. Because some `PDO` drivers don't support native prepared statements, so `PDO` performs emulation of the prepare. It also lets you manually enable this emulation. To use the native server-side prepared statements, you should explicitly set it `false`.

The other is to turn off prepare emulation which is enabled in the `MySQL` driver by default, but prepare emulation should be turned off to use `PDO` safely.

I will later explain why prepare emulation should be turned off. To find reason please check [this post][18].

It is only usable if you are using an old version of `MySQL` which I do not recommended.

Below is an example of how you can do it:

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8',
'username',
'password',
array(PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));

**Can we set attributes after PDO construction?**

**Yes**, we can also set some attributes after PDO construction with the `setAttribute` method:

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8',
'username',
'password');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

<h2>Error Handling </h2>

------

Error handling is much easier in `PDO` than `mysql_*`.

A common practice when using `mysql_*` is:

//Connected to MySQL
$result = mysql_query("SELECT * FROM table", $link) or die(mysql_error($link));

`OR die()` is not a good way to handle the error since we can not handle the thing in `die`. It will just end the script abruptly and then echo the error to the screen which you usually do NOT want to show to your end users, and let bloody hackers discover your schema. Alternately, the return values of `mysql_*` functions can often be used in conjunction with [mysql_error\(\)](

[To see links please register here]

) to handle errors.

`PDO` offers a better solution: exceptions. Anything we do with `PDO` should be wrapped in a `try`-`catch` block. We can force `PDO` into one of three error modes by setting the error mode attribute. Three error handling modes are below.

* `PDO::ERRMODE_SILENT`. It's just setting error codes and acts pretty much the same as `mysql_*` where you must check each result and then look at `$db->errorInfo();` to get the error details.
* `PDO::ERRMODE_WARNING` Raise `E_WARNING`. (Run-time warnings (non-fatal errors). Execution of the script is not halted.)
* `PDO::ERRMODE_EXCEPTION`: Throw exceptions. It represents an error raised by PDO. You should not throw a `PDOException` from your own code. See *Exceptions* for more information about exceptions in PHP. It acts very much like `or die(mysql_error());`, when it isn't caught. But unlike `or die()`, the `PDOException` can be caught and handled gracefully if you choose to do so.

**Good read**:

- [Errors and error handling ¶][19]
- [The PDOException class ¶][20]
- [Exceptions ¶][21]

Like:

$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

And you can wrap it in `try`-`catch`, like below:

try {
//Connect as appropriate as above
$db->query('hi'); //Invalid query!
}
catch (PDOException $ex) {
echo "An Error occured!"; //User friendly message/message you want to show to user
some_logging_function($ex->getMessage());
}

You do not have to handle with `try`-`catch` right now. You can catch it at any time appropriate, but I strongly recommend you to use `try`-`catch`. Also it may make more sense to catch it at outside the function that calls the `PDO` stuff:

function data_fun($db) {
$stmt = $db->query("SELECT * FROM table");
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

//Then later
try {
data_fun($db);
}
catch(PDOException $ex) {
//Here you can handle error and show message/perform action you want.
}

Also, you can handle by `or die()` or we can say like `mysql_*`, but it will be really varied. You can hide the dangerous error messages in production by turning `display_errors off` and just reading your error log.

Now, after reading all the things above, you are probably thinking: what the heck is that when I just want to start leaning simple `SELECT`, `INSERT`, `UPDATE`, or `DELETE` statements? Don't worry, here we go:

------
Selecting Data
-----

![PDO select image][22]

So what you are doing in `mysql_*` is:

<?php
$result = mysql_query('SELECT * from table') or die(mysql_error());

$num_rows = mysql_num_rows($result);

while($row = mysql_fetch_assoc($result)) {
echo $row['field1'];
}

Now in `PDO`, you can do this like:

<?php
$stmt = $db->query('SELECT * FROM table');

while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $row['field1'];
}

Or

<?php
$stmt = $db->query('SELECT * FROM table');
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);

//Use $results

**Note**: If you are using the method like below (`query()`), this method returns a `PDOStatement` object. So if you want to fetch the result, use it like above.

<?php
foreach($db->query('SELECT * FROM table') as $row) {
echo $row['field1'];
}

In PDO Data, it is obtained via the `->fetch()`, a method of your statement handle. Before calling fetch, the best approach would be telling PDO how you’d like the data to be fetched. In the below section I am explaining this.

Fetch Modes
---

Note the use of `PDO::FETCH_ASSOC` in the `fetch()` and `fetchAll()` code above. This tells `PDO` to return the rows as an associative array with the field names as keys. There are many other fetch modes too which I will explain one by one.

First of all, I explain how to select fetch mode:

$stmt->fetch(PDO::FETCH_ASSOC)

In the above, I have been using `fetch()`. You can also use:

* [`PDOStatement::fetchAll()`][23] - Returns an array containing all of the result set rows
* [`PDOStatement::fetchColumn()`][24] - Returns a single column from the next row of a result set
* [`PDOStatement::fetchObject()`][25] - Fetches the next row and returns it as an object.
* [`PDOStatement::setFetchMode()`][26] - Set the default fetch mode for this statement

Now I come to fetch mode:

* `PDO::FETCH_ASSOC`: returns an array indexed by column name as returned in your result set
* `PDO::FETCH_BOTH` (default): returns an array indexed by both column name and 0-indexed column number as returned in your result set

There are even more choices! Read about them all in [`PDOStatement` Fetch documentation.][27].

**Getting the row count**:

Instead of using `mysql_num_rows` to get the number of returned rows, you can get a `PDOStatement` and do `rowCount()`, like:

<?php
$stmt = $db->query('SELECT * FROM table');
$row_count = $stmt->rowCount();
echo $row_count.' rows selected';

**Getting the Last Inserted ID**

<?php
$result = $db->exec("INSERT INTO table(firstname, lastname) VAULES('John', 'Doe')");
$insertId = $db->lastInsertId();

-------

Insert and Update or Delete statements
----

![Insert and update PDO image][28]

What we are doing in `mysql_*` function is:

<?php
$results = mysql_query("UPDATE table SET field='value'") or die(mysql_error());
echo mysql_affected_rows($result);

And in pdo, this same thing can be done by:

<?php
$affected_rows = $db->exec("UPDATE table SET field='value'");
echo $affected_rows;

In the above query [`PDO::exec`][29] execute an SQL statement and returns the number of affected rows.

<sub>*Insert and delete will be covered later.*</sub>

The above method is only useful when you are not using variable in query. But when you need to use a variable in a query, do not ever ever try like the above and there for [**prepared statement or parameterized statement**][9] is.

------

**Prepared Statements**
---

**Q.** What is a prepared statement and why do I need them?<br>
**A.** A prepared statement is a pre-compiled SQL statement that can be executed multiple times by sending only the data to the server.<br>

The typical workflow of using a prepared statement is as follows ([quoted from Wikipedia three 3 point][9]):

1. **Prepare**: The statement template is created by the application and sent to the database management system (DBMS). Certain values are left unspecified, called parameters, placeholders or bind variables (labelled `?` below):

`INSERT INTO PRODUCT (name, price) VALUES (?, ?)`

2. The DBMS parses, compiles, and performs query optimization on the statement template, and stores the result without executing it.
3. **Execute**: At a later time, the application supplies (or binds) values for the parameters, and the DBMS executes the statement (possibly returning a result). The application may execute the statement as many times as it wants with different values. In this example, it might supply 'Bread' for the first parameter and `1.00` for the second parameter.

You can use a prepared statement by including placeholders in your SQL. There are basically three ones without placeholders (don't try this with variable its above one), one with unnamed placeholders, and one with named placeholders.

**Q.** So now, what are named placeholders and how do I use them?<br>
**A.** Named placeholders. Use descriptive names preceded by a colon, instead of question marks. We don't care about position/order of value in name place holder:

$stmt->bindParam(':bla', $bla);

[`bindParam(parameter,variable,data_type,length,driver_options)`][30]

You can also bind using an execute array as well:

<?php
$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
$stmt->execute(array(':name' => $name, ':id' => $id));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

Another nice feature for `OOP` friends is that named placeholders have the ability to insert objects directly into your database, assuming the properties match the named fields. For example:

class person {
public $name;
public $add;
function __construct($a,$b) {
$this->name = $a;
$this->add = $b;
}

}
$demo = new person('john','29 bla district');
$stmt = $db->prepare("INSERT INTO table (name, add) value (:name, :add)");
$stmt->execute((array)$demo);

**Q.** So now, what are unnamed placeholders and how do I use them?<br>
**A.** Let's have an example:

<?php
$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->bindValue(2, $add, PDO::PARAM_STR);
$stmt->execute();

and

$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->execute(array('john', '29 bla district'));

In the above, you can see those `?` instead of a name like in a name place holder. Now in the first example, we assign variables to the various placeholders (`$stmt->bindValue(1, $name, PDO::PARAM_STR);`). Then, we assign values to those placeholders and execute the statement. In the second example, the first array element goes to the first `?` and the second to the second `?`.

**NOTE**: In **unnamed placeholders** we must take care of the proper order of the elements in the array that we are passing to the `PDOStatement::execute()` method.

-----

`SELECT`, `INSERT`, `UPDATE`, `DELETE` prepared queries
----

1. **`SELECT`**:

$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
$stmt->execute(array(':name' => $name, ':id' => $id));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

2. **`INSERT`**:

$stmt = $db->prepare("INSERT INTO table(field1,field2) VALUES(:field1,:field2)");
$stmt->execute(array(':field1' => $field1, ':field2' => $field2));
$affected_rows = $stmt->rowCount();


3. **`DELETE`**:

$stmt = $db->prepare("DELETE FROM table WHERE id=:id");
$stmt->bindValue(':id', $id, PDO::PARAM_STR);
$stmt->execute();
$affected_rows = $stmt->rowCount();

4. **`UPDATE`**:

$stmt = $db->prepare("UPDATE table SET name=? WHERE id=?");
$stmt->execute(array($name, $id));
$affected_rows = $stmt->rowCount();

-------

**NOTE:**
---

However `PDO` and/or `MySQLi` are not completely safe. Check the answer *[Are PDO prepared statements sufficient to prevent SQL injection?][18]* by [ircmaxell][31]. Also, I am quoting some part from his answer:

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->query('SET NAMES GBK');
$stmt = $pdo->prepare("SELECT * FROM test WHERE name = ? LIMIT 1");
$stmt->execute(array(chr(0xbf) . chr(0x27) . " OR 1=1 /*"));


[1]:

[To see links please register here]

[2]:

[To see links please register here]

[3]:

[To see links please register here]

[4]:

[To see links please register here]

[5]:

[To see links please register here]

[6]:

[To see links please register here]

[7]:

[To see links please register here]

[8]:

[To see links please register here]

[9]:

[To see links please register here]

[10]:

[To see links please register here]

[11]:

[To see links please register here]

[12]:

[To see links please register here]

[13]:

[To see links please register here]

[14]:

[To see links please register here]

[15]:

[To see links please register here]

[16]:

[17]:

[To see links please register here]

[18]:

[To see links please register here]

[19]:

[To see links please register here]

[20]:

[To see links please register here]

[21]:

[To see links please register here]

[22]:

[23]:

[To see links please register here]

[24]:

[To see links please register here]

[25]:

[To see links please register here]

[26]:

[To see links please register here]

[27]:

[To see links please register here]

[28]:

[29]:

[To see links please register here]

[30]:

[To see links please register here]

[31]:

[To see links please register here]

Reply

#12
The MySQL extension:

* Is not under active development
* Is **officially [deprecated][1]** as of PHP 5.5 (released June 2013).
* Has been **[removed](

[To see links please register here]

) entirely** as of PHP 7.0 (released December 2015)
* This means that as of [31 Dec 2018][4] it does not exist in any supported version of PHP. If you are using a version of PHP which supports it, you are using a version which doesn't get security problems fixed.
* Lacks an OO interface
* Doesn't support:
* Non-blocking, asynchronous queries
* **[Prepared statements][2] or parameterized queries**
* Stored procedures
* Multiple Statements
* Transactions
* The "new" password authentication method (on by default in MySQL 5.6; required in 5.7)
* Any of the new functionality in MySQL 5.1 or later

Since it is deprecated, using it makes your code less future proof.

Lack of support for prepared statements is particularly important as they provide a clearer, less error-prone method of escaping and quoting external data than manually escaping it with a separate function call.

See [**the comparison of SQL extensions**][3].


[1]:

[To see links please register here]

[2]:

[To see links please register here]

[3]:

[To see links please register here]

[4]:

[To see links please register here]

Reply

#13
## Don't use mysql because is deprecated use Mysqli Instead. ##


**What Deprecated Means:**

It means don't use some specific function/method/software feature/particular software practice it just means that it should not be used because there is (or there will be) a better alternative in that software that should be used instead.

**Several common issues can arise when using deprecated functions:**

**1. Functions just flat-out stop working:** Applications or scripts might rely on functions that are simply no longer supported, Thus use their improved versions or alternative.

**2. Warning messages display about deprecation**: These messages don’t normally interfere with site functionality. However, in some cases, they might disrupt the process of the server sending headers.

For Example: This can cause login issues (cookies/sessions don’t get set properly) or forwarding issues (301/302/303 redirects).

**keep in mind that:**

-Deprecated software is still a part of the software.

-Deprecated code is just a status (label) of the code.


**Key Differences in MYSQL vs MYSQLI**
mysql*
- old database driver
- MySQL can only be used procedurally
- No protection from SQL injection attack
- Was deprecated in PHP 5.5.0 and was removed in PHP 7


mysqli
- new database driver
- Currently under usage
- prepared statements protect from attacks
Reply

#14
There is no need to update if you are sure you don't want to upgrade php version , But at the same time you won't get security updates too which will make your website more vulnerable to hackers that's the main reason.
Reply

#15
This answer is written to show just how trivial it is to bypass poorly written PHP user-validation code, how (and using what) these attacks work and how to replace the old MySQL functions with a secure prepared statement - and basically, why StackOverflow users (probably with a lot of rep) are barking at new users asking questions to improve their code.

First off, please feel free to create this test mysql database (I have called mine prep):

mysql> create table users(
-> id int(2) primary key auto_increment,
-> userid tinytext,
-> pass tinytext);
Query OK, 0 rows affected (0.05 sec)

mysql> insert into users values(null, 'Fluffeh', 'mypass');
Query OK, 1 row affected (0.04 sec)

mysql> create user 'prepared'@'localhost' identified by 'example';
Query OK, 0 rows affected (0.01 sec)

mysql> grant all privileges on prep.* to 'prepared'@'localhost' with grant option;
Query OK, 0 rows affected (0.00 sec)

With that done, we can move to our PHP code.

Lets assume the following script is the verification process for an admin on a website (simplified but working if you copy and use it for testing):

<?php

if(!empty($_POST['user']))
{
$user=$_POST['user'];
}
else
{
$user='bob';
}
if(!empty($_POST['pass']))
{
$pass=$_POST['pass'];
}
else
{
$pass='bob';
}

$database='prep';
$link=mysql_connect('localhost', 'prepared', 'example');
mysql_select_db($database) or die( "Unable to select database");

$sql="select id, userid, pass from users where userid='$user' and pass='$pass'";
//echo $sql."<br><br>";
$result=mysql_query($sql);
$isAdmin=false;
while ($row = mysql_fetch_assoc($result)) {
echo "My id is ".$row['id']." and my username is ".$row['userid']." and lastly, my password is ".$row['pass']."<br>";
$isAdmin=true;
// We have correctly matched the Username and Password
// Lets give this person full access
}
if($isAdmin)
{
echo "The check passed. We have a verified admin!<br>";
}
else
{
echo "You could not be verified. Please try again...<br>";
}
mysql_close($link);

?>

<form name="exploited" method='post'>
User: <input type='text' name='user'><br>
Pass: <input type='text' name='pass'><br>
<input type='submit'>
</form>

Seems legit enough at first glance.

The user has to enter a login and password, right?

Brilliant, now enter the following:

user: bob
pass: somePass

and submit it.

The output is as follows:

You could not be verified. Please try again...

Super! Working as expected, now lets try the actual username and password:

user: Fluffeh
pass: mypass

Amazing! Hi-fives all round, the code correctly verified an admin. It's perfect!

Well, not really. Lets say the user is a clever little person. Lets say the person is me.

Enter in the following:

user: bob
pass: n' or 1=1 or 'm=m

And the output is:

The check passed. We have a verified admin!

Congrats, you just allowed me to enter your super-protected admins only section with me entering a false username and a false password. Seriously, if you don't believe me, create the database with the code I provided, and run this PHP code - which at glance REALLY does seem to verify the username and password rather nicely.

So, in answer, THAT IS WHY YOU ARE BEING YELLED AT.

So, lets have a look at what went wrong, and why I just got into your super-admin-only-bat-cave. I took a guess and assumed that you weren't being careful with your inputs and simply passed them to the database directly. I constructed the input in a way tht would CHANGE the query that you were actually running. So, what was it supposed to be, and what did it end up being?

select id, userid, pass from users where userid='$user' and pass='$pass'

That's the query, but when we replace the variables with the actual inputs that we used, we get the following:

select id, userid, pass from users where userid='bob' and pass='n' or 1=1 or 'm=m'

See how I constructed my "password" so that it would first close the single quote around the password, then introduce a completely new comparison? Then just for safety, I added another "string" so that the single quote would get closed as expected in the code we originally had.

However, this isn't about folks yelling at you now, this is about showing you how to make your code more secure.

Okay, so what went wrong, and how can we fix it?

This is a classic SQL injection attack. One of the simplest for that matter. On the scale of attack vectors, this is a toddler attacking a tank - and winning.

So, how do we protect your sacred admin section and make it nice and secure? The first thing to do will be to stop using those really old and deprecated `mysql_*` functions. I know, you followed a tutorial you found online and it works, but it's old, it's outdated and in the space of a few minutes, I have just broken past it without so much as breaking a sweat.

Now, you have the better options of using [mysqli_](

[To see links please register here]

) or [PDO](

[To see links please register here]

). I am personally a big fan of PDO, so I will be using PDO in the rest of this answer. There are pro's and con's, but personally I find that the pro's far outweigh the con's. It's portable across multiple database engines - whether you are using MySQL or Oracle or just about bloody anything - just by changing the connection string, it has all the fancy features we want to use and it is nice and clean. I like clean.

Now, lets have a look at that code again, this time written using a PDO object:



<?php

if(!empty($_POST['user']))
{
$user=$_POST['user'];
}
else
{
$user='bob';
}
if(!empty($_POST['pass']))
{
$pass=$_POST['pass'];
}
else
{
$pass='bob';
}
$isAdmin=false;

$database='prep';
$pdo=new PDO ('mysql:host=localhost;dbname=prep', 'prepared', 'example');
$sql="select id, userid, pass from users where userid=:user and pass=:password";
$myPDO = $pdo->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
if($myPDO->execute(array(':user' => $user, ':password' => $pass)))
{
while($row=$myPDO->fetch(PDO::FETCH_ASSOC))
{
echo "My id is ".$row['id']." and my username is ".$row['userid']." and lastly, my password is ".$row['pass']."<br>";
$isAdmin=true;
// We have correctly matched the Username and Password
// Lets give this person full access
}
}

if($isAdmin)
{
echo "The check passed. We have a verified admin!<br>";
}
else
{
echo "You could not be verified. Please try again...<br>";
}

?>

<form name="exploited" method='post'>
User: <input type='text' name='user'><br>
Pass: <input type='text' name='pass'><br>
<input type='submit'>
</form>

The major differences are that there are no more `mysql_*` functions. It's all done via a PDO object, secondly, it is using a prepared statement. Now, what's a prepared statement you ask? It's a way to tell the database ahead of running a query, what the query is that we are going to run. In this case, we tell the database: "Hi, I am going to run a select statement wanting id, userid and pass from the table users where the userid is a variable and the pass is also a variable.".

Then, in the execute statement, we pass the database an array with all the variables that it now expects.

The results are fantastic. Lets try those username and password combinations from before again:

user: bob
pass: somePass

User wasn't verified. Awesome.

How about:

user: Fluffeh
pass: mypass

Oh, I just got a little excited, it worked: The check passed. We have a verified admin!

Now, lets try the data that a clever chap would enter to try to get past our little verification system:

user: bob
pass: n' or 1=1 or 'm=m

This time, we get the following:

You could not be verified. Please try again...

This is why you are being yelled at when posting questions - it's because people can see that your code can be bypassed wihout even trying. Please, do use this question and answer to improve your code, to make it more secure and to use functions that are current.

Lastly, this isn't to say that this is PERFECT code. There are many more things that you could do to improve it, use hashed passwords for example, ensure that when you store sensitive information in the database, you don't store it in plain text, have multiple levels of verification - but really, if you just change your old injection prone code to this, you will be WELL along the way to writing good code - and the fact that you have gotten this far and are still reading gives me a sense of hope that you will not only implement this type of code when writing your websites and applications, but that you might go out and research those other things I just mentioned - and more. Write the best code you can, not the most basic code that barely functions.
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through