hide id passed in url

Asked

Viewed 444 times

0

is the following, in the application I am developing, I have a complaint form where the user does not need is logged in to fill it and make his due complaint, up to there everything right, so he sends the data is displayed to him a (page)view with the information he filled out. However, once this page(view) is displayed with the information, the registration id is displayed in the url, and this way I am calling a security problem.

for example: if user made a registration is displayed to him the view with the information he registered and the following url http://127.0.0.1:8000/controlNote/exibeInformacaDeNote? data=40

but if the user passes another id manually in the url is displayed to him the data of that other complaint http://127.0.0.1:8000/controlNote/exibeInformacaDeNote? data=41

Obs: I’m using the framework

has some way to avoid this situation?

This is the controller responsible for calling and validating the report form

   public function adiciona(){
    return view('AdminDenunciaView.adicionaDenuncia');
}
 public function adicionaAction(Request $request){ 
    $request->validate([
      'crime'=>['required','string'],
      'descricao'=>['required','string','min:10','max:200'],
    ]);
    $crime = $request->input('crime');
    $descricao = $request->input('descricao');
        
    $data = new Denuncia();
    $data-> crime = $crime;
    $data-> descricao = $descricao;
    $data-> save();
   return redirect()->route('exibeInformacaoDenuncia',['data'=>$data]);
}

This controller is responsible for calling the view with registered information

public function exibe(Request $id){
   $data = Denuncia::find($id);
   return view('AdminDenunciaView.exibeInformacaoDenuncia',['data'=>$data]);  
}

3 answers

5

No way to hide the ID in GET: /a/164252/3635 ... something else has no sense to want to hide the IDENTIFIER, it serves for this, identify, if your intention that people do not assume the number of items (in your case denounces) you can simply use in your Migration the UUID (version 4 with 2122) along with the method ->primary(), thus:

$table->uuid('id')->primary();

The problem with UUID is that there is a slight possibility of collision: /a/40528/3635

The problem with UUID is that every bank has a scheme to adjust this, examples:

  • Postgres will have to set the ID column to default value: uuid_generate_v4() (you will need to install the Postgis extension)
  • Postgres 13 I believe will have native, that is the function gen_random_uuid() (not tested yet)
  • Mysql will probably have to use default value as UUID_TO_BIN(UUID()) (assuming you use BINARY for the column type) and then BIN_TO_UUID(id) in select

I will not go into detail, I will just say that most people resolve the PHP side in the Laravel Model, to make few Inserts will not be problematic, but to insert thousands in the PHP side will be much slower, since it will have to process one by one, so I don’t really like it:

<?php
namespace App\Models;

class Exemplo extends \GoldSpecDigital\LaravelEloquentUUID\Database\Eloquent\Model
{
    //
}

The example was with the composer require goldspecdigital/laravel-eloquent-uuid:^7.0, But you can do it manually, which is kind of simple, but still doing it in Eloquent if you need to process a lot of things can take time (It is possible that as soon as I have time I will ask questions on how to solve for each most popular DBMS, if it is possible or advantageous of course)


Whether with UUID or ID, as "perfumery" instead of dequerystring you could change the route scheme instead of:

/controledenuncia/exibeInformacaoDenuncia?dados=41
/controledenuncia/exibeInformacaoDenuncia?dados=d7266915-f014-485c-a2dc-85a2b81d94cd

Would use:

/controledenuncia/exibeInformacaoDenuncia/41
/controledenuncia/exibeInformacaoDenuncia/d7266915-f014-485c-a2dc-85a2b81d94cd

And on the route you must name it:

Route::get('exibeInformacaoDenuncia/{dados}', [
   'as' => 'rotaDenuncia',
   'uses' => 'NomeDoController@exibe'
]);

And if you were to redirect it would be something like:

return redirect()->route('rotaDenuncia', [ $id ]);

Masking the ID

Instead of using UUID, which requires a lot of configuration depending on the DBMS, there are people who solve this in the Eloquent, which I personally think if you’re going to input too much data at the same time will be bad at performance, so a simple way to avoid assuming the amount would be enough to ADD and SUBTRACT the value of the ID, for example, in the .env apply something like:

MASK_ID=5000

After creating with Model pass the ID like this:

return redirect()->route('rotaDenuncia', [ $dados->id + env('MASK_ID') ]);

That way ID 41 will be adding up with 5000 and will display in the URL as:

/controledenuncia/exibeInformacaoDenuncia/5041

And when it’s time to read using find(), make the subtraction thus $id - env('MASK_ID') (assuming your namespace is more or less like this):

