Are these steps enough to secure a site? - php

I am about to launch my website and security is important so i wanted to outline what I have done to secure the site. Please correct me if I am wrong and if I need something else:
To connect to our server, I have a two-factor authenitcation enabled via VPN.
The site uses SSL
Data is encrypted at rest.
I have a log monitoring tool
WHen users enter data into the database i use mysql_real_escape_string(); and when i display user data i use htmlspecialchars();
Passwords are stored using md5 encryption.
Sample insert query:
// I use these on every page
$username = removeBadChars($_SESSION["username"]);
$password = removeBadChars($_SESSION["password"]);
//Sanitized data
$_SESSION["username"] = $username;
$_SESSION["password"] = $password;
//Query to display
$sql = "select `User_name`, `User_id`, `User_kind` from `clientele`
where `username` = '$username' AND `password`='$password'";
$query = mysql_query($sql) or die ("Error: ".mysql_error());
while ($row = mysql_fetch_array($query)){
$name = htmlspecialchars($row['User_name']);
$uid = htmlspecialchars($row['User_id']);
$uis = htmlspecialchars($row['User_kind']);
}
mysql_free_result($query);
//Insert Query
$title = mysql_real_escape_string($_POST['title']);
$comment = mysql_real_escape_string($_POST['comment']);
$insert = "INSERT INTO table (Title, Comment)
VALUES ('".$title."', '".$comment."')";
$query = mysql_query($insert) or die ("Error: ".mysql_error());

Use a stronger hash function (e.g. sha256)
Append a salt (random value for every user) to the password before hashing it
Use prepared statements (MySQLi) instead, to avoid the possibility of forgetting to escape data before entering it into the database
Do not store user information in $_SESSION. Instead, store a session variable that means nothing to the outside world, changes every time someone logs in, and links to the user account. - This only applies to cookies. drinks some caffeine
Be careful putting data from user in attribute values (e.g. <span title="FULLNAME">), as additional escaping is needed (quotes, spaces if not using quotes, etc)
Note: This list is not exhaustive. It only lists things I noticed that were wrong with the short snippets you provided.

