Security of post submission, picture upload and post fetch

I am a newbie and have been following a tutorial I bought on Udemy. But I was told it is old and teaches bad code practices. I used this in some code from my old projects. Now I'd like to know how secure it is.

<?php

error_reporting(-1);

require 'config/connect.php';

// just define at the top of the script index.php
$username = '';$username = isset($_SESSION['username']) ?$_SESSION['username'] : '';

//Initializing variable
$body = ""; //Initialization value; Examples //"" When you want to append stuff later //0 When you want to add numbers later //isset()$body = isset($_POST['body']) ?$_POST['body'] : '';
//empty()
$body = !empty($_POST['body']) ? $_POST['body'] : ''; if(isset($_POST['bts'])) {

if (empty($_POST["body"])) { echo"You didn't enter anything . <a href= profile.php>Try again</a>"; } else {$body = $_POST["body"];$sql = "INSERT INTO posts (username, body ) VALUES ('" . $username . "', '" .$body . "')";

if(mysqli_query($conn,$sql)){

die();
} else{
echo "<br>error posting . <br> <a href= profile.php>Try again</a> " .
mysqli_error($conn); } } } ?>  Profile pic upload and fetch: <?php$username = trim( isset($_SESSION['username']) ?$_SESSION['username'] : "" );
$userPic = isset($_SESSION['userPic']) ? $_SESSION['userPic'] : "";$info = date('Y-m-d_H-i-s');

if(!empty($username)) { if (isset($_FILES['fileToUpload'])) {
$errors= array();$file_name = $_FILES['fileToUpload']['name'];$file_size = $_FILES['fileToUpload']['size'];$width = 1500;
$height = 1500;$file_tmp = $_FILES['fileToUpload']['tmp_name'];$file_type = $_FILES['fileToUpload']['type'];$tmp = explode('.',$_FILES['fileToUpload']['name']);$file_ext=strtolower (end ($tmp));$extensions= array("jpeg","jpg","png");

if(in_array($file_ext,$extensions)=== false){

$errors[]="extension not allowed, please choose a JPEG or PNG file."; } if ($file_size > 8097152) {

$errors[] = 'File size must be 2 MB'; } if ($width > 1500 || $height > 1500) { echo"File is to large"; } if(empty($errors)==true) {

$userPic = date('Y-m-d_H-i-s').$file_name;
move_uploaded_file($file_tmp,"uploads/".$userPic);

$stmt =$conn->prepare("UPDATE users SET userPic=?, date_time=? WHERE username = ?");
$date_time = date("Y-m-d H:i:s");$stmt->bind_param('sss', $userPic,$date_time, $username); /* execute prepared statement */$stmt->execute();

printf("", $conn->affected_rows); /* close statement and connection */ } } } else { echo "Invalid Username"; } ?> <?php$getimg = mysqli_query($conn,"SELECT userPic, date_time FROM users WHERE username='".mysqli_real_escape_string($conn, $username )."'");$rows=mysqli_fetch_array($getimg);$img = $rows['userPic']; ?>  Posts fetch: <?php$username = isset($_SESSION['username']) ?$_SESSION['username'] : '';
$username = trim(isset($_GET['username']) ? $_GET['username'] :$username);

//Write the query
$sql = "SELECT * FROM posts WHERE username = '" .$username. "'  ORDER BY post_id DESC ";
$result =$conn->query($sql); if ($result->num_rows > 0) {
// output data of each row
while($row =$result->fetch_assoc()) {

echo '<div id="rcorners2">';

echo '<p id="p2">' .$row['username']. '</p>'; echo '<p id="p4">' .$row['date_time']. '</p>';

echo '<hr id="hr2">';

echo '<p id="p3">' .$row['body']. '</p>'; echo '<div class="test"> <a href="#" class="fill-div"></a></div>'; echo'</div>'; echo'</br>'; } } else { echo '<center><b><p style="font-size: 30px; color: #262626;"> Write your first post</p></b></center>'; } ?>  • Why are you developing a php5 application?!? There is no excuse for developing on deprecated versions of php. Do you actually want to allow anonymous posting? Honestly, your queries are VERY susceptible to breakage and malicious injection. – mickmackusa Jun 6 '20 at 3:25 • Yeah this project is about 3 or 4 years old. I just picked it up again to gain some understanding. – user13477176 Jun 6 '20 at 13:47 • Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers. – Mast Jun 6 '20 at 15:33 2 Answers Please read about sql injection. Basically you should be using prepared statements with parameters for executing SQL queries - either PDO::prepare() or mysqli_prepare(). If that isn't enough of a clue, consider the case where $_POST['body'] contains something like body');DROP TABLE users; or some variant that leads to successful WHERE conditions that end up dropping one or more tables. This Stack Overflow post also has more information.

