Best and secure way to send parameters in URL

2019-03-31 23:15发布

问题:

I am working on a website in which there would be functionalities to update and delete data on the basis of id. Now the thing I am worried about is like my url would be

www.example.com/public/controller/action/1

if the action would be delete, any person can change id from 1 to 2 in url and the data with id 2 would get deleted. What would be the best way to keep the flow secure. I am using Zf2 and Doctrine2... Any suggestions please !!! And moreover I am keeping ids hidden in fields, anybody can use firebug to change the value in fields, is there any way to protect data from that too?

Would any encryption-decryption way would make it secure, like if anybody even edits the encrypted value, after decrypting it would not result in a required id? Which one would be good, I have never used encryption decryption.

回答1:

You should worry less about what happens when people change parameters within the URL or try to hack something into your HTML (hidden fields), as much more you should worry about what your users are actually allowed to do.

If an admin is allowed to delete all posts for example, then it doesn't matter if he changes domain.com/post/delete/1 into domain.com/post/delete/42. If admins are supposed to delete everything they can. So let them just change it as much as they want to.

If admins however are only allowed to gain administrative privileges to their own entries, then you need to work this into your Service-Layer. The Service-Layer would check for permissions of the current user against the currently requested object. My personal favorite would be ZfcRbac.

If however you want to make it more difficult for people to actually change IDs, then you should give every entry a unique hash. So for example the url would be domain.com/post/delete/12acd-4a7f7c6-4a7f7c6-12acd-4a7f7c6 or something like that.

TL/DR don't worry what happens when people change stuff within the URL/HTML, simply worry about Authentication and Permissions in general.



回答2:

You can change id to some_random_string (based on timestamp to make it unique) and search databese for that. There is no chance that user would guess that random string. And second check in controller that logged user have rights to CRUD actions.

You can use https://github.com/ZF-Commons/ZfcUser (with second module for Doctrine) to make auth and in controller you can check if user is logged

if ($this->zfcUserAuthentication()->hasIdentity()) {
    $user = $this->zfcUserAuthentication()->getIdentity();
    if($user->systemRole=='admin')//you can make switch for that
    {
      //can edit/delete/create
    }
}

To make this work you must copy UserEntity from that module and add systemRole. (check documentation for zfc-user for that)



回答3:

1- try to check authorization in action .
2- In some case you can save some data such as entity id in session on page load and then only call delete.
3- any encryption algorithm has one (or more) key . some important part of security management is key management . if you have implementation of an algorithm in PHP and Javascript then you should have key in both side for decryption (user can find your keys in client side code)
4- hash may help you . hash do,'t need to key and make your data unreadable but hacker can call your url with hash data
http://en.wikipedia.org/wiki/Cryptographic_hash_function

Update 1 :
for encryption you can use accessible data on server and client as key . for example use "url character count" as key
url character count : 10
id (plain data) : 23
id (encrypted and use for send to server ) 33 = 23 + 10
on server you should decrypt id (id = id - url character count)

important point : encryption algorithm should be extremely minified and obfuscate on client .



回答4:

The most secure way to send a url with data is over a secure connection with ssl (https). However, I don't think this is the question you are meaning to ask.

I think you are wanting to prevent certain people or groups of people (roles) from accessing certain resources. If this is the case, you need an access control list, and you should use the \Zend\Permissions\Acl component.

Edit:

The best way to encrypt data in PHP is to use a modern reversible-encryption functions like mcrypt_encrypt and mcrypt_decrypt.

However, this is simply obscuring the url, it does not fully protect you from someone simply making a robot to check all the delete urls available (given, there may be quite a few).

The only bulletproof way of protecting certain pages (resources) is to use some type of access control. Say for instance, you only want a particular user to be able to delete their own posts. You could have an action deleteMyPost. (I am presuming you have a user login to the site in order to perform actions, otherwise, all bets are off). When someone goes to www.mysite.com/public/controller/deleteMyPost/1, the action or the ACL will check if the id of 1 is a post of the logged in user. If not, the user will be redirected away from the page in some fashion, maybe with a header('Location: <url>') call.



回答5:

What you are asking about relates to ACL which ZendFramework has a perfectly working library for it. In ACL, you will first configure who can do what on which resource, and then later you will query it to see if some request by some user is permitted or not. Here are the parts of an ACL:

  • User
  • Action
  • Resource

For instance:

  • User: Mehran
  • Action: Delete
  • Resource: Any record of table T1

