i'm a newbie and I just built a CRUD system but its not secure at all. The edit page has the ID number in the URL and users can simple just randomly type ID's to access other records in the database.
http://example.com/example_edit.php?id=2
<?php
include_once("connection.php");
$result = mysqli_query($mysqli, "SELECT * FROM mkregistrationchecklists WHERE login_id=".$_SESSION['id']." ORDER BY id DESC");
?>
<tbody>
<?php
while($res = mysqli_fetch_array($result)) {
echo "<tr>";
echo "<td>".$res['id']."</td>";
echo "<td><span class='label ".$res['labelwarning']."'>".$res['status']."</span></td>";
echo "<td>".$res['todaysdatetime']."</td>";
echo "<td>".$res['tag']."</td>";
echo "<td>".$res['serialnumber']."</td>";
echo "<td>".$res['currentequipment']."</td>";
echo "<td>".$res['company']."</td>";
if ($res['status'] == "Submitted") {
echo "<td><a href='page_read.php?id=$res[id]' class='btn btn-default glyphicon glyphicon-eye-open'></a></td>";
} else{
echo "<td></td>";
}
echo "</tr>";
}
?>
</tbody>
What is the best approach in securing this?
Should i encrypt like this?
$secure_id = $_GET['id'];
$decryped_id = base64_decode($secure_id);
I updated my code, im saving the records according to the login_id but it still looks unprofessional with the id tag in the urls.
You have to add user / record owner unique identification into all SQL queries, typically :
$query = "SELECT * FROM table WHERE id = 1 AND user_id = 2";
with this approach you can be sure that user access only his records. Id of logged in user can be placed somewhere in SESSION.
Hiding or hashing ids is not recommended, it's a anti-pattern and security through obscurity.
Related
I'm creating a website where users will need to be able to upload images, and I'd like them to be able to delete those images. Right now, I have a page that will display all of the images that that user has uploaded, and I have a php set up to delete an image from the database. It just needs to be given the id of the image. I have it functioning with the GET method, but I'm concerned a user could find the URL for my delete php and put in random ids, deleting everyone's images. Is there a way I can adjust my code to make it safer?
<?php
$sql = "SELECT id, userid, name, image FROM images";
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) > 0) {
// output data of each row
while($row = mysqli_fetch_assoc($result)) {
if ($imageUser == $row["userid"]){
echo "<tr>";
echo "<th>".$row["userid"]."</th>";
echo "<th>".$row["name"]."</th>";
echo "<th><img src='showimage.php?id=".$row["id"]."'></th>";
echo "<th><a href='imgdelete.php?id=".$row["id"]."'>delete</a></th>";
echo "</tr>";
}
}
} else {
echo "0 results";
}
?>
The delete.php simply deletes the entry WHERE id=$_GET['id'];
In a RESTful API, a GET request should never modify the data. If you want to delete items, you should use a POST or a DELETE request.
I'm having a little bit of an issue figuring this one out. What I've done is i've created a table using a while loop that displays all my courses into an html table :
<?php
include_once "Includes/config.php";
function manCourse(){
$SQL = "SELECT cname FROM course";
$result = mysql_query($SQL);
if (!mysql_num_rows($result))
{
echo "There are no courses.";
}
else
{
while ($row = mysql_fetch_assoc($result))
{
echo "<tr><td> Course name: <b> " .$row['cname']."</b></td> <td><a href = ''>Edit</a></td> <td><a href = ''>Delete</a></td> </tr>";
}
}
}
?>
My issue is when someone clicks the delete or edit link it needs to do just that. What can I use as a key so it knows which row it needs to edit or delete?
Any help would be appreciated! thanks.
<?php
include_once "Includes/config.php";
function manCourse(){
$SQL = "SELECT id,cname FROM course";
$result = mysql_query($SQL);
if (!mysql_num_rows($result))
{
echo "There are no courses.";
}
else
{
while ($row = mysql_fetch_assoc($result))
{
echo "<tr><td> Course name: <b> " .$row['cname']."</b></td> <td><a href = ''>Edit</a></td> <td><a href = 'delete.php?id=".$row['id']."'>Delete</a></td> </tr>";
}
}
}
?>
delete.php is your new file where you will add code for deleting record. $row['id'] is primary of record, which is always unique.
Its very good database design to always include a unique primary key for each row. This will solve your issue here, and will allow for other benefits like joining to other tables. This key should then be included in your table, but not visible to the user.
create table course
(
course_id int not null primary key auto_increment,
. . .
)
Pass that key back from the UI when they click delete, and use this SQL to delete it from the database:
delete from course where course_id = $course_id
you must create a page named delete.php
the delete.php must have this code.
and you must pass the variable via tha delete link which will be like this
while ($row = mysql_fetch_assoc($result)){
echo " Course name: " .$row['cname']." Edit Delete ";
}
The question might seem a little odd but I will show you what I mean :)
So I have made a webpage that contains comments that have been made by authorised users (teachers). That is another piece of code in another page so that works perfectly.
Of course it should be possible for the person who made the comment to change his own comments in case of mistakes etc.
I managed to show the user his own comments with his comments in seperate text areas.
The text areas have no specific name and are just called txtComment, how do I make them unique for every comment (which is flexible because comments can be added later).
I think that is the issue why I cannot update the changed/adapted textareas after I press the button.
I hope you guys understand what I am trying to say :p
I changed Dutch words mostly to English so if there is a spelling error that is due to that :)
This is the code:
<?php
$sqlKlas = "Select * from tblcomments WHERE ForWho='".$_SESSION['User']."' AND ForWho='6HA1' OR VoorWie='6HA2'";
$resultKlas = mysql_query($sqlKlas) or die(mysql_error());
if (isset($_POST['btnAdaptCommentKlas'])){
while($rowKlas = mysql_fetch_array($resultKlas)){
$CommentNr = $rowKlas['CommentNr'];
$sqlUpdate = "Update tblcomments SET Comment='".$_POST['txtComment']."' WHERE CommentNr=$CommentNr";
$resultUpdate = mysql_query($sqlUpdate) or die(mysql_error());
echo "<tr>";
echo "<td>";
?><textarea name="txtComment" cols="80" rows="5"><?php echo $rowKlas['Comment']; ?></textarea><?php
echo "</td>";
echo "<td>".$rowKlas['ForWho']."</td>";
echo "<td>".$rowKlas['Datum']."</td>";
echo "</tr>";
}
}
else {
while($rowKlas = mysql_fetch_array($resultKlas)){
echo "<tr>";
echo "<td>";
?><textarea name="txtComment" cols="80" rows="5"><?php echo $rowKlas['Comment']; ?></textarea><?php
echo "</td>";
echo "<td>".$rowKlas['ForWho']."</td>";
echo "<td>".$rowKlas['Datum']."</td>";
echo "</tr>";
}
}
I would do it a little differently - updating separate to listing out the comments. Also You would have to set the textarea name containing the comment ID, like in my example:
<?php
$sqlKlas = "Select * from tblcomments WHERE ForWho='".$_SESSION['User']."' AND ForWho='6HA1' OR VoorWie='6HA2'";
$resultKlas = mysql_query($sqlKlas) or die(mysql_error());
if (isset($_POST['btnAdaptCommentKlas'])){
foreach($_POST['txtComment'] as $key => $value) {
$sqlUpdate = "UPDATE tblcomments SET Comment='".mysql_real_escape_string($value)."' WHERE CommentNr=".(int)$key;
$resultUpdate = mysql_query($sqlUpdate) or die(mysql_error());
}
}
while($rowKlas = mysql_fetch_array($resultKlas)){
$CommentNr = $rowKlas['CommentNr'];
echo "<tr>";
echo "<td>";
?><textarea name="txtComment[<?php echo $CommentNr; ?>]" cols="80" rows="5"><?php echo $rowKlas['Comment']; ?></textarea><?php
echo "</td>";
echo "<td>".$rowKlas['ForWho']."</td>";
echo "<td>".$rowKlas['Datum']."</td>";
echo "</tr>";
}
Also I would recommend not to use mysql_* function but use PDO or at least mysqli_* instead. Using mysql_real_escape_string() to escape the user input is highly recommended.
Also using MVC and separating the data manipulation (updating, fetching, creation) and data presentation (in an HTML template) would be much nicer and more maintainable for further development.
Instead of txtComment use txtComment[unique_id].
This way you can do something like
foreach(array_keys($_GET['txtComment']) as $id => $comment) { ...
then try this
$sqlUpdate = "Update tblcomments SET Comment='".$_POST['txtComment']."' WHERE OpmerkingNr='".$OpmerkingNr."' ";
and change this
$sqlKlas = "Select * from tblcomments WHERE ForWho='".$_SESSION['User']."' AND ForWho='6HA1' OR VoorWie='6HA2'";
to this
$sqlKlas = "Select * from tblcomments WHERE ForWho='".$_SESSION['User']."' AND (ForWho='6HA1' OR VoorWie='6HA2' )";
you could also check the user if logged in or not here
if (isset($_POST['btnAdaptCommentKlas'])){
try change it to
if (isset($_POST['btnAdaptCommentKlas']) AND $_SESSION['User'] !=0 ){
obs: I advice you to use PDO instead.
I am writing a script that allows users to create teams, send contracts to others that are registered, so on and so forth. I want the logged in user to be able to withdraw from a team. The html tables are dynamically populated from mysql using php. I can get it to apply my delete option to all the users within the <td></td> but not just the one that is logged in. Here is some code snippets to help I hope. Basically I want only the user that is logged in to have the delete option.
Id Player
1 User 1 - No Delete Option
2 User 2 - Delete Option (Is the logged in user)
3 User 3 - No Delete Option
session_start();
$get_users_name = $_SESSION['username_u'];
$sql = ("SELECT id, username FROM user WHERE username='$get_users_name'");
$result = mysql_query($sql) or die(mysql_error());
while ($row = mysql_fetch_array($result)) {
$grab_id = $row['id'];
$grab_user = $row['username'];
//the rest of the table generation done here such as <tr> etc
echo "<td>";
if ($grab_user == $get_users_name) {
echo ''.$grab_user.'';
}
else
{
echo $grab_user;
}
echo "</td>";
//the rest of the table generation done here such as </tr> etc
}
**Edited to fix echo problem caught by #easteregg
Just be sure you will style your code for readability ,then you will notice that you have your if condition inside the echo ;)
Try this it should work!
echo "<td>";
if ($grab_user == $get_users_name) {
echo ''.$grab_user.'';
} else {
echo $grab_user;
}
echo "</td>";
Be aware of the fact, that you should check again in the user_delete.php if a user has the right to delete something , otherwise you will run into some strange sort of trouble ;)
I'm working on a project to further learn php and how it can be used to interface with a mysql database. The project is a forum, with the page in question displaying all the topics in a category. I'd like to know if I am handling my calls efficiently, and if not, how can I structure my queries so they are more efficient? I know its a small point with a website that isn't used outside of testing, but I'd like to get a handle on this early.
<?php
$cid = $_GET['cid'];
$tid = $_GET['tid'];
// starting breadcrumb stuff
$catname = mysql_query("SELECT cat_name FROM categories WHERE id = '".$cid."'");
$rcatname = mysql_fetch_array( $catname );
$topicname = mysql_query("SELECT topic_title FROM topics WHERE id = '".$tid."'");
$rtopicname = mysql_fetch_array( $topicname );
echo "<p style='padding-left:15px;'><a href='/'> Home </a> » <a href='index.php'> Categories </a> » <a href='categories.php?cid=".$cid."'> ".$rcatname['cat_name']."</a> » <a href='#'> ".$rtopicname['topic_title']. "</a></p>";
//end breadcrumb
$sql = "SELECT * FROM topics WHERE cat_id='".$cid."' AND id='".$tid."' LIMIT 1";
$res = mysql_query($sql) or die(mysql_error());
if (mysql_num_rows($res) == 1) {
echo "<input type='submit' value='Reply' onClick=\"window.location = 'reply.php?cid=".$cid."&tid=".$tid."'\" />";
echo "<table>";
if ($_SESSION['user_id']) { echo "<thead><tr><th>Author</th><th>Topic » ".$rtopicname['topic_title']."</th></thead><hr />";
} else {
echo "<tr><td colspan='2'><p>Please log in to add your reply.</p><hr /></td></tr>";
}
echo "<tbody>";
while ($row = mysql_fetch_assoc($res)) {
$sql2 = "SELECT * FROM posts WHERE cat_id='".$cid."' AND topic_id='".$tid."'";
$res2 = mysql_query($sql2) or die(mysql_error());
while ($row2 = mysql_fetch_assoc($res2)) {
echo "<tr><td width='200' valign='top'>by ".$row2['post_creator']." <hr /> Posted on:<br />".$row2['post_date']."<hr /></td><td valign='top'>".$row2['post_content']."</td></tr>";
}
$old_views = $row['topic_views'];
$new_views = $old_views + 1;
$sql3 = "UPDATE topics SET topic_views='".$new_views."' WHERE cat_id='".$cid."' AND id='".$tid."' LIMIT 1";
$res3 = mysql_query($sql3) or die(mysql_error());
echo "</tbody></table>";
}
} else {
echo "<p>This topic does not exist.</p>";
}
?>
Thanks guys!
Looks like a classic (n+1) query mistake that could die a latent death. You get a key using one round trip, then you loop over the results to get n values based on it. If the first result set is large you'll have a lot of network round trips.
You could bring it all back in one go with a JOIN and save yourself a lot of network latency.
The statements themselves are fairly simple so there's not much you can do to optimize them further that I know of. However, if you create some business objects and cache the data into them on a single call and then access data from the business objects then it could be faster.
In other words, 1 SQL call for 1,000 rows is going to be much faster than 1,000 calls for a single row.
Here are some of extra things I would do when I write a code like above:
Never use * in SELECT statement when you know the columns you are going to use.
Always use or die(mysql_error()) when executing the query.
Unset the result sets once the result sets has served its purpose.
Use mysql_real_escape_string() to escape the injections when using some substitutions in your queries.