For safety you should probably use a PDO or mysqli_ functions and skip that old-school mysql_ junk, it's no longer being developed. Here's how to use the PDO:
$pdo = new PDO('mysql:host=localhost;dbname=whatever', $username, $password);
$statement = $pdo->prepare('select `User_name`, `User_id`, `User_kind` from `users`
where `username` = :user AND `password`= AES_ENCRYPT(:pass,:user)');
$statement->bindParam(':user', $_GET['user']);
$statement->bindParam(':pass', $_GET['pass']);
$results = $statement->execute();
var_dump($results->fetchAll());
the parameters are much safer because when you bindParam it automagically validates. Others have mentioned using md5 hashing, but there are plenty of databases for "decoding" them and also rainbow table attacks, so they're not very secure. Here I'm using mysql's AES_ENCRYPT for the password, and using the username as the key for demonstration purposes, you'd probably want to generate your own key and store it somewhere, because you can AES_DECRYPT with that... There are libraries for better encryption you should check out, like scrypt.
Whatever you do, do not use addslashes() it's insecure
On top of that you should look into securing your server's OS and Apache in other ways, like making not advertise version numbers and running apache as it's own users etc. Check out the Open Web Security Project website for tons of security info.

Related

Struggling to get PHP variable to work in MySQL Select request

I'm attempting to get my code to pull up a username based on the password a user inputs. It works successfully when I bake the actual password into the code, but I haven't found any way to get the variable in successfully.
The troublesome line is:
$result=$dbh->prepare('SELECT * from account WHERE password = (' & $formpassword & ')');
The variable is $formpassword.
I have variables successfully working on an INSERT statement elsewhere in my code, using this system:
$_query = "INSERT INTO account (username, password) ";
$_query = $_query."VALUES ('".$formusername."', '".$formpassword."')";
^^^ I have tried using the above system for my SELECT statement, but it doesn't appear to work either.
Sorry if my post is unclear or anything, I'm not remotely experienced with programming...
Thanks for the help!
Never store plain text passwords! Please use PHP's built-in functions to handle password security. If you're using a PHP version less than 5.5 you can use the password_hash() compatibility pack. It is not necessary to escape passwords or use any other cleansing mechanism on them before hashing. Doing so changes the password and causes unnecessary additional coding.
When using prepared statements you put placeholders in the sql.
$stmt=$dbh->prepare('SELECT * from account WHERE password = :formPassword');
$stmt->execute([':formPassword'=>$formpassword]);
$row = $stmt->fetch();
$stmt = $pdo->prepare('INSERT INTO account (username, password) VALUES (:username, :formPassword)');
$stmt->execute([':username'=>$formusername,':formPassword'=>$formpassword]);
You should be able to use " (Double quotes) instead of ' (Single quotes). Then you can just use the variable without concatenation.
$result=$dbh->prepare("SELECT * from account WHERE( password = $formpassword )");

How to print ONLY the data, as a string, from a mysql row

I have tried to simply print/echo the data from this row in my table:
I then use the following code (without all the connect stuff):
//please just ignore the query part
$sql2 = "SELECT Password FROM bruger WHERE Brugernavn='$Login_Navn'";
$result2 = mysqli_query($con, $sql2);
$row_result2 = mysqli_fetch_assoc($result2);
print_r($row_result2);
And the output of this ends out being:
I would like to know what i have to do to make it appear without all the "Array ([Password]....." stuff, so it just ends out being plain "TestPassword".
-Do i have to use another function?
Thanks in advance!
Sidenote: Im creating a login system for a school project. It ain´t advanced in any way, and the security/encryption etc. is as low as it gets. But that´s not really what im interested in with the project.
If you have some reading material on how to create a login system properly tho´ it would be appreciated.
That would be echo $row_result2['Password'];
You need to specify the corresponding index of the array to get the respective element to be printed.
You would echo the place in the array
echo($row_result2['Password']);
If your query brings back multipule fields you could loop over them:
foreach($row_result2 as $key => $val)
{
echo($key . ':' . $value);
}
Lastly, instead of storing into a associated array, you could use mysqli's bind to bind the results to single varibles:
$sql2 = 'SELECT Password FROM bruger WHERE Brugernavn=?';
$stmnt = mysqli_prepare($con, $sql2);
mysqli_stmnt_bind_param($stmnt,'s',$Lpgin_Navn);
mysqli_stmnt_bind_result($stmnt,$result2);
mysqli_stmnt_execute($stmnt);
mysqli_stmnt_fetch($stmnt);
echo($result2);
Or object oriented:
$sql2 = 'SELECT Password FROM bruger WHERE Brugernavn=?';
$stmnt = $con->prepare($sql2);
$stmnt->bind_param('s',$Lpgin_Navn);
$stmnt->bind_result($result2);
$stmnt->execute();
$stmnt->fetch();
echo($result2);
The use of mysqli_prepare protects your database from SQL injection attacks (consier if $Login_Navn = "'; drop table burger; --"). Binding the parameter tells it which string to sanitize when running the query. It also will speed up the time it takes to run the same query multiple times on different passed strings.
Lastly, never store passwords if you can help it. If you must, you should read the best practices for storing passwords. This, currently, includes salting (with random salt) and hashing (using a hash algo that is not currently known to be broken) the password before storing it in the database.

php crypt password and postgresql database

I'm new in PHP. I'm doing authentication, where I'm checking password with password stored in database PostgreSQL. On db site i used this function to crypt my password:
update ucty set psswd = crypt('some_pswd',gen_salt('md5')) where uid='1';
In my PHP srcipt I'm using this code:
$query = "SELECT meno, priezvisko, nickname, psswd, uid
FROM ucty
where nickname='$nickname' and psswd=crypt('$password', psswd)";
Everything works fine, but I'm not sure , that this is correct way to secure my password.
Any advice?
You're correct; this isn't the correct way to secure your password.
You're encrypting the password as part of the query. This can be logged (in plaintext), so it's very possible for intruders (or anyone listening to your traffic) to see users' passwords in plaintext.
"How can I prevent this?" Do your hashing on the server-side, within your PHP code. You can read up on this in the PHP manual.
Essentially, you want to have your query to set a password be something like this:
UPDATE ucty SET psswd=$hashed WHERE uid=1;
You're putting variables directly into the SQL statement. You didn't mention what method you're using to query the database, but you'll want to use prepared statements. This is a safe way to slide in user-supplied data (which $nickname and $password are).
This would be an example of a good way to use prepared statements:
$query = "SELECT meno, priezvisko, nickname, psswd, uid"
. " FROM ucty"
. " WHERE nickname=? and psswd=?";
$stmt = $dbh->prepare($query);
$stmt->execute(array($nickname, $hashedPassword));

unsecure login script - how to protect

I am investigating a project that could be sql injected (one user reported it).
Here is part of login script:
$loginemail = $_POST['loginemail'];
$loginemail_sql = mysql_real_escape_string($loginemail);
$password = $_POST['loginpass'];
$password_sql = mysql_real_escape_string($password);
//get user data
$q = 'SELECT uid, full_name, score, status FROM users WHERE email="'.$loginemail.'" AND password="'.$password_sql.'" LIMIT 1';
I would like to now if this is part of code that could be injected?
Is there a problem that $loginemail and $password are treated incorrectly and could contain some dangerouse "SQL parts"?
Let's see:
Please, don't use mysql_* functions in new code. They are no longer maintained and are officially deprecated. See the red box? Learn about prepared statements instead, and use PDO or MySQLi - this article will help you decide which. If you choose PDO, here is a good tutorial.
For starters.
Second, you're escaping $loginemail, but using the unescaped version (instead of $loginmail_sql).
Third, it's implied by your code that you store your passwords in the database as-is. You shouldn't. If an attacker gets his hands on the database, your passwords would be compromised. You should hash the password and store the hash there.
Yes, you are using $loginemail in your query that is unchanged. Use $loginemail_sql instead.
For further reading, have a look at How to prevent SQL injection in PHP?
Well as #Madara Uchiha said it's good to stop using mysql_* functions. But he gave no example. So i'll. Sorry for my english, i'm brazilian :)
PDO:
<?php
$loginemail = $_POST['loginemail'];
$password = $_POST['loginpass'];
// open a PDO connection within mysql driver
// PDO uses DSN string for connections they look like: "driver:options"
$dsn = 'mysql:dbname=testdb;host=127.0.0.1';
// DB username
$dbUser = 'dbuser';
// DB password
$dbPassword = 'dbpass';
// PDO is instantiable, so you need to create an object for each connection
$dbh = new PDO($dsn, $dbUser, $dbPassword);
// You must prepare your query, PDO uses a placeholder system for sanitize data and avoid injection, params can be passed using "?" or ":varname"
$stmt = $dbh->prepare('SELECT uid, full_name, score, status FROM users WHERE email= :email AND password= :password LIMIT 1');
// Binding a param called :email
$stmt->bindValue(':email', $loginemail);
// Binding a param called :password
$stmt->bindValue(':password', $password);
// Execute the PDOStatement
$stmt->execute();
// Then fetch result
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
// ALSO, you can fetch only one row using
$firstRow = $stmt->fetch(PDO::FETCH_ASSOC);
For one thing, you're escaping $loginemail, but then using the unescaped version in the query.
One thing you might want to consider, if possible, is using PDO and prepared statements to simplify escaping and parameter substitution.
You use mysql_real_escape_string on $loginemail to arrive at $loginemail_sql, but you then stop short of using it in your query:
$q = 'SELECT uid, full_name, score, status FROM users WHERE email="'.$loginemail.'" AND password="'.$password_sql.'" LIMIT 1';
I'm no expert on sql injection but escaping the strings is a great first step which should be enough although there is probably more that can be done.
My biggest issue with your code is that you seem to store the passwords in plan text in the database. You should use a salted hash to store them. Check this out for more information:
Secure hash and salt for PHP passwords
Also you made a mistake in this code:
$q = 'SELECT uid, full_name, score, status FROM users WHERE email="'.$loginemail.'" AND password="'.$password_sql.'" LIMIT 1';
Should be:
$q = 'SELECT uid, full_name, score, status FROM users WHERE email="'.$loginemail_sql.'" AND password="'.$password_sql.'" LIMIT 1';

sha('$password') return with empty set

I have two problems.
problem one:
I am trying to create a registeration form where users can register with my website.
when I run this mysql statement a get dublicate entry found error:
$sql "insert into users(username, password) values('$username, sha('$password'))";
Duplicate entry 'da39a3ee5e6b4b0d3255bfef95601890afd80709' for key 'password'
despite the fact that I changed the the string sha('$password') several times.
please help.
else{
include("databaseconnection.php");
$databaseconnect = connect($host,$user,$password,$database)
or die("couldnot connect to database serever.\n");
$database_select = mysql_select_db($database,$databaseconnect)
or die("could not select dabases.\n " .mysql_error());
$query2 = "insert into company(username,password)
values('$username',sha1('$password'))";
$result2 = mysql_query($query2,$databaseconnect);
echo "you have been registered as '$companyloginName' <br/>";
header("Location:/index.php");
my login php script is as follow:
$result ="select username, password form users where username ='$username' and password = sha('$password');
if(mysql_num_rows($reuslt)==1){
echo"welcome '$username";
}
First, I would STRONGLY advice against using MySQL's sha() or PHP's sha1() alone for password hashing purposes. This is a huge security risk for your users if your database gets compromised.
Please take the time to read my previous answer on the subject of password hashing to properly secure your data.
Second, your code is vulnerable to an SQL Injection attack. Use mysql_real_escape_string() to escape the variables you are going to put in your query before-hand.
$query2 = "insert into company(username,password)
values('" . mysql_real_escape_string($username) .
"', sha1('" . mysql_real_escape_string($password) . "'))";
Third, your $password variable is being overwritten by your databaseconnection.php file.
include("databaseconnection.php");
$databaseconnect = connect($host,$user, $password ,$database);
To put emphasis...
$databaseconnect = connect($host,$user,$password,$database);
Therefore, the $password used later on in your query still contains the password for the database connection, not your user's password.
Change the name of your variable in databaseconnection.php or even better still, use an array to hold all the configuration.
$dbConnectParams = array('host' => 'localhost'
'user' => 'myUser',
'pass' => 'myPassword',
'db' => 'myDB');
Then, change your code as follows:
include("databaseconnection.php");
$databaseconnect = mysql_connect($dbConnectParams['host'],
$dbConnectParams['user'],
$dbConnectParams['pass'],
$dbConnectParams['db']);
Since you are already passing the database when calling mysql_connect(), you do no need to call mysql_select_db().
da39a3ee5e6b4b0d3255bfef95601890afd80709 is the sha1 hash of the empty string. Make sure that you actually insert the password into your SQL query, for example by echoing the query instead of sending it to the SQL server.
Edit With the new information added to your question, check out these two lines:
include("databaseconnection.php");
$databaseconnect = connect($host,$user,$password,$database)
Here, $password is the password used to connect to the database. The inclusion of databaseconnection.php probably overwrites what was previously in the $password variable.
Try to echo $query2 and you'll probably see it for yourself, that the SQL query doesn't include any password at all or that the password therein is not the same as the one entered by the user.
Guessing from the commented line, it may be possible you accidentally use the connection password that is set in 'databaseconnection.php' rather than the user password - you don't show how you initialize the $password string.
Also note the comma in your sql that shouldn't be there:
insert into company(username,password,)
^
I have not tested if that is the cause, but you should probably get rid of it and test it again.
Also, seriously consider pdo / prepared statements to prevent sql-injections, even more so if you want to insert the password from user input.

Categories