PREVENT DUPLICATION for INSERTING DATA in PHP MySQL - php

Good Days I am new at programming and I have a problem I want to prevent duplication. What do I need to Add in my code just to prevent duplication when inserting a data ( just only in the "NAME" on my table).
if(isset($_POST['text'])){
$text =$_POST['text'];
$sql = "INSERT INTO table_attendance(NAME,TIMEIN) VALUES('$text',NOW())";
if ($conn->query($sql) ===TRUE) {
$_SESSION['success'] = 'Action Done';
}else{
$_SESSION['error'] = $conn->error;
}
header("Location: index.php");
}
$conn->close();
What do I need to add in my code so it wont accept same NAME and prevent duplication

Add a UNIQUE KEY in MySQL on the name column.
Change your INSERT INTO table_attendance... to INSERT IGNORE INTO table_attendance....
Please note that your code is currently susceptible to SQL injections.
This is very dangerous. Be sure to not deploy such code when launching an actual product.
See more info here: How does the SQL injection from the "Bobby Tables" XKCD comic work? .

Related

Is my site vulnerable to SQL injections if I get error 403?

I have a login form and just to test I tried to fill in "select * from accounts where username = test" and then I pressed enter to see what happens. I got redirected to this page:
Should I be concerned about SQL injections? Or is this a normal response?
Edit: the PHP code for this particular case.
$sql = "SELECT * FROM accounts WHERE Useremail=?";
$stmt = mysqli_stmt_init($conn);
if(!mysqli_stmt_prepare($stmt, $sql))
{
echo "There was an error whilst trying to connect to the database. Please re-submit your password reset request.";
exit();
}
else
{
mysqli_stmt_bind_param($stmt, "s", $userEmail);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
if (!$row = mysqli_fetch_assoc($result))
{
header("Location: /reset-password.php?reset=fail");
exit();
}
}
403 is the standard http status code for an unauthorized request. It seems that at least in this one test, the site did the correct thing.
That doesn't guarantee it's free of SQL injection vulnerabilities. There's an old saying:
"Testing shows the presence of bugs, not their absence."
In other words, there might be another way to use SQL injection to exploit this site, just not the one you tested.
You should always be concerned about SQL injection vulnerabilities and seek to use safe programming techniques to prevent them.
P.S.: I hope you have permission to do penetration-testing on this site. Doing it without permission is a crime in some countries, for which people have been prosecuted. I recommend you avoid doing that kind of testing for vulnerabilities, unless it's your own site, or you have been specifically hired to do that kind of testing by its owner.

SQL Injection parameters aren't working on my page

I have a login form and I'm confused why my SQL Injection parameters doesn't work in here. I don't have any function or method for preventing the SQL Injection.
I made this login form for the testing of SQL injection and it's written in PHP.
Here is my code.
<?php
include("myconnection.php");
$error="";
if(isset($_POST["submit"]))
{
if($_POST["username"] == '' || $_POST["password"]== '')
{
$error='Please fill the blanks!';
}else
{
$username=$_POST['username'];
$password=$_POST['password'];
$sql="SELECT * FROM users WHERE username='$username' AND password='$password'";
$result=mysqli_query($db,$sql);
$row=mysqli_fetch_array($result,MYSQLI_ASSOC);
if(mysqli_num_rows($result)==1)
{
$login_user=$_POST["$username"];
header("location: myhome.php");
$error="Connected";
}
else
{
//$error="Incorrect Username/Password";
$message="Incorrect Credentials";
echo "<script='text/javascript'>$message</script>";
}
}
}
else
{
}
?>
I tried admin'OR'1'='1 in both username and password fields and any other possible basic injections but it doesn't work. I tried using the basic sql injection in most of working sites and it works, I'm just confused my my code doesnt accept sql injections.
And it gives me the same echo when you have an incorrect credentials.
I hope this is done for academic purposes as I have no idea why you would ever want to have this in any production websites. That being said it is probably because of the AND needing to also be true for the query to return any results. Where as if you had submitted admin'OR'1'='1 in the username field your query would look like
SELECT * FROM users WHERE username='admin'OR'1'='1' AND password='123'
That reads to me as WHERE username equals admin OR 1 equals 1 AND password equals 123. You would probably need to figure out how to also bypass that check as it will try to match password field still and vice versa the username field.
Seems odd to say but if you wanted to inject something maybe this would work in the username field injection' OR 1 LIMII 1# Which would make something like this
SELECT * FROM users WHERE username = 'injection' OR 1 LIMIT 1#' AND password = 'pass'
Essentially you are already injecting SQL, you are just not doing it in such a way that is yielding the results you want. Try echoing the query and running it directly in the mySQL CLI to see what the result set is and if it is a valid query. Maybe play around with the query there to try and obtain your intended injection.

