Get or Pass Sensitive Data via AJAX in PHP - javascript

I want to update a row of data in a database using Ajax and PHP; however, I'm struggling with the following issue: the field in the database to update (henceforth the id) is dependent on the page the ajax request is sent from.
I need to get this id to my PHP script that Ajax calls, however:
I don't want to set the id in a data attribute or hidden input on the page because these can both be manipulated by a malicious user.
Similarly, identifying the id using the referring URL is also prone to spoofing as $_SERVER isn't secure.
I can't set the id in a SESSION variable (or COOKIES) because the user could have multiple pages open and the SESSION would only hold the last page id that was opened.
The only solution I can think is to create a map of random tokens to id's in a table in the db and pass that in a SESSION variable (as per #3 above), then check the table for the token and grab the respective id that way. Seems somewhat convoluted though.
Are there any other options or thoughts? Thanks.

This is a problem related to OWASP Top10 A7 (Missing Function Level Access Control).
There might be no issue with putting your ID on the page so the page can send it back - you just need to validate that the actual save request is permitted for the user.
Just think, regardless of whether you put the ID on the page or not, the page does know the base url for performing the action, so they could go ahead and guess IDs anyway.

Simplify your logic. Pass some sort of indicator of what type of id is in use from the client to the server.
If you create overly complex application logic to address a security concern you will probably have more problems with your code than improvements in security.
Use SSL/HTTPS and a WAF (web application firewall - like mod_security).

Related

How to send data to another page without using cookies or JS in PHP?

So, I have a PHP file that runs an SQL(MySql) query and gets the result. I need that page to send that result to another page automatically(I can use PHP in the receiving page). However, I want to make my website accessible to privacy-sensitive people who disable cookies and javascript on their browsers. I'm not using any PHP frameworks.
An initial page that runs the query only runs in the backend like a controller so it does not have any HTML in it. This means I cannot use a hidden form and make the user submit it with a button. I thought about sessions but they need cookies to work and JSON needs javascript. I thought about sending the data in the URL but the query result is quite big and I was afraid it could exceed some kind of URL length limits(if such thing exists). Is there a way to achieve this reliably?
EDIT: To clarify some things, the data I am sending is a search result so the query changes depending on the users input(which was provided to the page which runs the query with a form).
Store data somewhere and send id or something through query string and access data from database through that id from query string. Sending too much data is not advisable through cookies, session or even query string just pass your unique id and grab data from db.
Happy coding.

Securing PHP scripts - Shopify

Basically my question is similar to this one:
How to secure php scripts?
with one slight difference, the other side is Shopify.
Background info:
Shopify user bought some credits (Audible style), and wants to know how many he has available. He logs in into his account, and it says there that he has X credits.
That number comes from AJAX call to my server (I have full control), where there is a simple php script which checks the value in db (which is updated using webhooks from Shopify, each of which needs to be verified so they are secure, I think).
The script uses customers ID for a look up, and that value needs to be passed to the script somehow, and that allows someone external to just keep running it until he has all IDs and corresponding credits values.
So, my questions is, how do I stop that? How do I ensure that only authenticated users can check it, and only for their IDs.
There is plenty of info on Shopify docs about securing the connections the other way, i.e. to make sure only correct scripts have access to the Shopify db, but nothing about my problem.
As far as I know I only I only have access to JS on Shopify, which creates the problem, because everything I send to my server is visible to all.
Thanks
EDIT: I just read up on CSRF. I can easily implement checks for origin and headers, but these can be faked, right?
EDIT 2: I got around this problem by using metafields. So, instead of storing all that info on my server's db, I just use Customer Metafields to store the available credits. Webhooks are secure so that's brilliant. It still doesn't solve a problem with the next stage though. Customers will still need to be able to use their credits and get digital products, which are generated by my server. So I still need to verify the requests.
EDIT 3: Comment by #deceze and answer by #Jilu got me thinking. Yes, you are correct, I need to do that, but I don't have access to back-end on Shopify, so I cannot create session. However, what I could do (if I figure out how in js) is hash it. PHP login scripts operate on password_hash. That way you do not store a password in the db. Password get's verified again hash (or whatever you call) in the db, and it's either true or false. If true, you are logged in. So I could try to generate a token using a specific string (make it very long) and user id. Send it with the request, and using password_verify or what not, check it against the users. The one that pops positive is logged in user who requested the information. That is assuming I can hide the string in the Shopify...
Step1: Do a session login system.
Step2: Before the Ajax, generate a random token in your form or request page, put it into a input display none, send it with POST.
Verify each time if the token is set and is the same that you got.
You have now verified if the user is really logged in with session.
And you checked that he is from the right page.
You create a token out of shared secret (both Shopify and server have it), and client ID.
On Shopify:
{% assign my_secret_string = "ShopifyIsAwesome!" | hmac_sha256: "secret_key" %}
My encoded string is: {{ my_secret_string }}
On server:
We gonna be checking received hash value against values in our db, so we need to hash local client IDs using the same algo and key (that probably should be done on receiving the Customer Creation webhook).
Hash IDs using: http://php.net/manual/en/function.hash-hmac.php
$hashed_id = hash_hmac('sha256', '$client_id', 'secret_key');
Compare hash using: http://php.net/manual/en/function.hash-equals.php
$check = hash_equals($hashed_id, $received_id);
Then all that's requires is to loop through the db until you find a match. There may be quicker ways of doing it.

