How to secure PHP/JQuery/Ajax calls? - php

I'm new to Ajax and PHP in general. So far, I managed to make an Ajax call to my PHP script which fetches data from my database. However, upon testing, I realized that, even if I'm not logged in, I can still access and run the PHP script directly and when that happens, it populates all the data from my table, which I don't want to happen.
Now based on that I see a major security issue where anyone can access and run the script and see user information.
Now I'm not familiar with security and stuff in PHP, kinda new to it. My question is how would I go about to make the script unaccessible directly, or only when the admin is logged in it could be accessible?
I read around that I could check the session, I tried but it didn't work for some reason. So I'll put what I coded below.
Here's the PHP which fetches data, getData.php:
<?php
session_start();
if(isset($_SESSION['id']) && isset($_SESSION['name']) && isset($_SESSION['admin']) && ($_SESSION['admin']==1)){
include_once('config.php');
//Create PDO Object
$con = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
//Set Error Handling for PDO
$con->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
//Query
$sql = "SELECT users.name, users.email, users.admin, stores.admin, stores.name FROM users INNER JOIN stores ON users.id=stores.admin";
//Prepare Statement
$stmt = $con->prepare($sql);
$stmt->execute();
while ($row = $stmt->fetch()){
echo '<tr>';
echo '<td>'.$row[4].'</td>';
echo '<td>'.$row[0].'</td>';
echo '<td>'.$row[1].'</td>';
echo '<td>**********</td>';
if($row[2] == 1){
echo '<td>Yes</td>';
}elseif ($row[2] == 0) {
echo '<td>No</td>';
}
echo '</tr>';
}
$con = null;
}
?>
Here's the ajax that does the call to get the data. It's just a snippet, but it's part of a bigger thing(button on click to be precise), myAjax.js:
$.ajax({ //create an ajax request to getData.php
type: "GET",
url: "includes/getData.php",
dataType: "html", //expect html to be returned
success: function(response){
$("#userInfo > tbody").html("<pre>"+response+"</pre>");
},
error:function (xhr, ajaxOptions, thrownError){
alert(thrownError);
}
});
Finally, this I set the following sessions, when user logs in:
$_SESSION['id']
$_SESSION['name']
$_SESSION['admin']
$_SESSION['admin'] == 1 means the user is an admin. Otherwise it's
not.
Any help is greatly appreciated.
Edit:
Forgot to include what I tried to check the session. I update the PHP.
Thanks

I usually do like this for checking whether the user is loged in or not to display the result or output
use if(!empty($_SESSION['admin'] && $_SESSION['admin']==1 && !empty($_SESSION['name']) && !empty($_SESSION['id']))
using !empty will also check that if the variable is set and has any value or not! using isset shows true even if the value of variable is "null". so It will pass the if conditions argument and show the result.
One More thing:
when you logout you need to unset the session variables using...
<?php
session_destroy();
session_unset();
this technique has worked always with me...thanks

Related

How to fix PHP errors while trying to create a login.php that displays username at a new page on successful login?

I am a business student, inexperienced with php,html etc. and as part of a course we were asked to develop a website using HTML,CSS and PHP that has a registration and login page, connected to an MS Access Database. When I first did the login.php page it was a success, but then we were asked to connect it to our homepage and have a welcome message with the Loggedin username. I tried following online suggestions on how do it but I am getting "undefined index error" and "trying to get property of non-object" errors when running my login.php file.
Here is what I have done:
login.php
<html>
<head>
<title>Login</title>
</head>
<body>
<?php session_start(); ?>
<?php
$email=$_GET['email'];
$password=$_GET['password'];
$odbc = odbc_connect ('group7', 'root', '') or die( "Could Not Connect to ODBC Database!");
$query = odbc_exec($odbc, "SELECT email, username FROM users WHERE email='$email' and password='$password'") or die (odbc_errormsg());
if ($rs->Fields["email"]->value && $rs->Fields["email"]->value == $email)
if ($rs->Fields["password"]->value && $rs->Fields["password"]->value == $password)
{
$_SESSION["email"] = $email;
$_SESSION["loggedin"]= true;
// Relocate to the logged-in page
header("Location: homespace-4 copy/index.php");
}
else
{
$_SESSION["loggedin"] = false;
$_SESSION["message"] = "login Error as $email." ;
}
odbc_close($odbc);
?>
</body>
</html>
Before i put the session_start(); it worked perfectly fine on its own, but was told I needed it for displaying the username on the redirected page. Please help me figure out how to make it work.
These are the things that jump out at me.
You cannot use header("Location: homespace-4 copy/index.php"); unless there has not been any html/header data before it. It just isn't meant to work that way. You have to call it before any html.
Avoid putting PHP inside your HTML. Instead, put HTML inside your PHP. [note: Based on what I see of your code, all of the HTML is unnecessary because you are redirecting your site visitor to your homespace-4 page.]
Avoid using $_GET, it opens you to security risks. Use $_POST. Unless, in this instance, your instructor explicitly told you to do it this way.
session_start(); is essentially called for 3 reasons: to add, read, or delete data
Putting session_start(); near the top of your code is "okay", but it is probably better putting in the area you need it to be in. In this case, right above your "if" statement comparing input values. You want it there because you are adding the data (true or false) at that part. [note: Additional sets of () were added to the "if" statement. Please take the time to study them so you understand why they are there.]
<?php
session_start();
if ( (($rs->Fields["email"]->value) && ($rs->Fields["email"]->value == $email)) && ($rs->Fields["password"]->value) && ($rs->Fields["password"]->value == $password)) ) {
$_SESSION["email"] = $email;
$_SESSION["loggedin"]= true;
// Relocate to the logged-in page
header("Location: homespace-4 copy/index.php");
} else {
$_SESSION["loggedin"] = false;
$_SESSION["message"] = "login Error as $email." ;
}
?>
I'm hoping this will give you enough to work with so that you understand the assignment better. Good luck with your class!