How to use same query to insert data

I am new at programming.
I am trying to create a simple guestbok.
i have one index page where you can register a firstname, lastname and email.
And if you click on one name you redirect to a new page with id.
How can i now insert text to this ID with the same codeblock using the ID.
My code looks like this.
<?php
require('dbconfig.php');
try {
$conn = new PDO("mysql:host=$servername;dbname=projektone", $username, $password);
//Set PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Insert to database
$sql = "INSERT INTO user (firstname, lastname, email)
VALUE ('".$_POST["first_name"]."','".$_POST["last_name"]."','".$_POST["email"]."')";
$sql = "INSERT INTO user (guestbok)
VALUE ('".$_POST["guestbok"]."')";
$conn->query($sql);
}
catch(PDOException $e)
{
echo $e->getMessage();
}
header('Location: /');
?>
Thanks in advance
/Daniel
Joining up raw bits of text and passing them on to your database to process is not a good idea. It opens up your system to SQL injection. While it's unlikely that someone could compromise your site when only INSERT statements are exposed in this way, it does mean that:
anyone with an apostrophe in their name will break the logic of the request
you are exposing a method by which someone can carry out a stored XSS attack by submitting javascript to your guestbook
Regarding the SQL Injection problem, there are 2 methods to protect your system - one is to transform the data in which a way that it cannot break the SQL string it is added to (e.g. using mysqli_real_escape_string()) but the recommended approach when using PDO to mediate your code's interaction with the DBMS is to use variable binding. Here you compose your SQL command with placeholders for the data and substitute them at run time.
If your ID is generated from a mysql auto insert id, then you can read the value from $conn->lastinsertid
$stmt=$conn->prepare("INSERT INTO user (firstname, lastname, email)
VALUES (:fnm,:lnm,:eml)");
$stmt->execute(array(
':fnm' => $_POST["first_name"],
':lnm' => $_POST["last_name"],
':eml' => $_POST["email"]));
$id=$conn->lastinsertid();
Your next problem is how to communicate this securely to the page where the user submits their guestbook comment (in your example code you try to do both operations in the same page).
Sending it in a round trip to the browser, as a cookie or as form variable means that it could be tampered with. There are esoteric stateless solutions where you can do this but with the data encrypted or cryptographically signed, however the simplest solution is to use sessions - add session_start() at the top of all your pages and any data you want available across requests can be stored in the $_SESSION superglobal.
(there are security issues relating to sessions as well)
When you receive the POST containing the guestbook data, then you should use an UPDATE user SET guestbook=:gstbk WHERE id=:id_from_session (or you could INSERT it into a seperate table with id as a foreign key)
Lastly, when you output the message the person left in your guestbook, make sure you protect the browser from any nasties in there:
print htmlentities($guestbook);
Ok, probably I managed to get what you need. Put the following two lines in your dbconfig.php:
$conn = new PDO("mysql:host=$servername;dbname=projektone", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
and then require it wherever you need a database connection:
file one:
require('dbconfig.php');
$sql = "sql 1";
$conn->query($sql);
then in another file
require('dbconfig.php');
$sql = "sql 2";
$conn->query($sql);

What is the best way to protect Mysql Delete statements?

I thought you guys would know the best way to do this:
When I delete an order ($prodId) from the ORDERS table, this script then goes and deletes all the items-ordered lines from the ORDERED_ITEMS table, which houses all the items ordered from every order in the system.
Is there a best practice to ensure that what I want deleted is deleted and only that? I'm worried about something going wrong/injected/mistyped with/into the script and accidentally deleting all the ordered item lines for all orders by mistake.
This is how far I got.
$delete_prod_items = mysqli_real_escape_string($con,$_REQUEST['prodId']);
if (is_numeric($delete_prod_items)){
$sql3 = "DELETE from proteus.ordered_items where order_id = $orderId";
mysqli_query($con,$sql3) or die('DELETE Order $orderId from the Ordered Items table failed: ' . mysqli_error($con).'<br>');
}
This script is POSTed into by my form.
$orderID is the order number that the script uses to identify which ITEM rows should be deleted
$delete_prod_item is the escaped $prodID value. I was trying to be super cautious. perhaps I don't need this.
Am I missing anything?
Don't know why anyone is mentioning it, but the best way to really protect any statement is using PreparedStatements:
$delete_prod_items = mysqli_real_escape_string($con,$_REQUEST['prodId']);
$mysqli = new mysqli("localhost", "localuser", "password", "database");
if ($mysqli->connect_errno) {
echo "Failed to connect to MySQL: " . $mysqli->connect_error;
}
if (!($stmt = $mysqli->prepare("DELETE FROM `proteus`.`ordered_items` WHERE `order_id` = ?"))) { //whatever query you want
echo "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->error;
}
$stmt->bind_param("s", $delete_prod_items);
$stmt->execute();
$stmt->close();
Also take after what #zerkms mentioned and use POST requests for your information.
First things first you need to take care of the sql injections. The link will give you an idea.
Secondly you could use javascript to get a pop-up which asks the user a confirmation before deletion.
Next, to avoid the unintentional deletion of more than one row is to include LIMIT 1 to your query.
N.B. You could also limit priveleges by creating a different user (username) to access the mysql database use it in your mysql_connect('host', 'username', 'password', 'database') function . If you are displaying something really important you may consider not giving deletion rights.
Escaping data is good for preventing SQL Injection
It's better to limit the request with $_POST instead of $_REQUEST
If this page is for admin only, then it's fine since only you have access, however, if users have access to it, therefore it's better to apply some condition to the request before proceeding to the deletion (example, verify that they are deleting something related to their accounts only)
As a first order of business, do the following...
Limit the request method to POST or even better, DELETE if you can get PHP to handle it.
Use prepared statements with bound parameters to avoid SQL injection vulnerabilities.
The main issue you will face is unauthorised requests. The best solution to this is to use a CSRF token.

Using a variable (not user inputted) in an SQL query

I am trying to encode json for several fields of different tables in my database. Below is my code. I am currently using an array to represent the names of my tables ($tablename). I've read about SQL injections but they seem to focus specifically on user input. However, in this case there is no user interaction with my database. It's a backend for my app. Any thoughts on using variable names like this? Thanks
I also looked into prepare statements but it was quite difficult to fetch the data in the form i wanted.
<?php
include $_SERVER['DOCUMENT_ROOT'] . '/mmcv/buildchartInfo.php';
$position = 0;
$results = array();
foreach($chartnames as $tablename) {
print $tablename."<br />";
encodejson($tablename);
}
function encodejson($tablename){
include $_SERVER['DOCUMENT_ROOT'] . '/mmcv/includes/connect.inc.php';
$sql="SELECT rank, name FROM $tablename";
$result = mysqli_query($connection,$sql);
//Error when data isn't returned
if(!$result)
{
$output = "error getting data";
echo $output;
//$GLOBALS['loginError'] = "error getting log in data";
exit();
}
while($row=mysqli_fetch_assoc($result)) $output[]=$row;
print(json_encode($output));
}
mysqli_close($connection);
?>
As long as the user can't change the value of $tablename, then you have nothing to be scared about.
As a general rule I'd suggest you to always use prepared statements even without user input. But technically speaking if you are absolutely sure the variable $tablename cannot be modified directly or indirectly (doesn't depends from other user inputted variables) then I guess it's fine to go with that.
Notice: table names cannot be prepared (SELECT ... FROM :table WHERE ... will not work), therefore sometimes you can't choose.
But sometimes its hard to track the real dependencies of a variable, therefore I still highly suggest you to with prepared statements.

Categories