As a comment alludes to, the code appears to be using PHP 5 or earlier features. As of the time of writing, PHP 7 has LTS for version 7.4, and 5.6 or anything earlier is in End of Life support, meaning "A release that is no longer supported. Users of this release should upgrade as soon as possible, as they may be exposed to unpatched security vulnerabilities."1.

There are many newer features added in PHP 7.0, 7.1, 7.2, 7.3 and 7.4 with things that can simplify your code like:

The nesting levels of this code isn't totally bad, but it does seem slightly off - e.g.

$body = !empty($_POST['body']) ? $_POST['body'] : ''; if(isset($_POST['bts'])) {

if (empty($_POST["body"])) { echo"You didn't enter anything . <a href= profile.php>Try again</a>"; } else {$body = $_POST["body"];$sql = "INSERT INTO posts (username, body ) VALUES ('" . $username . "', '" .$body . "')";

if(mysqli_query($conn,$sql)){


Why does it keep incrementing spaces by two characters, even if a new block level is not introduced?

Then the closing braces are all on the same level??

}
}
}
?>


There are some excess assignment statements:

// just define at the top of the script index.php
$username = '';$username = isset($_SESSION['username']) ?$_SESSION['username'] : '';


The second assignment to $username makes the first assignment useless. //Initializing variable$body = ""; //Initialization value; Examples
//"" When you want to append stuff later
//0  When you want to add numbers later
//isset()
$body = isset($_POST['body']) ? $_POST['body'] : ''; //empty()$body = !empty($_POST['body']) ?$_POST['body'] : '';


Here the second assignment of $body also makes the first assignment of it superfluous. It appears $width and $height are set initially: $width = 1500;
$height = 1500;  And then they don’t appear to be updated. Then the following conditions never appear to have a chance at evaluating to true: if ($width > 1500 || $height > 1500) { echo"File is to large"; }  Alas, an online search for 'php tutorial' returns plenty of outdated tutorials, some of which are downright dangerous (SQL injections). It's no wonder newcomers to PHP perpetuate bad code and bad practices. This kind of code does not belong in 2020, nowadays developers are expected to use development frameworks and not Notepad or some variant - Example I think there are logical flaws in your code, for example: $username = isset($_SESSION['username']) ?$_SESSION['username'] : '';


That means: if $_SESSION['username'] is not set then $username = ''; but you proceed with the rest of the code anyway, and therefore insert a blank username in your table ?

If you use session variables then you have to make sure that the session is still active and in a valid state.

This code does not look like a finished product. Yes, it is vulnerable (SQL injections). Try to hack your site using SQLmap, even with default options it might very well be able to dump your database. Maybe upload a shell too, leading to total compromise of your server (in addition to the data leak).

AFAIk PHP does not allow stacked queries in order to mitigate possible injections but there are still plenty of ways the code can be abused. Note that a SQL injection is not always exploitable but it is nonetheless pretty serious.

You must stop these coding practices immediately or you will get into trouble. If you have code like this in production you need to patch it. At a minimum, use prepared queries whenever user-supplied input is involved.

If you deliver defective code to clients you should consider your legal liability. If your code results in a data breach you might be prosecuted for failure to observe minimum security standards (in America perhaps, you can be sued for anything by anybody). Otherwise your reputation could take a hit. There is no excuse for code like that in 2020.

File uploads are also dangerous and there are quite a few ways they can be abused. See for example:

In your code you make no effort to sanitize the file name, that may contain stuff like: ../../ or characters that are invalid on the local (server) file system.

There are very few checks, the most important being the check on the extension.

The relevant lines are:

$file_name =$_FILES['fileToUpload']['name'];
$userPic = date('Y-m-d_H-i-s').$file_name;
move_uploaded_file($file_tmp,"uploads/".$userPic);


I have made some tests on a Linux machine in an attempt to defeat your code and upload a PHP shell. I can for example upload names that contain a carriage return. I have tried null byte injections too but I think PHP now has built-in protection.

An old version of PHP could be vulnerable. In particular check out this bug report: Sec Bug #69207 move_uploaded_file allows nulls in path. This is the situation you want to avoid.

The point is that you rely on a file name that is supplied by the user (browser) and can be manipulated using a proxy or some tool like Burp. I have not tried Unicode tricks like RTL (right to left) makers or whatever, I will leave the exercise to interested readers.