I am working on a OpenCart based eCommerce website and would like to know how to hide the variables passed in a URL. The reason I want to do this is that we allow the customer to print their invoice at the end of a successful transaction and the structure of the URL is as follows:-
http://www.mywebsite.com/invoice/standard&order_id=1000010
Now the thing is, if you change the last value of the order_id to anything else or even change any of the other digits, it will show you the invoice for that order number and if that order_id belongs to another customer, it will show their details to this customer.
So now what I would like to know is that is there a good way to encrypt this url and decrypt it on the server-side to complete the request without showing the user order_id.
Please let me know if you need anymore info and I'll try and add it to my question.
I don't have experience with Opencart, but chances are it checks whether the current user is logged in, and displays the invoice only if it belongs to them.
If that is not the case, the underlying problem should be fixed instead, and access to invoices limited to the customer (e.g. through a login system), instead of creating security through obscurity.
You shouldn't need to do this really, instead you should be validating the logged in user for that invoice within the model/DB File.
For example....
I assume as it stands, your DB query would be similar to this:
$this->db->query("SELECT * FROM `" . DB_PREFIX . "order` WHERE order_id = `" . (int)$order_id . "`");
You should check also check the customer_id:
$this->db->query("SELECT * FROM `" . DB_PREFIX . "order` WHERE order_id = `" . (int)$order_id . "` AND customer_id = '" . (int)$this->customer->getId() . "'");
If the invoice is not owned by that customer, then no results would be found.
I haven't worked with Opencart but I believe the order_id being displayed in the URL is not the big problem. The major issue here is that other users can view another user's invoice. You have to perform access control for non-public pages like these. ONLY allow the owner to look at their own invoice.
Now to answer your question, to prevent your order_id from being shown on the URL, you need to use POST data, currently you are using GET. You can access POST data using $_POST.
This is not a standard feature, and as such you should contact the developer of the extension. If your store allows guest checkouts, then the URL should contain a random key of some sort, or the e-mail address attached to the order for instance to validate that the request is from an authorised user only. If the order is for a registered user then the customer_id assigned to the order should be validated against the current logged in user, and redirected to a login if the user is not logged in
Related
I made a login function with bruteforce protection, different bot protection functions like honeypot.., input filtering, Argon2 encrypted password.
But in the end to identify the user i save the id inside a session after a successful login.
With this id until now i checked if the column "admin" has the value 1 or 0.
If this value is 1 the user can do everything.
How i could improve the security ?
How else i could check if a user is an admin ?
You should do as I will direct you
As long as you have user id in act so it's half of the way
I will assume that you have function.php which have all the functions you use in website
Also you have login function that check user account details and give access
You now need to improve that to restrict user access
First:
Create table in MySQL call it group this table will have two records or as you like so. Admin will have id 1 and members id 2 then you can make much modifications like make another column in that table called upload and set admin to yes while members to no
Second in your login function use the following
$res = mysql_query("SELECT * FROM users INNER JOIN group ON users.class=group.group_id WHERE users.enabled='yes' AND users.status = 'confirmed'") or die(mysql_error());
$row = mysql_fetch_array($res);
Users.class is the group id and users is the table users
Now you can check group credits as example if on upload page you do the following
if($row["can_upload"]=="no")
echo("admin only can upload ");
You can check credentials on group as you need also you can make much classes like admin , members, uploders, reviewers,authors and give every class special permissions as website content is viewed
On admin.php you can use
if($row["admin"]=="no")
ech("admin only can view this page ");
In both examples above Admin and can_upload is colum in group table and it's changed by user class .
I have a php page which does an insert and then does a redirect to a "success" page which displays the order details. I am redirecting by using a variable, but I am thinking this is not so secure:
header("location:success.php?id=$orderid");
This generates a url like this: success.php?id=22
I am then using the URL to obtain the order ID number and doing a query based off of that to present the order details:
$getName = explode('?id=', $_SERVER['REQUEST_URI']);
$id = $getName[1];
$query = <<<SQL
SELECT * FROM `order` WHERE `orderid` = ?;
SQL;
$request = $mysqli->prepare($query);
$request->bind_param("i", $id);
$request->execute();
The obvious issue is that anyone could simply change the URL id number to get the details of a different order number. I'm not too terribly concerned as this is strictly an internal site, but I'd still like to fix this behavior. Is there a better, more secure way to do this?
Here is an easier solution: Store orderid in the session like this $_SESSION['orderid'] = $orderid.
And on redirect you'll get it's value as below:
$getName = explode('?id=', $_SERVER['REQUEST_URI']);
$id = $_SESSION['orderid'];
$query = <<<SQL
SELECT * FROM `order` WHERE `orderid` = ?;
SQL;
$request = $mysqli->prepare($query);
$request->bind_param("i", $id);
$request->execute();
In general, the problem of allowing a customer to view a past order while not allowing others to view this order has two steps.
Set authorization policy: Determine which users are allowed to view which order numbers. This ought to include the ability to come back in a later session and view the status of an order.
Back it with an authentication method: Store and retrieve enough information to identify the user.
Authorization policies to consider include the following:
The user who just placed an order is allowed to view it in the same session. This is the policy you describe in your question.
Placing an order creates a unique ID. Anyone with this ID is allowed to view it.
Someone who creates a user account, provides an e-mail address and verifies ability to receive mail at that address is allowed to list orders associated with that billing e-mail and view them.
Someone who provides the correct order ID and shipping postal code (or other PII needed for order processing) is allowed to view that order, but not list any, and this is rate limited in some manner for each IP address. (Users behind a big NAT have the other three choices.)
To implement policy 1 (same session), you can store the order ID in the session, whether in PHP's $_SESSION or in a separate session properties table, as soon as the order is marked as paid. Then when the user tries to view an order, you can allow it if the order ID matches the most recent for this session.
To implement policy 2 (unique ID), you can generate and store a suitably long random identifier, such as a version 4 UUID, and store it with the order. Warn the user: "Be careful: anyone who sees this order ID can view and change your order."
To implement policies 1 and 2 in one stroke, you can store the session ID with each order, display the session ID on the success page, and then let the user search for orders associated with a particular session.
To implement policy 3 (control of billing e-mail), you can add a user table including user ID, password hash, e-mail address, and (nullable) e-mail confirmation date. This would also give you a chance to add user-created product lists, which lets you add features such as an alert when a product comes back in stock.
To implement policy 4 (order ID and shipping info), you can make a table logging the IP address, date, and more information about each request, apply a heuristic to determine whether a scripted brute force attack is in progress, and then compare the shipping postal code provided by the user to that in the order.
Keep these policies and mechanisms in mind as you continue to develop your store application, as they are likely to increase its usability.
On your system I assumed your orders are related to you users.
For example order: 1234 has relation with user: 5
Check this relation on your success.php
If your scheme has not user-order relation I strongly recommend it. But if orders doing by anon users, hash order_id
basically like
select * from order where order_id = 1234 and userid =5
If this query returns a row, that user really has this order. Else something is wrong.
if($returnedRow == 1){
//Do something here
}else{
//access denied. You are not owner of this order.
}
As I said, count returned row, this is simple way. Also if you hash your order_id like dfljfk45498ds545 it can be less predictable. You can use uniqid() for this purpose.
use cookie or session to send "$orderid"
*session is better
I would like to monitor which dashboard user ("admin") added new product to the database.
The solution i was thinking about is simply adding another insert under admin > model > catalog > product.tpl under function addProduct(), which adds the user id to the custom column added before under oc_product.
$userID = // currently logged in
public function addProduct($data) {
$this->event->trigger('pre.admin.product.add', $data);
$this->db->query("INSERT INTO " . DB_PREFIX . "product SET addedby = $userID, .......");
.......
}
The only problem I have now is how to call / get the currently logged admin id inside this file (model/catalog/product.tpl).
This is just how i think about it, if this idea is completely wrong, please do write some better solutions.
It would be better if you create another table to store this information since it will save you from altering the core table. In new table you store the user_id and product_id and set product_id as primary key.
Now you will be able to fetch this data as you require by joining these two tables ON basis of product_id match.
The idea is correct (at least for me, this is how I was going to do it)
You can get the id of the currently logged-in admin through a call to $this->user->getId()
Add this code fragment $userID = $this->user->getId() inside the addProduct function, not inside the class declaration
There is no such a column named added_by in product table, you will have to alter the table structure and add it
I am creating a simple db for School Students and want to achieve it in wordpress using any method that is available now.
Every student details like first name, class etc will be saved in database along with ID as primary key.
In PHP, there used to be ONE file like details.php etc and based on QUery passed using GET or POST method, it will display the details. Can we do the same in Wordpress using a SINGLE Page or Post;
Instead of creating seperate Page / Post for every student, i had created PHP Queries in Page / Post using WP Plugin which will display the details of student based on querying ID.
But i am not sure how to make it generalized so that on entering http://mywpsite.com/studentpageorpost/?id=10 i should get the details of student with ID 10; and on entering http://mywpsite.com/studentpageorpost/?id=11, i should get the details of ID 11;
Can anyone please help on this.
If I understand well the code would work like this:
1 Take the id number from url and stored
1.1 htmlspecialchars() is for converting html tags so you can't be hacked by php injection
$id = htmlspecialchars( $_GET["id"] );
2 Here we have stored the user info in a object with the wordpress function get_userdata();
2.1 If ID not found return false.
$user_data = get_userdata( $id );
Accessing Usermeta Data
$user_data = get_userdata( $id );
echo $user_data->last_name . ", " . $user_info->first_name . "\n";
Results in:
Doe, John
If you want to know how to access more user info use print_r($user_data); and will output all the info that the user has.
Here are some of the useful values in the wp_users and wp_usermeta tables you can access with this function for use in your theme or plugin:
users
ID
user_login
user_pass
user_nicename
user_email
user_url
user_registered
display_name
user_meta
user_firstname
user_lastname
nickname
description
wp_capabilities (array)
admin_color (Theme of your admin page. Default is fresh.)
closedpostboxes_page
primary_blog
rich_editing
source_domain
Edit: I think the above system is the easiest still as MarkBlythe sed, no need for individual account, you can use custom post type plugin and custom fields. You could add the students very fast in a loop and array with this function wp_create_user( $username, $password, $email );
I am currently building a payment module which processes a customers account once a month. I have a query which gets all the customer payment items for the given month, sums the amount and then sends the data to the payment gateway. This works great and I receive back confirmation from the bank yes or no. If yes I then need to update all the items which were in the request with the invoice number. I am getting the sum using a while loop and this is performed before the request is sent. The gateway can only process a single request and I don't want to loop through each invoice item for each request, I would rather perform a single request for all outstanding invoice items.
Some code is:
$get_payment_items_query = mysql_query("SELECT * FROM tbl_invoice_item WHERE billing_cycle = date");
while($get_payment_items_result = mysql_fetch_assoc($get_payment_items_query)){
$invoice_amount = $invoice_amount + $get_payment_items_result['payment_amount'];
}
then later after I get the response back from the bank I am adding a record to the invoice table and getting the invoice id and then do:
$update_payment_item_query = mysql_query("UPDATE tbl_invoice_item SET status = '" . PAYMENTCOMPLETE . "', invoice_id = '$invoice_id' WHERE invoice_item_id = '" . $get_payment_items_result['invoice_item_id'] . "'");
This only updates a single record because the update query is outside the while loop. I know there is a way to store the record identifier in a string/array and perform a single update query but I don't really know the name for something like that so haven't been able to find an example.
I hope that makes sense but here is some more detail.
There are 5 items ready to be invoiced. I get the total amount of the 5 items. I then make a single request to the payment gateway to charge for the 5 items. The bank send back a response yes or no. If yes, I then generate an invoice id for the payment. I then need to update the 5 items with the newly created invoice id. The updating the 5 items in a single query is where I am stuck.
Thanks in advance.
I do not know if I understand your question right but you could use a sub-query in your where. Use the first query in where of second query:
WHERE invoice_item_id IN (SELECT invoice_item_id FROM tbl_invoice_item WHERE billing_cycle = date)
Found the solution. I am using a WHERE IN clause.
In the while loop I create a variable to hold the items which need to be updated
$invoice_item_id .= $get_payment_items_result['invoice_item_id'] . ',';
I then remove the last comma using substring_replace then in the update query I use
WHERE invoice_item_id IN (" . $invoice_item_array . ")
Seems to work OK.