But in ZF Action and Resource are merge into one which is no big deal. In ZF you need to say Action_Resource instead. The thing I'm going to expand here is the types of resources you might face. In my opinion there are two:

  1. Static resources.
  2. Dynamic Resources.

Static resources are those that you can list (completely) while you are designing your software. e.g. you might have posts in your software, which you might want to grant the permission to some user to delete them. If you won't give some other user such permission, then he/she can not delete any of the posts. But if you do give it to someone, then he can delete any post he wants (assuming we are not including dynamic resources yet). In other words, static resources are types of dynamic resources.

Moreover, we have dynamic resources which do not exists until the software is deployed. In fact dynamic resources are created by end user. So they've got owners. You might want to grant the delete permission of dynamic resources to their owners only. Expanding the same example as before, any specific post could be a dynamic resource.

Before I come to conclusion, I would like to expand the types of actions in computer world (in general). Usually you can assume there are only four types of action:

  1. Create
  2. Modify
  3. Delete
  4. Read

If you want to check the permission for one of the actions above, only Create deals with static resources and the rest are talking about dynamic ones. That is, when you are creating a post there's no dynamic resource created yet so all you can do is to stick to static one instead. But in all the rest of action types, there's always a dynamic resource to include in your permission check.

Now putting the two types of resources side by side, you've got a decision to make. If a dynamic resource is available, should I check the permission with dynamic resource or its static (since all dynamic resources will always have a static one as their type)? The answer to this question is usually: both of them. Here's how:

  1. User can delete if: he has access to static and dynamic resource.
  2. User can delete if: he has access to static or dynamic resource.

In first scenario any user can delete his own resources if he's granted the permission. But no one else can ever do so. In the second case, any owner can delete his own resource regardless of any other permission granted or not. But you can also grant the deletion permission to some administrator who is not the owner. Usually the later case is preferred.

Having said all this, in your case you are talking about checking the access to some dynamic resource and you need to implement an ACL for it.



回答6:

$token = sha1("id=1&action=delete");

$url = "www.mysite.com/public/controller/action/delete/id/1/token/".$token;

on target page create token for passed parameters and cross check with url token. If it's matched then consider it as valid input (You may add timstamp to generate token for better security)



回答7:

I would simply advise using POST instead of GET.

When to use GET?

Information sent from a form with the GET method is visible to everyone (all variable names and values are displayed in the URL). GET also has limits on the amount of information to send. The limitation is about 2000 characters. However, because the variables are displayed in the URL, it is possible to bookmark the page. This can be useful in some cases.

GET may be used for sending non-sensitive data.

Note: GET should NEVER be used for sending passwords or other sensitive information!

When to use POST?

Information sent from a form with the POST method is invisible to others (all names/values are embedded within the body of the HTTP request) and has no limits on the amount of information to send.

Moreover POST supports advanced functionality such as support for multi-part binary input while uploading files to server.

However, because the variables are not displayed in the URL, it is not possible to bookmark the page.



回答8:

I propose a dynamic method:

The essence of this method is based on identifying a single use.

1 - You create a new unique identifier for each identifiers.
for example, for the identifier $id1 you can do:

$new_id1 = uniqid(sha1("$id1")). / / Just for example

And you put all these identifiers in an array:

array ($new_id1 => $ id1,
       $new_id2 => $ id2,
       .....
       / / I advise you to have a trace logger for in case of problems.

2 - You put this array in session (or cache) after delete if it already existed

3 - You create links with new identifier:

<A href = "/Controller/Action/". $new_id1 . "> link text </ a>

The user only has access to his page identifiers (and thus for which it has the rights) and will be hard (very very ... very hard :) ) pressed to find another identifier.

4 - When PHP retrieve the identifier $new_id1, it will fetch the array in session (or cache) to get the real identifier ($id1).

5 - Delete the array from the session (or cache) to do not be able to use (single use)

This method can be enhanced depending on your level of requirement.

  • You can use a form instead of a link.

    < a onclick="submit_form(" . $new_id1 . ")">Your text link < / a> ...

The submit_form() fill the hidden element with the good value You can add a Hash element for the protection from CSRF attacks.

  • If the identifier php side is not in the array, you can disconnect the person and possibly put on a black list

  • There are other possibility as dynamic routing. generating a url without controller and with the new id, and if this id is recognized, route it to the correct controller.

Good luck