perl-modperl mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From André Warnier (tomcat)>
Subject Re: random token re-used in subsequent requests
Date Mon, 16 May 2016 17:15:14 GMT
On 16.05.2016 16:38, Vincent Veyron wrote:
> Hi,
> I use the code shown here :
> in a mod_perl handler.
> At line 57, $args->{_token_id} ||= ... generates a random token that is used to uniquely
identify the request (users may reload the URL in two different windows), and added to the
request's arguments.
> Out of five different servers, the code works fine on four machines, and a different
token is generated every time the page is loaded or re-loaded. On one server however, a previous
token is being re-used. The servers are not identical, but all run the same up-to-date Debian
Jessie, using the same distribution packages of Apache and mod_perl
> Below is what is printed in the error log of the faulty system by Data::Dumper; as you
can see, on the third iteration, the first token is reused.
> Before : $VAR1 = {
>            'id_entry' => '16007',
>            'mois' => 0,
>            'open_journal' => 'Fournisseurs'
>          };
> After : $VAR1 = {
>            '_token_id' => 'Gh63Y2J9YYaNuReIsI8JAEj9oCY39oiy', <-------------------------------------
token 1
>            'id_entry' => '16007',
>            'mois' => 0,
>            'open_journal' => 'Fournisseurs'
>          };
> Before : $VAR1 = {
>            'id_entry' => '16007',
>            'open_journal' => 'Fournisseurs',
>            'mois' => 0
>          };
> After : $VAR1 = {
>            'open_journal' => 'Fournisseurs',
>            'mois' => 0,
>            'id_entry' => '16007',
>            '_token_id' => 'EHL2mm1LvmFIgPeYEFYO8dKt71lWiwkP' <-------------------------------------
token 2
>          };
> Before : $VAR1 = {
>            'mois' => 0,
>            'open_journal' => 'Fournisseurs',
>            'id_entry' => '16257'
>          };
> After : $VAR1 = {
>            'open_journal' => 'Fournisseurs',
>            'mois' => 0,
>            'id_entry' => '16257',
>            '_token_id' => 'Gh63Y2J9YYaNuReIsI8JAEj9oCY39oiy' <-------------------------------------
token 1 again
>          };
> What can I do to find the cause of this misbehaviour?


I have not really analysed the instruction by which you create the token, to check if 
there was not some flaw there which would lead to generate a less-than-random token.
But I have a suspicion and a theory nevertheless :

1) What is the Apache MPM used on the 5 machines (prefork, worker, etc.) ?
You can find out by entering "apache2ctl -l" on each machine.

2) the rand() function, when called repeatedly, provides a *pseudo*-random series of 
return values.
Example : run this little program, *repeatedly*, on any one of the servers :

# : simple test for rand()
use strict;
use warnings;
for my $it (1..10) {
print "it # $it : " . sprintf("%05d",int(rand(99999))) . "\n";

3) what does this show ?
That when you start with the same "seed" (srand(12345)), even in totally independent 
processes running one after the other, you obtain exactly the same sequence of 
pseudo-random numbers when you then call rand() repeatedly.

4) you are running Apache + mod_perl. If this is a "prefork" configuration, it means that

there will be a "main Apache process" (which actually receives the browser requests) , and

a number of Apache "children" started in parallel, each with its own persistent perl 
interpreter. When a request comes into the main Apache, it looks in some table, to find a

"child" process which isn't currently doing anything, and if found, it passes the request

to that one for processing.
This is largely unpredictable : depending on how many requests come in over a period of 
time, and the number of started Apache children processes, and the time it takes to 
process one request, one or the other child process can be free or not, to handle the 
latest request.
It is thus possible that the same child process will handle a series of requests in a row,

or that each child will be called in turn, or whatever combination.
(And also, according to how I understand your application, Apache will receive a 
succession of requests, some with already a token, and some not.  So rand() will be called

or not in any child, depending on how requests exactly come in.

5) now look at the description of rand() and srand() here :

It says that the first time rand() is called by any process, if srand() has not been 
called before, it is called automatically wihout argument, to return some seed for the 
first rand() call.
I do not know exactly what srand() returns in such a case, but if it happened in each of 
these "Apache children processes + perl", to return initially the same seed, then each of

these Apache processes, subsequently, would return the same series of successive "random"

numbers when rand() is called.

So now put all of that together, and I believe that it is almost guaranteed that you will

regularly get the same keys, on all your servers, not just the one you cite as different.

Also, if I may say so, the function that you are using to generate your "random" unique 
session-id :

join "", map +(0..9,"a".."z","A".."Z")[rand(10+26*2)], 1..32 ;

looks at first sight to me like quite inefficient and probably likely to generate the same

string regularly, even if it does not look that way.
(The only variable there is rand(), and it can only return values between 0 and 62).
I haven't done the math, but it just looks like an awful lot of function calls, int/string

conversions, array contruction and retrievals etc., to get a 32-char string that is 
finally not so random.
Would it not be better to call rand() only a few times, with a much larger argument, so 
that it returns a much wider range of values, and then map these values to letters for 
example using a hex sprintf, and then concatenate these hex strings ?
(Or better, use one of the CPAN modules specially designed to do similar things, 
efficiently and really randomly)

View raw message