How to secure data or row ids that represents something in PHP

In my project a user can make a post (post a photo or some text). Technically I identify each post with a unique id in table posts where I store the user_id (owener of the post) and the id of the post is set to auto increment . Knowing the identification for each post I fetch all rows in the post table and put these post and relevant details( post_id, user_id, data, etc) inside an HTML. There are more things a user can do on that post, like discuss on the post, rate the post, and etc.
These things are done via an ajax post since I store the post_id on the HTML element attribute like ( data-p=52). sometimes I use the php base64_encode function to encrypt the post_id
Most in my application an event is acted on these post_id and user_id that is or are stored in the HTML custom attributes.
Now I am thinking of security issues and my question is : Is there a proper method or way I can hold these info in Javascript or a proper way I can encrypt these information about the post.
It is good you are thinking about the possible security vulnerabilities within your system. However, at the moment, from what I can tell, you are not quite worrying about the right thing. Data, like a user's ID, a post's ID, is not sensitive in itself. If you look at the URL of social networks, etc, it is very likely you will see user ID information, etc. What you need to think about, is how can I make sure that it doesn't matter this data is public? In other words, how can I prevent an attacker from using this data? Because this data on it's own, is just a bunch of numbers. Now, if there is a reason why these IDs are actually sensitive in your system, you should think about a slight structural rearrangement.
Take the common (or less so these days) SQL Injection technique. Where a attacker will input SQL code into a user input, and that input will then be concatenated/substituted right into a SQL query, therefore giving unwanted access to the database (see here http://www.w3schools.com/sql/sql_injection.asp). It does not matter the attacker knows the post ID, meaning oh no! He can delete the post he wants to, instead, it matters that he can delete any post he wants. So the problem is in the SQL vulnerability, not the knowing of the ID. And, to fix the SQL vulnerbabilty, you need to make sure that user input will disallow code-like characters. This is known as sanitization.
Of course I am not saying you shouldn't take care of what data is available to users. But the system itself needs to be robust.
The scenario you're worried about (that an attacker can use these IDs to send requests to your system to manipulate data in a way that you don't want) is independent of whether you expose your IDs to the client or not.
In some fashion, requests from your client will need to be handled by your server. If you have a feature where authors of posts can delete their own posts, hopefully you are validating delete requests that the user initiating the request is actually the owner of that post and not just blindly deleting data whenever someone asks your system to. Even if you introduced a surrogate key so as to prevent the actual primary key from leaking to the public, whatever route endpoint that is used to delete posts will still need to handle that data in a robust fashion that maintains the integrity of your data.
As I stated in a comment, really the only thing you should worry about are people performing maths on your IDs (such as plus and minus 1) in order to see if they can game your system and receive data back that maybe they shouldn't have. But even in that scenario whatever endpoint is responding to the request should validate that request before returning anything back. You can prevent this entirely by a) validating that the user requesting the data actually owns the data and b) by not using auto incremented integers as a primary key and instead relying on UUIDs as your primary keys.

HTML hidden input shouldn't be editable

