I've got a database where you can load details of a candidate through the following get request url: database/candidates/?loadcandidate=n where n is the id of the candidate to load.
Is there a common practice where you can add something to the get request which would prevent my users from being able to type in any id to access the details of candidates? I want them to only be able to access the candidate page from my search results or by bookmarking the candidate page and revisiting it later.
I could probably figure out my own eccentric way of doing this, but I'm wondering if there is a common procedure?
Get requests are get requests and you can't prevent users from changing get request variables.
But reading between the lines, I think the solution you're looking for is obfuscating (hiding/cloaking the intended meaning of) the userid so that it can't just be plainly accessible via changing the id incrementally, (e.g., ?loadcandidate=1/2/3/4/5/6...).
In this case, try assigning a user code so that it would be harder to pull up candidates just by guessing the ID.
Just as a simple example (which by no means should be used for production) try simple MD5 hashing and get the first 6 digit substring.
Example:
1 = c4ca42
2 = c81e72
3 = eccbc8
...
database/candidates/?loadcandidate=c4ca42 will pull up candidate with user id = 1.
So that when you access database/candidates/?loadcandidate=n, n will be something much more difficult to guess, thereby decreasing the number of random lookups exponentially. Of course this will all depend on how random the obfuscation/code actually is.
Hope this helps!
Related
I have several forms where a user can make changes to events tied to their account but I'm not sure how to take care of security involving the user changing the value set in data-employeeID for example.
I initially set up a security check script that would look at an identifying piece of data coming in through ajax requests and before it goes on to actually use it. It would first do a series of mysql joins to work it's way back to the Users table and then do a final check to make sure the ID_NO of the users table can bej oined using the session stored userID.
I assume this would work and be secure. But the site is rather large, and often times 5 or 6 values are being passed though ajax calls. So on every public facing function I would need to repeat the process for each variable (Unless they can be tied together along the way; not always possible) before continuing on.
After googling around though I've only found results related to php/ajax processing errors, or security surrounding the user who is making the request.
If the user is legit though they can still make changes on the page, and keep all of the correct information except for changing something like the meeting ID to something else. If I only check the users CompanyID, or DepartmentID though my callback chain and skip meeting ID they will be able to get data inserted into the database that is not accurate, with a meeting possibly being manipulated because I didn't create a callback chain for every single variable being passed between ajax and PHP.
I feel there must be a better way and that this is a solved problem so I'm hoping someone can point me in the right direction before I dive too deeply into making an over-complicated process. Thanks.
Requested Sample Code:
$.ajax({
type: "POST",
url: "<?php echo base_url().'meetings/addstarttime/'?>",
data: {
validDaysID: this.dataset.validdaysid,
departmentID: this.dataset.departmentID,
companyID: this.dataset.companyID,
employees: employeesArray,
start: this.dataset.start
},
success: function(data){
//update html to show updated values
$validDaysID = $_POST['validDaysID'];//unencoded
$securityArray[] = array("validDays", $validDaysID)//Check if access to this value is OK
$tieItBack[] = array("Buildings", "BuildingID");
$tieItBack[] = array("Location", "LocationID");
$tieItBack[] = array("Department", "DepartmentID");
$tieItBack[] = array("Companies", "CompanyID");
From there I make a query that selects the COUNT(*) of rows for the initially requested table, validDays, INNER JOINS the tables specified in the tieItBack chain and then finally checks if Companies.ID_NO == $this->session->userdata('CompanyID');
If there is a hit then they have access, if there is no rows then they do not.
For this example three of the variables can be knocked off in a single query but that is not always the case. Also this is using replaced table/col names cause I'm paranoid I guess but the structure is the same.
You have no reliable way of guaranteeing that the client-side code is doing what you want it to do.
Your server-side software should distrust all input, regardless of whatever client-side validation you've already written. (Users might not even run JavaScript, for example.)
This isn't a problem that can magically be solved. It's just a reality about networked computers and software development.
I have a panel I'm making that will use session data from another forum to give it permissions. Basically when the user logs into our forum and the session and trust is created on the forum, they can click on the panel and the panel will check their browser cookie for the session id and trust id. It then takes that trust id and checks the forum's database for the user id associated with that trust. Then takes the session id and verifies that it belongs to that user id. The issue is that when I get the session id, the associated user id is part of a blob that i have to cast in order to get the data from the field. So I get a result like this:
('7c64c90413beb7d139c64ccc8b13380b',
'a:12:{s:12:"sessionStart";i:1454075264;s:2:"ip";s:4:"b???";s:11:"sessionCsrf";s:16:"-2Yx13nBLdstUj4H";
s:7:"user_id";i:20;
s:13:"password_date";i:1453353041;s:16:"previousActivity";i:1454072099;s:13:"trophyChecked";b:1;s:16:"promotionChecked";b:1;s:16:"dismissedNotices";a:0:{}s:15:"lastNoticeReset";i:0;s:13:"canAdminUsers";b:1;s:20:"userModerationCounts";a:2:{s:5:"total";i:0;s:13:"lastBuildDate";i:1454075264;}}'),
I know there is a lot there, but I singled out the part that matters to me. The first column returned is the session id, which im using to verify the user id, but the user id is in the middle of that all that crap in the second column. So you can see where I single out the definition, what I want to do is just assign that "20" after "user_id;i:" to a variable and discard the rest. I'm sure this is simply done, but at this point I think I'm just nuking it out and spinning wheels. I was thinking explode, but the structure of that data seems like that's not an option.
That data is simply the result of a PHP serialize() call. You can pass it to unserialize(), which will provide you with an array containing the values.
<?php
$str = 'a:12:{s:12:"sessionStart"…etc…etc…i:1454075264;}}';
$arr = unserialize($str);
var_dump($arr['user_id']);
In case you’re trying to extract the value from within MySQL alone, for some reason I’ve done something similar with an awful query containing lots of nested SUBSTR() and LOCATE() just two weeks ago. I wouldn’t recommend it. Especially because in my case I was doing a one-off reporting query, while you’re trying to do authentication with it. People might try to use specially crafted cookies to circumvent your string extraction and gain illegitimate access.
Im using functions for logging in a user, When they login but fail either by no captcha sent, failed captcha or failed login it will give there IP a Try. When they reach 5 tries they get blocked from the login page for approximately 1 hour. I have a function that updates the MySQL Column to increment there try count and last try date. But from looking at PHP's documents it states:
Note: The increment/decrement operators only affect numbers and
strings. Arrays, objects and resources are not affected.
My function gets the try count from the Database and then tries updating it. My SQL result for fetching the Try count is by default an Array because of how PDO works. So how can I efficiently increment an array?
I was thinking of doing a foreach condition and use the .=opperator to save it to a string and from there increment. But is that really the most efficient way?
Thank you.
P.S: I'm not showing any example code e.t.c because this question is simple enough. I have searched around on here and couldn't find a proper answer.
To understand why your question is wrong, you have to understand what an array is.
An array is just a "bag" that holds other variables. so, your question sounds like "How can I pay for a two beers with my pocket?". The thing is, you can't pay with a pocket. you have to take the cash out of the pocket and then use that cash.
Exactly the same thing goes with arrays: you have to extract the returned data from array, and then you are free to perform any operation on its contents. On the contents, remember, not on the bag.
But for the efficient solution, go for the other answer, which solved your initial problem the right way - without the need of selecting any arrays at all.
And just a side note
MySQL result for fetching the Try count is by default an Array because of how PDO works.
As a matter of fact, PDO can work in many different ways. For example, it can return scalar values all right.
You can increment it in an update query directly. When you want to add a try, simply:
UPDATE `tries` SET `tries` = `tries` + 1 WHERE `ip` = '127.0.0.1';
Just replace the IP with the actual IP.
Just to add..
IMO you should be using a separate table for incorrect login attempts. There are many reasons for this, but one of the important is that any attack is likely to rotate usernames and not only passwords in the attempt.
Having a separate table that records all incorrect logins allows you to much more easily query for an amount of incorrect logins in xx time. Incorrect logins attached to a user limits your ability to detect DoS and brute force attacks coming from scripted sources as you can only look at the username attempted if it actually existed in the first place.
However, you can relate a field in the table to the users ID, so that you can track users independently, then on successful login, the records that relate to that user could be deleted.
To give you a working example. I have built in the following functionality into the commercial Symfony project that I work on on a daily basis.
table example
userID --- foreign key (not mandatory)
IP --- mandatory
timestamp --- mandatory
we query the data like this:
Overall failed attempts for a particular subdomain (we have lots of them in use using the same system)
the system is used in schools, so we have to cater for naughty students!
Overall failed attempts in the last minute
system sleeps for a random time based on a base value x the amount. (a bit of a hacky way to try to trip up script attacks)
Overall attempts for a particular user
similar to your example.. compares to preconfigured amounts then warns/disables users accordingly. If it blocks sends an email to the helpdesk team.
this is by no means a suggested list, or an example of what should be done.. its merely what we decided on our applications circumstances.
The point is, without a separate table much of this wouldn't be possible.
Please help me argue my point.
I am working on a website project with a team of developers, we are developing the system in 3 parts. The one part is the API, 2 back-end and front-end. Both the front end and back-end gets and stores data by sending it to the API.
I am specifically responsible for the front end. I am using Codeigniter as my framework.
A little background: The app is a sports betting site.
This is the problem: The developers of the API use the name of for example a tournament or fixture or sport to do the lookup, I pass the name of a tournament for example:
www.example.com/sport/add_bet/{tournament_name}
The problem I have with this is that the tournament name as entered into the system by humans might have characters such as spaces, forward slashes, etc in the name.
As you can imagine using a forward slash in the url will completely break the system, since we use them to call different controllers, actions and to pass variables.
I am trying to get them to change to using a simple primary key id field, to perform the lookup of the data. For some reason these developers don't want to do this.
The project manager that manages this project (not a programmer and no experience of programming) had a chat to them about this issue, but still they don't want to change, and they told her that it is a matter of personal preference on which way to go.
As far as I know ID's have always been the way to do it.
Could you guys/girls please help me argue my point by giving some reasons as to why I am correct or incorrect in your view. I would like to provide your answers as motivation to get them to change over to doing it the right way.
Your help/answers/suggestions would be much appreciated.
The most important thing is the id will be unique as it is should be the primary key. so searching by ids will return unique results.
But the multiple record may have save title if you didn't validate them at the time of saving.
And also if you want some joins or something like that the id would help it.
And the should never trust the user and expect them to work as you wanted.
There is two sides:
1) You allow select single Title from dropdown and send to server only ID. Look-up by ID is way faster (assuming you are using ID as primary key). But if you have lots of Titles than you have to list all of them and user will be forced to scroll till find that Title.
2) You have simple input field to allow search only by part of Title. That way you don't have to list all Titles. As programmer, you have to escape all user input, that goes to server (via GET or POST), so that user can input even DELETE FROM user WHERE 1 to your input field and your system will sill works fine. Also, by inputting only part of Title allow to show multiple results, while using IDs is impossible.
I prefer second approach.
To make the look up fast, you need to place an index on the column by which you are looking up records. Primary key column always has an index. In order to use some other column you need to add an unique index, to avoid duplicates and make the search faster, which in turn makes the table larger. If you expect the table to grow (which is not too unlikely if you follow many sports and many leagues/tournaments over a number of years), it might become a problem at some point, depending on the resources in your production environment. It's not the strongest argument you can present, but it is not a bad argument either
Designing a fairly complicated site with a lot of ajax running on a single page. I have reached the point where some user's need to have specific permission to do things and some need to be stopped from the action. I have set up user roles in my database and all is working fine, but I wonder if there is an easier/safer method for me to store each permission.
Currently, when a user logs in their specific permissions are grabbed from the db and loaded into a session array. To check if the user has permission, I simply check to see if the permission is contained in the array. This seems sluggish, and almost like I am missing a better solution.
Also, sessions can apparently be edited by the user... is there a safer method?
I have thought running a query for each check, but that could greatly increase the load time for a simple ajax request.
I am open to any and all ideas. Thanks.
First and foremost, the user cannot edit Session variables. The only thing that is saved on the user's machine is a Session ID. That ID is then used by the server to grab key/value pairs that are stored ONLY on the server. From a client's standpoint, it is impossible to change values on a whim.
Second, I would not worry too heavily on a database connection. Avoid repeating yourself, but don't worry too much about the first connection.
Finally, my favorite way to do multiple permissions without creating roles is to use binary math. Some people like this, some people don't, but I find it useful.
To use this method, imaging that we define the following values:
CAN_EDIT_SOMETHING = 1 // Powers of 2
CAN_SEE_SOMETHING_ELSE = 2
CAN_DO_ADMIN_STUFF = 4
... = 8
To give people multiple permissions, use binary OR
PERMISSIONS = CAN_EDIT_SOMETHING | CAN_DO_ADMIN_STUFF
To illustrate how this works, we can look at the bits:
0b0001
OR 0b0100
---------
0b0101
To check if someone has a permission, use binary AND
if( PERMISSIONS & CAN_EDIT_SOMETHING != 0 ) {
}
To see how this works, we look at the bits again
0b0101
AND 0b0001
----------
0b0001 // Not equal to 0. They must have that permission!
The final benefit of this method is that it allows you to combine multiple permissions easily into "meta-permissions"
// If both EDIT_SOMETHING and ADMIN_STUFF are tasks that an admin
// can perform, we can combine them easily
//
IS_FULL_ADMIN = CAN_EDIT_SOMETHING | CAN_DO_ADMIN_STUFF
// We can then use this value exactly as we do any other permission
//
PERMISSIONS = IS_FULL_ADMIN | CAN_SEE_SOMETHING ELSE
Use it if you want, but it is a nice trick to have in your arsenal.
Seems OK to me! You could look at some software to enhance your session chache peformance.
Querying the DB every time is not as bad as it sounds! Firstly you probably need to connect to the DB anyway, secondly if you queried the users permisions when they signed in then the chances are that all the relevent rows are sitting in the buffer and no IO is required, thirdly a query for a single permision for a single user is going to be a lot lighter than a query for all permisions for a user.
Your explanation of the model seems a bit confused. Permission is the product of the subject authorization and the object authorization. Do you really store these products for every combination of subject and object? That's a very inefficient solution and very hard to manage.
Also, sessions can apparently be edited by the user
WTF?????!!!!
Session data should only ever be changed by the methods you define in your code - if users are able to modify any part of the session data in any way they like then this is the first problem you need to address - until you do, it will be virtually impossible to rely on any part of your authentication/authorization method unless you move authentication completely out of the domain of your application code (BTW: this is not the right way to fix the problem).
Certainly searching a very large array (not sure of the actual breakpoint - but in the region of n=1000 - but there are lots of variables affecting this) can be significantly slower than fetching the results from a database.
Its hard to say what you're doing wrong without understanding how your current system works. Is it one of these?