public function exibe(Request $request, $id)
{
   $data = Denuncia::find($id - env('MASK_ID'));
   return view('AdminDenunciaView.exibeInformacaoDenuncia', ['data'=>$data]);  
}
  • hello Guilherme, very obg by the feedback, when trying to practice your tips in the mode displays() I get the following error Object of class Illuminate Http Request could not be converted to number

  • @frdmarkes ah got it, it was my mistake, 1 min

  • @frdmarkes corrected in response, the correct is: public function exibe(Request $request, $id), sorry for the mistake.

  • Hello William, once again, thanks for trying to help me. I’m getting another answer, check it out: it’s as if he expects to be passed only 1 parameter: Too few Arguments to Function App Http Controllers Admindenunciacontroller Information::displays(), 1 passed and Exactly 2 expected

  • @frdmarkes you changed the route to Route::get('exibeInformacaoDenuncia/{dados}', ... ? Understand how route parameters work?

  • I gave +1 for the first alternative, the second seems to make no sense. If you are always adding and subtracting 5000 (in this case), then instead change /41 for /42 would trade /5041 for /5042 and would have the same result. No?

  • Thanks dear @Inkeliz, about MASK_ID, I will try to elucidate me based on a question... what is the goal usually of someone who uses UUID as Ids? Even though this in some Sgdbs has a worse performance than using INTEGERS.

  • @Guilhermenascimento I think there are several objectives, but the main (in this case) would be to prevent access to other content. That is, if there was a youtube.com/v/123 I could change to /124 and end up accessing a private video. This is a case similar to that of the OP. However, the sum and subtraction does not solve this problem, in my view. Since now you have /5041 and I can still change to /5042, they remain sequential and easily accessible. Even if multiplied, they would continue sequentially (create two denunciations and that’s it). Or, I’m sleepy and I’ve lost some information. haha

  • Dear @Inkeliz if numeric format had been a security breach for years it would have been abandoned, because if it is possible to access content that does not belong to you by changing the ID in the URL then the problem is not the format but the application ... actually the only problem that switching to UUID solves is to avoid people deducting the amount of items that exist from a type of information.

  • @Guilhermenascimento, the goal of the OP is precisely to hide the information and prevent others access the content, has no relation to quantity of item. He says: "but if the user manually passes another id in the url, the data of this other complaint will be displayed to him". I’m not talking about number format or not, but adding and subtracting as a way to prevent deducing other Ids does not solve the OP issue. The use of random Ids would prevent this (which is the same as the UUID order), at least it would have more work, mainly attached to a rate-limit, and other authentications (which the OP does not have).

  • @Inkeliz and therefore I said at the beginning of the question, it does not make sense, it is not necessary.... the only utility that exists in this is only will be to deduce values, for other objectives so it is only lack of understanding, ID has the goal to identify something, you gain nothing hidden.

Show 6 more comments

2

but if the user passes another id manually in the url is displayed to him the data of that other complaint

I think to prevent this would have to use non-sequential Ids (as mentioned by @Guilherme Nascimento), as long as you take into account the number of complaints that exist, after all the more denunciations there are the higher the chances of finding a valid ID.


I have no knowledge about Laravel, so I’m only using the native PHP features, which will probably have to be adapted to Laravel.


Another possibility would be to create a basic type of authentication that does not yet need other user information (let alone need to login).

This could be done with HMAC (or Ed25519, if you want public key signatures), in order to simplify I will use HMAC:

$id = 40;

// Via LibSodium (Blake2):
$hmac = sodium_crypto_generichash($id, $chave);

// Via PHP (SHA256):
$hmac = hash_hmac('sha256', $id, $chave);

This way, instead of the user accessing by:

?dados= $id 

He’ll have to have the "signature":

?dados= $id &assinatura= $hmac

So if he changes the id it will not have the corresponding valid signature, the user will be unable to create a assinatura valid without knowing the value of $chave. When showing the result, you should do something like:

if (!is_numeric($_GET['id'])) {
   return
}

if(!hash_equals(hash_hmac('sha256', $_GET['id'], $chave), $_GET['assinatura'])) {
    return
   // Assinatura é inválida;
}

To $chave could probably be replaced by env('HMAC_KEY_DENUNCIA'), similar to the one @Guilherme Nascimento mentioned.


The "performance impact" was not taken into consideration, the priority is exclusively to solve the problem of lack of authentication (without collecting additional information about the user, and without requiring login). In addition, general purpose hashes are made to be fast (main Blake2 and Blake3).

-3

Some of that kind of trouble bothered me, too. My alternative was to create tokens for users, which ended up being very useful and opened new features in the development. In my case I created another column (token) for the users, I want a random string with know there, 60 digits, I check if it is not in use and assign the value to the user, so you will not identify the user being ID=32 and yes as token=Fdsfs#4g%fsflfqe1oi...eufow50ok.

  • 1

    I think it’s funny that down people vote, to come to participate in the question comes 2, to negativar comes a handful... Helping colleagues is difficult, criticizing and discouraging those who try to help is easy, right. Nor to point out errors or show where the answer is wrong, turning everything into a constructive criticism serve, after all, pointing the finger (down) is much easier, practical and convenient than thinking and writing...

Browser other questions tagged

You are not signed in. Login or sign up in order to post.