I just discovered a bug which I couldn't find any solution of, I would like your advise on that. Issue is there are a few hidden input types, which are there to store ID's of already saved data such as per person id if it is already saved etc. etc.
I just tried and change the value of that hidden variable manually, using google chrome and submit the form and surprisingly i did not get the id that should be there but instead i received the Id that I changed. for instance there was an value of 22 I change it 263 I received 263, whereas I should have be receiving 22. I want that 22 to come not that 263.
Its hard to explain I know but I have tried my level best to convey my issue please help and advise my on that how should I store some hidden value that are un-editable.
Any Idea?
Rule of Web Development #1: Never trust the client
Rule of Web Development #2: Never trust the client
Rule of Web Development #3: You can't make the client trustworthy
If the user shouldn't be able to edit it, never give it to them.
As others have said, there are a few ways to handle the situation. The most common is to use a SESSION variable on the server, available almost everywhere.
Store the "secret" values on the SESSION. They will be available when the user posts back.
You cannot control what data users put in HTTP requests to your server.
Instead, use authentication and authorization, on the server, when the request is received, to make sure that the user is allowed to submit the values they submit.
If you're wanting to keep track of data from one page to another I would use sessions. This is data that is tracked on the server.
//page one.php
$_SESSION['id'] = 22;
//page two.php
echo $_SESSION['id']; //22
This is a basic functionality of how browsers work - essentially someone could POST data pretending to be your form with whatever values they wanted in the fields - or even add extra fields.
If it's a problem consider moving that data from hidden fields to session variables.
If it's important for your hidden fields to be secure, don't contain them on the client-side. Client side variables are pretty easy to modify.
You should probably store them in your session, so they're not outputted to the client. If they're required on the page, use AJAX to grab them instead.
It kinda depends on the domain of your application, if it's in-house software then I wouldn't worry about it particularly.
It does not look like a bug.
What scares you about this? These fields are not going to be accessed and changed by your visitors. If you're afraid someone is going to hack the http request of your visitor and change his order (for example), then https connection should help.

Shall I use javascript for page submission?

I am working on a big site, and in the site there is a search module. Searching is done by using a a lot of user submitted values, so in pagination I must pass all these data to the next page, appending the values to url make the url very big.
Sso how can I solve this issue? I am planning to use a javascript based page submission (POST) with all the values in hidden fields to the next page the read all the values from the next page.
Will it cause any problems? Or should I use database to keep the search criterias?
I would create a server side object, possibly with a database backend which is updated by the different pages.
It is at my opinion the most clear and easy solution. Giving parameters from page to page, either by post or javascript or cookie will work too but it's more of a quirk in my experience.
Also if a search query is so complex that it needs multiple pages to create it, it might be helpfull for the user to have all the data stored on the server so he can change it more easily by switching back and forth between the different pages.
I would store all the search criterias in some kind of session-store on the server when the initial search is being triggered.
For pagination I would retrieve the criterias from the session-store and then just show the appropriate results. Also I would append some kind of key to the pagination links (so this would be the only hidden post-field) under which the search criterieas can be found.
Even though the session is per user, you might have several search windows open within the same session, and you don't want to mess them up with the pagination.
In order to make a reliable search with pagination, we need to do a bit more than normal.
We need to handle the following cases.
Once search is done, user may choose to do browser back and forward. Here, if you are doing form submission on every page, it would be an overload. Also, if user presses browser refresh button, it will unnecessarily warn him that data is being submitted.
Searching on a large database with lots of criteria is costly. Hence, optimization is important.
So you should NOT do the following:
Submit data on every page change
Not store data in cookie. (This is not secure and not even reliable.)
For large database with complex query, cache the result in session.
In case, you need very up-to-date and real-time result, ignore point (3) and try doing partial search for every page.
Thus, for your case, you can do the following:
When user searches first time, make the form POST data to a search page.
This search page will store the search query in session and generate a unique id for it.
Now render the result page. The result page will be passed the search id (generated in point 2) and the page number. Example result.aspx?searchId=5372947645&page=2
The result page will puck up the query from session using the searchId and then provide result based on the page number sent.
Using hidden fields and POST method should be fine too unless you are able to get them on the next page right.
To supplement Sarfraz's answer...
It's not necessary to use Javascript to make a POST.
<form action="destination_url" method="POST">
...
</form>

Categories