Header won't work with conditions

I have been trying to get a page working for a number of days now, and there doesn't seem to be much help from the "related" questions on this site.
I have made a signup.php page, which has a form for inputting user credentials to signup up for the site I am building, when the form is filled out and the user presses the 'submit' button, the form uses the action "signupsuccess.php" which has all of the php code for inserting the credentials into the database, and then redirects the user to the "Login.php" page.
My problem:
I have written code to say that if the user has not put in any data for one of the fields in the form, then they are brought back to the signup.php page by using this code:
<?php
if(!isset($_POST['fname'])&&($_POST['lname'])&&($_POST['email'])&&($_POST['pass'])){
header('Location:Signup.php');
exit;
}
else{
$host = "localhost";
$user = "******";
$password = "******";
$conn = mysql_connect($host, $user, $password);
$db = mysql_select_db('*****', $conn);
if(! get_magic_quotes_gpc() )
{
$fname = addslashes ($_POST['fname']);
$lname = addslashes ($_POST['lname']);
$email = addslashes($_POST['email']);
$pass = addslashes($_POST['pass']);
}
else
{
$fname = $_POST['fname'];
$lname = $_POST['lname'];
$email = $_POST['email'];
$pass= $_POST['pass'];
}
$query = mysql_query("select * from users where pass='$pass' AND email='$email'", $conn);
$rows = mysql_num_rows($query);
if ($rows == 1) {
$errors[] = 'That user already exists, try another email';
}else
{
$sql = "INSERT INTO users ".
"(fname,lname, pass, email) ".
"VALUES('$fname','$lname','$pass','$email')";
$retval = mysql_query( $sql, $conn );
if(! $retval )
{
die('Could not enter data: ' . mysql_error());
}
}
}
mysql_close($conn);
?>
But the header() just won't bring the user back when they haven't put anything in to the fields. Is there anything I am doing obviously wrong or can anyone help me sort out the redirection of the user if they haven't entered anything.
Your if statement is incorrect. If you're just trying to check to see if those variables are set you need to call isset() on all of them.
You can do this with individual calls to isset() or all in one call.
if(!isset($_POST['fname'],$_POST['lname'],$_POST['email'],$_POST['pass'])){
header('Location:Signup.php');
exit;
}
FYI, you are wide open to SQL injections. addslashes() does not prevent SQL injections. Also, the mysql_* funcstions are obsolete and you should not be writing new code using them. Look into mysqli or PDO instead.
I don't think you really need a redirection, you probably should overcome this issue from the frontend, maybe a js validation could do the trick and is way simpler.
1.- change the action of submit to run the function "validate()"
2.- create the function that will be something like:
$(document).ready(function(){
function validate(){
if ($.trim($("#inputid").val()) == ""){
$(this).css('border', '2px solid red');
} else if ($.trim($("#inputid2").val()) == "") {
$(this).css('border', '2px solid red');
} else if ($.trim($("#inputid3").val()) == "") {
$(this).css('border', '2px solid red');
} else {
submit();
}
}
});
Where '#input?' is the selector for the input you want to validate and null is the value that you want to avoid, in this case, no value, just empty input. Then if all the inputs are filled it will execute submit() function which you should create to do whatever he has to.
Note: This kind of selectors are for jquery so you must include it in your code as well, put this in your header
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
Note 2: This is the frontend approach. I don't know if this is convenient but at least is an option and helps.
Good luck!
Your if statement was the problem. because the isset was only affecting
$_POST['fname'],
the if statment was being skipped so
header('Location:Signup.php')
was not being reached.
I like to put
echo 'test';
in my code while i am testing it and move it around the code. That way, if it is not echoing 'test', i know that the code isn't even being reached. That could have helped you in this case, showing you that the problem wasn't the header, it was the if statement. Also, consider using PDO for mysql connections. It is more secure against mysql injections.
Your condition (if corrected according to the previous answers) would still always result in the else case. Since you are checking for $_POST fields, those will always be present. isset()returns false if the variable is not set (but it is: it comes from your form) or is NULL (which it is not: it contains an empty value). So, isset() will return true fopr every field. What you need is, for each field: if (empty(trim($_POST['fname']))) || ... )empty() returns false when the variable is not set or empty (i.e NULL, an empty string, 0, 0.0, false, etc, see here: http://php.net/manual/en/function.empty.php)Plus, you need to do something about the deprecated mysql_functions and your vulnerability to attacks.

PDO Ajax updating mysql database

I need help in this PHP Ajax updating mysql database using PDO. I wanted to update the database if a user checks the checkbox. Below is my code:
JS:
$('input[name=product_new]').click(function(){
var chkbox_id = $(this).attr('alt');
var chkbox_selected = $(this).is(':checked');
if(chkbox_selected == true)
{
chkbox_selected = "checked";
}
else
{
chkbox_selected = "uncheck";
}
$.post({
url: "../products_listing.php",
type: "POST",
data: {product_id: chkbox_id, product_new: chkbox_selected},
cache: false,
success: function(){}
});
});
PHP page with PDO to update database:
$id = $_POST['product_id'];
$product_new = $_POST['product_new'];
if(isset($_POST['product_new']))
{
try
{
$query = "UPDATE productinfo SET new_arrival=? WHERE id=?";
$stmt_new_chkbox = $conn->prepare($query);
$stmt_new_chkbox->bindParam(1, $product_new, PDO::PARAM_STR);
$stmt_new_chkbox->bindParam(2, $id, PDO::PARAM_INT);
$stmt_new_chkbox->execute();
}
catch(PDOException $e)
{
echo 'ERROR: ' . $e->getMessage();
}
}
It was working when I use mysql but now I've changed it to use PDO, it won't work anymore. I can't find where went wrong. Thanks in advance guys.
Below is the old code from mysql_:
$id = mysql_real_escape_string($_POST['product_id']);
$product_new = mysql_real_escape_string($_POST['product_new']);
if(isset($_POST['product_new']))
{
$upt_new=mysql_query("update products_list set new_arrival='$product_new' where id='$id'");
}
Ok! I know what's wrong already. The damn directory path. I took out ../ and it works! Kinda weird though.
Because my js file is in JS folder and products_listing.php is outside of the js folder. Isn't it supposed to be ../products_listing.php?
Can anyone tell me why it's not working which it is supposed to be?
Thanks in advance guys!
Just split your task into 2 parts: AJAX part and PDO part.
First of all make sure that your PDO part works well. Make a mock $_POST array, and then start playing with PDO calling this script directly, without AJAX. Ask questions here, if something goes wrong. then, as you ret it to work, move to AJAX part, the same way - first, without PDO by just by sending data to server and verifying if it's correct.
Solving 2 problems at once makes things a lot harder. Always split your task into separate parts and solve them one by one.

how to get the current added in the table without getting all the data

guys im trying to make a simple commenting system, that when i click the submit the fields will automatically save in the database then fetch it using ajax. but im getting all the data repeatedly instead of getting the recently added data in the database here is the code:
<div id="wrap-body">
<form action="" method="post">
<input type="text" name="username" id="username">
<input type="text" name="msg" id="msg">
<input type="button" id="submit" value="Send">
</form>
<div id="info">
</div>
</div>
<script>
$(document).ready(function (){
$('#submit').click(function (){
var username = $('#username').val();
var msg = $('#msg').val();
if(username != "" && msg != ""){
$.ajax({
type: 'POST',
url: 'get.php',
dataType: 'json',
data:{ 'username' : username , 'msg' : msg},
success: function (data){
var ilan=data[0].counter;
var i = 0;
for(i=0;i<=ilan;i++){
$('#info').append("<p> you are:"+data[i].username+"</p> <p> your message is:"+data[i].mesg);
}
}
});
}
else{
alert("some fields are required");
}
});
});
</script>
PHP:
<?php
$host='localhost';
$username='root';
$password='12345';
$db = 'feeds';
$connect = mysql_connect($host,$username,$password) or die("cant connect");
mysql_select_db($db) or die("cant select the".$db);
$username = $_POST['username'];
$msg = $_POST['msg'];
$insert = "INSERT INTO info(user_name,message) VALUES('$username','$msg')";
if(#!mysql_query($insert)){
die('error insertion'.mysql_error());
}
$get = "SELECT * FROM info ";
$result=mysql_query($get)or die(mysql_error());
$inside_counter = mysql_num_rows($result);
$data=array();
while ($row = mysql_fetch_array($result))
{
$data[] = array(
'username'=>$row['user_name'],
'mesg'=>$row['message'],
'counter'=>$inside_counter
);
}
echo json_encode($data);
?>
SELECT *
FROM "table_name"
ORDER BY "id" desc
LIMIT 1
This is a SQL query to get last record from table. It return last inserted according to id. id should be a auto increment field. I think this will be helpful for you.
Its because you are returning all the row in the table again to the ajax call via
$get = "SELECT * FROM info ";
if you do return all of them again you will have to test if they are not already there before appending them with the jQuery
Perhaps only return the newly inserted row.
or
The jQuery already knows the data it sent to the server, just return success true or false, and then append it if true with the jQuery, no need to return the data back again to the client side
EDIT
I'm not going to write code for you but perhaps these suggestions may help
mysql_query($insert)
link here for reference - http://php.net/manual/en/function.mysql-query.php
will return true of false depending on if the insert statement was successful
you could potentially also check that it acutally inserted a row by calling
mysql_affected_rows()
link here for reference - http://php.net/manual/en/function.mysql-affected-rows.php
then assuming that the insert was successful (i.e. true from mysql_query($insert) or mysql_affected_rows() > 0) simply return successful (i.e. something like
echo json_encode(true);
then on the client side you could do something like the following:
(jQuery Ajax success function only:)
success: function (data){
if (data) {
$('#info').append("<p> you are:"+username +"</p> <p> your message is:"+msg);
}
else
{
alert('There has been an error saving your message');
}
}
using the variables that you just used to send the request
(Please note code samples provided here are only for example, not intended to be used verbatim)
Couple of points though. Is your intention to post the data via ajax only? (i.e. no page refresh) as if that is the case, you will need to return false from you form submit event handler to stop the page full posting. Also you do not appear to have any logic, or are not worried about complete duplicates being entered (i.e. same username, same message) - not sure if you want to worry about this.
I would also potentially look at tracking all the messages via ids (although I don't know your DB structure), perhaps using
mysql_insert_id()
link here FYI - http://php.net/manual/en/function.mysql-insert-id.php
That way each message can have a unique id, may be easier to establish duplicates, even if the username and message are identical
There are numerous ways to deal with this.
Anyway hope that helps
PS - using the mysql_ - group of commands is generally discouraged these days, use the mysqli_ range of function instead

jQuery AJAX add/edit/delete actions can be hacked?

Just wondering about a security issue. Right now I'm using the following function to delete movies from my database:
function deleteVideo(video_id){
function mycallbackform(v,m,f){
if(v=="yes"){
$.ajax({
type: "POST",
url: "delete.php?action=video",
data: "video_id=" + video_id,
success: function(html){
if(html == "1"){
//$("#result").html(html);
$("#row_"+video_id).fadeOut("slow");
$("#result").show();
$("#result").html("<div class='notification success png_bg'> <div><?php echo $LANG_video_succesfull_delete; ?> </div></div>");
setTimeout(function(){ $('#result').fadeOut('slow'); }, 5000);
}else{
$("#result").show();
$("#result").html(html);
}
}
});
}
}
$.prompt('Are you sure?',{ buttons: { Ok: 'yes', Cancel: 'no'}, callback: mycallbackform});
}
At the back end the following code is executed:
/*** DELETE data ***/
/*** prepare the SQL statement ***/
$stmt = $dbh->prepare("DELETE FROM videos WHERE username=:username AND videos_id=:video_id");
$stmt->bindParam(':username', $currUser);
$stmt->bindParam(':video_id', $video_id);
/*** execute the prepared statement ***/
$stmt->execute();
The username is stored in a session in this case.
Is there any way user A will be able to delete user B data with this code?
I was thinkinig to add a query to check if the current user is the same user who added the video in the database. If not he can't delete the data. But is this necessary or is this code safe enough?
Thanks in advance.
You'd better store a unique user id in the session. What if there are two people with the same username?
Edit: If the username is unique, it is quite safe. It is not possible to change the value of a session variable working the client side, unless you've made a terrible mistake in your PHP code. But if you're sure the session variable is always set correctly, you don't have to worry.

Categories