I'm writing a web app in PHP (using Codeigniter). I'm just wanting some security advice here. I have a task controller with a delete method. The link to delete the task is then http://localhost/task/delete/12345
So I'm wondering how to handle the fact that people have the ability to modify the link, thus deleting another task (probably not their own).
So my options I guess are to always do a check that the user owns that particular task before deleting it, or some sort of ID hashing?
Does anyone have any suggestions?
So my options I guess are to always do a check that the user owns that particular task before deleting it
that is the usual, and best, approach, yes. Hashing the ID is too insecure for many use cases: The link containing the hash is stored in the browser's history, might get E-Mailed around, be present in REFERER headers for outgoing links....
Either check ownership, or use a full-blown Access Control List, depending on how complex the permissions are.
Yes, check whether the user is allowed to delete that task and respond with an
HTTP/1.1 403 Forbidden if he isn't. Also, make destructive actions like deleting records POST requests. Otherwise watch Google (or some other fetcher-type client) happily triggering all your delete actions.
It is not recommended to update/delete your data via an http get request. Use post instead.
So my options I guess are to always do
a check that the user owns that
particular task before deleting it
Yup, that's it. There's no point in hashing an id, as if some user guesses another hash id he might delete a task from another user (that would be security through obscurity, and it's not a great security method). So, yes, chech that the task belongs to the user before deleting it.
Also, it isn't clear from your question, but to delete something, the user should go to blablah.com/tasks/delete/1234, and then confirm to delete the task via POST (submitting a form by clicking a button probably).
You can use session to store the item's id to delete and then on the delete page you check that the id given is equal to the session stored id.
Hope it helps you
Related
I am wondering about the security of my application. I'm simply using twig loop to display all of my records in database. And everything is all right when I make separate site to display the details and there are buttons to e.g. delete this thing. It usually happens DELETE method and somebody can display only own details. But I want to have button to delete specific record in basic view where every records displayed e.g. next to title of item.
I cant do this by CreateFormBuilder because I cannot send the current id of the item from the form (or I just don't know how to do it). But is it secure? Everyone can change the id parameter of button and delete other record.
I can use AJAX and simply button in twig but this is the same case. Everyone can change e.g. data-id parameter in button and delete other record.
What I should to do in this situation? How you usually solve this problem?
Summarising I want to make a secure button to delete item next to each displayed record.
Have a nice day!
One of the way to secure AJAX routes is to use JWT (json-Web-Token) (see this : https://jwt.io/) instead of random string token. This token is crypted with the user's information to ensure the person who clicked on the button is allowed to do someting (and the token is send with the request in header of the request).
Anyway, you have to send something to identify the id of the element you want to erase or modify in your database. I would personnaly implement this JWT system, but the access to the page where you can see and click on these buttons must be protected too. This way, you can assume that the users don't have bad intentions.
Theis bundle (https://github.com/lexik/LexikJWTAuthenticationBundle/blob/master/Resources/doc/index.md#getting-started) can help you to implement this on symfony very easily (i'm new to this framework and i did this in a few hours - just a thing: if you use Apache, don't forget to allow override in your Apache configurations to allow the .htaccess of symfony to do his job, or headers will be strip by Apache - it makes me several hours to find why things did not work !).
Hope this will help !
It really boils down to what kind of app you want to build:
more traditional app - with full page refresh/navigation cycle
AJAX based - with all sorts of async calls to your server
In any case you choose, it is your responsibility to check whether the current user is authorized to make any change (deletion included) to an object. This comes as especially important in case of id being integer, which is predictable.
So, first, make sure your routes are protected from anonymous users, and second, make sure that you put in place permission strategy which allows/denies user's specific action.
Most of the permission-related stuff can be achived via Voters, but if you are really in need of heavy-lifting you can turn to ACL.
Hope this helps...
I am seeking a best practice advice for implementing delete confirmation forms.
The following page, among other options, contains delete button...
/website/features/f/123
...when clicked a simple form gets loaded under following url:
/website/features/f/delete/123
A user has to confirm deletion in a simple delete confirmation form. Delete button gets enabled after the 'check to confirm' checkbox is checked.
All good and clear, however I am concerned that providing direct URLs to delete options may lead to... say, situations that could be avoided.
Is there a better way of handling this scenario? Perhaps referer validation?
The most common "situations that could be avoided" are:
Bots following links (e.g. to precache results). Avoid this problem by ensuring that the URL requires a request to use an HTTP method that is not safe such as POST and not GET.
CSRF attacks as covered by this other question
Actually deleting something should required the user to be logged in to the site and you should check that this user has the necessary permission to actually delete something. If your use case permit that something can be delete publicly, then it doesn't really matters if the confirm is checked or not (think trolls). If your user has the permission to delete something, then there shouldn't be any problem except if mistype something in the URL.
To avoid this you can also implement the DELETE http request (think REST). A combination of permission and DELETE should be enough to avoid bypassing the confirm dialog.
Another solution could be to implement validation token. The confirm dialog generate a secret token that needs to be validated by the delete action.
I implemented my initial referer idea. But as always I am open for suggestions and constructive criticism.
if(empty($_SERVER['HTTP_REFERER'])) $this->_app->redirect('/website/features', 302);
Note that this is a slim based redirect.
Just wondering if people think it is safe for a website to use a html link to allow users to mark their documents for deletion from their secure account page?
I have a website where users can create documents once they have registered and logged in to the website. To delete a document I include links on their account page for each document to be marked for deletion as follows :
http://www.examplewebsitename.com/delete_document.php?docid=5
The delete_document script makes sure the docid parameter is numeric, then checks using a session variable of their user id set when they logged in, wether this person actually created this document by looking up the user id of the creator of the document. If they where the creator, then it marks the document for deletion, otherwise if the current logged in person wasnt the creator then it doesnt mark the document for deletion and returns an error page.
Do you think this is a valid and safe way to mark documents for deletion, or should I be using a form and Post to do this more securely?
Three main concerns I can think of about using GET as a delete operation for your app.
Semantic reason, GET, according to http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html, should be an idempotent method
the side-effects of N > 0 identical requests is the same as for a single request.
More prone to CSRF, someone could post a link to http://www.examplewebsitename.com/delete_document.php?docid=5 and wrap the link into a harmless looking anchor
Click here for free puppy!
If by any chance the user is logged in and clicked on that link on his trusted website, it would inadvertently get the user to delete the document.
Browser addon / plugin that crawls web pages and cache links might accidentally crawl the link, opens it and again, delete the document without your user knowing.
Generally I advice against using GET requests to manipulate data because that's not what GET is designed to do if you stick to the HTTP Spec. If you would go completely restful you should be using a DELETE request but in most cases i use a confirmation page with a form that performs a POST request to delete the record.
Read Why should you delete using an HTTP POST or DELETE, rather than GET? for the reasoning behind this. It's been asked before in some other contexts.
The main reason is because GET is meant to be a safe method that is used for retrieval only:
In particular, the convention has been established that the GET and
HEAD methods SHOULD NOT have the significance of taking an action
other than retrieval. These methods ought to be considered "safe".
This allows user agents to represent other methods, such as POST, PUT
and DELETE, in a special way, so that the user is made aware of the
fact that a possibly unsafe action is being requested.
User agents expect this method to have no side-effects:
Naturally, it is not possible to ensure that the server does not
generate side-effects as a result of performing a GET request; in
fact, some dynamic resources consider that a feature. The important
distinction here is that the user did not request the side-effects,
so therefore cannot be held accountable for them.
This means GET should no cause any server-side state change.
Another reason, but rather a minor one, is that GET is easier to exploit that POST as there are more ways to trigger GET request than to trigger POST request. But no matter which method, both are vulnerable to CSRF attacks.
So if you make sure you’re protected against CSRF, you could even use GET for state changing requests.
I want to allow users as well as me(the admin) to delete data in mysql.
I used to have remove.php that would get $_GETs from whatever that needed to be deleted such as... remove.php?action=post&posting_id=2. But I learned that anyone can simply abuse it and delete all my data.
So what's the safest way for users and me to delete information without getting all crazy and hard? I am only a beginner :)
I'm not sure if I can use POSTs because there is no forms and the data isn't changing.
Is sessions good? Or would there be too many with postings, user information, comments, etc.
Ex: James wants to delete one of his postings(it is posting_id=5). So he clicks the remove link and that takes him to remove.php?action=post&posting_id=5.
EDIT: Alright, so now I am a little confused. While I can't be 100% secure, how do I do this with $_POSTs?
SOO I should use GETs to get all the data to remove.php, THEN have a confirmation submit button and when users click on it, it put all the data into POSTs and delete from the dbc?
Deleting records is a kind of a scary practice. If you or someone makes a mistake there's no real recourse to resolve the issue. Expunged records are very hard to resurrect.
Instead of deleting records, you could add an "active" bit (e.g. Boolean) column that is toggled off when users "delete" records. Essentially your users would be suspending records by toggling them off and the records would be saved in case mistakes or abuse but appear "deleted" to the user. To make this work with your other queries, just add a where clause of active = 1.
You could then have a utility script that's run at some specific date interval that would clean out deprecated, past dated records. You'd also need some type of timestamp for this type of maintenance.
Just a thought. Take if for what it's worth.
I'll echo gurun8 in preferring to 'mark' records as deleted, instead of actually removing data. And then obviously, you'll need to check that the authenticated user has permission to delete the post.
However, it seems very important to mention that $_GET is not safe even with authentication because of cross-site request forgery.
Imagine if Amazon adding things to your cart based on a GET request. All I'd have to do is put an image on my page with that URL, and everyone who visited that page and logged into Amazon will have products added automatically.
To match your example, I don't like Jame's post, so i put an image on my site like this:
<img src='http://example.com/remove.php?action=post&posting_id=5'>
And I send him a link to my page, and ask him to check it out, hoping that at the time he's logged in to your site. Because, of course, he clicked that little 'keep me logged in' button.
So you are right to be concerned about using GET. If you don't want to litter pages with forms, then confirm the action by POST.
Well you have to start by authenticating the users with a login script.
If you want the simplest solution possible, then I'd suggest protecting the directory in which you have remove.php with a simple .htaccess username and password.
If different users have different rights for deleting database entries, then you probably should create a PHP login script and use PHP session.
Bonk me if I'm stupid, but I searched for quite some time for a simple PHP login tutorial that could be placed on a real site (doesn't use session_register(), uses mysql_real_escape_string(), htmlspecialchars() etc) and I simply couldn't find one!
Probably this one comes the closest, you just have to replace session_register() variables with $_SESSION ones for it to work without register_globals (default in PHP5).
I have the following code snippet to delete records from a database given a primary key. This is called via an AJAX request, through GET. Anyone who were to examine my JavaScript could work out the URL and delete arbitrary records. What can I do to prevent this?
Not use GET?
Use sessions?
if($cmd=="deleterec") {
$deleteQuery = "DELETE FROM AUCTIONS1 WHERE ARTICLE_NO = ?";
if ($delRecord = $con->prepare($deleteQuery)) {
$delRecord->bind_param("s", $pk);
$delRecord->execute();
$delRecord->close();
echo "true";
} else {
echo "false";
}
}
Not using GET won't change a thing. You have to use sessions to manage 'access control' before you even get to this point in the code.
That is to say, when the AJAX request is made you should at that point confirm via the session that the person making the request is allowed to do the delete, before actually doing it.
Think about how you would check permissions in a 'non-AJAX' way and do the same here.
You can give your records a non-sequential random unique id to use in AJAX requests.
Still not the most secure solution although should be easy to integrate into your current system.
Use post rather than get
Embed hidden unique ids in any forms that will perform this action, and check that the id that comes back has been issued by you
Obfuscate the URL/parameter names
Generate unique IDs for the rows, and dont expose them externally, so an attacker cannot pick a row to delete.
Well, if not everyone can delete a record, make sure this one is behind a password, so only the authorized users can do deletes. Make yourself a login that adds a 'Delete' button on the page afterwards and on the PHP side make sure the user is authorized when processing the commands.
Oh and yes, make sure you always pass a confirmation value through POST to validate, not just a GET parameter, it's best practice, even with authorized users.
There are two important aspect to your question.
Are authorized user supposed to be able to delete any record they see fit? If that's the case your issue is one of making sure the request came from an authorized user. In that case using PHP's session is one way of making sure that it's the user you authenticated that made the request. Of course, with all technologies you have to make sure you use PHP session the right way. There are a bunch of articles on that mather. PHPsec.org has one here.
If a user cannot delete any row, in addition to doing authentication and sessions you'll also need to had a check in your code for the verify if the record being deleted can be deleted by that user. Now this is highly dependant on your application. For example, in a project management software, one could be allowed to delete tasks associated with one project but not with another one. That's part of your business logic.
The best would be to perform both check. One, your application must verify if the user making the deletion is a valid user and is allowed to delete (very simple to implement with php sessions) and two make sure that the user can delete the specific record based on some form of ownership.
Don't expose CRUD methods via Ajax.
You have to check before deleting records if user is authorized and allowed to delete.