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.
Related
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.
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.
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).
On my website I have a registration page which makes an AJAX request to check if a username is available after it has been entered. This file is called check.php and is in the same directory as the registration.php file. When data is posted to check.php it will perform a query at a MySQL database and return how many users it found with that username.
If anybody were to post data to the check.php file they would see the result, too. I need to stop this somehow, I've read on a few answers I need to "authenticate" each request. This is probably a very large topic although I'm not too sure what to search for to find more about it. Is authenticating each request a good way to stop unnecessary username checks? If so I would really appreciate it if anyone could point me in the right direction as to how to do this.
A solution is to generate a unique token in session, and put it in all pages that will contain a form. Post this token on each AJAX request you make.
It is called CSRF protection, Cross-Site Request Forgery.
You can add a protection layer checking the user referer in HTTP headers.
Answer for common case: no - you can't prevent this, since AJAX is just an HTTP-request. It can be sent no matter how you'll protect your server. So if the point is - to protect from 'evil hackers' - there's no way to do this. The correct though is to check/validate anything on server side.
But is it's about only basic check, you can read
if (strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])=='xmlhttprequest')
-but be aware - this is also a data, which came from client i.e. it can't be trusted (actually, it's just HTTP-request header, nothing more)
I think you can create a Session variable when the user logs in your aplication and check if this variable has the correct value whe you post something to your 'check.php' file to check if your user is previous authenticate
Missing a lot of info but conceptually I am not sure you are worrying about a real risk. Bottom line is that people can use your form to check if emails exist so it's logical they can use check.php as well. Would be overkill to try and prevent that.
I have one think - you can generate some unique token, store it on SESSION before show the page. Than on each checking you must to add this token to request. check.php must regenerate token and return it new.
But each request can emulate and it not protect you from people, which want to know results of check.php. Nothing protect...
Also you can make mechanism for analyzing ip request for checking
I was recently messing with a django local server project and I had a input like
<form....{% csrf_token %}
....
<input type="text" value="foo" readonly />
....
</form>
Now the value of the input should stay the way I want it to ("foo"), but I used google chrome inspect and was able to change the value of the readonly input and pass the new value to the server, which saved the bad value.
So I have a few questions:
What are the general rules or mental checklists to prevent security risks like this?
Could I use the JavaScript console and corrupt data like this as well? Update: YEP.
So do I have to basically do all my checks on the server side?
If no to 3, what are the client side validations that are protected from html/js inspectors?
Edit:
I'm guessing from the answers so far, it's yes to 3. So should I still bother with client side security/checks? Will they actually make me more secure or is it just a false sense of security (which is bad)? Should I do client side checks to possibly save some checks on the server side, so my performance might be better? Basically: How much client side checking should I do?
You cannot reply on Javascript or anything on the client side for security. Just ensure that your server is secure.
For example you can just telnet to the port and send the appropriate data to the server. This will thwart and checks via Javascript (or any other technology( on the client side.
Just use Javascript to make the users experience on the client more enjoyable and more responsive. Do not use it for security.
Ask yourself why you needed that readonly value in the first place. Presumably, it was your code that generated it, when the user first requested the form. So, what was available to your code when the user requested the form that is not available when the user submits it back? There shouldn't be anything, which should lead you to the conclusion that that field can just as easily be generated on submit, without it needing to appear in the form at all.
Your server code must be the final authority, it simply cannot rely on the quality of validation that the client has done. View all clients, be they HTML or otherwise as prone to the effects of both devious users and fallible coders.
Never believe the data sent by a user (cookies, session,parameters in HTTP request,...). All data send by users can be modified.
Yes of course
It is still to be done.