perl-modperl mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From André Warnier ...@ice-sa.com>
Subject Re: random token re-used in subsequent requests
Date Mon, 16 May 2016 20:26:51 GMT
On 16.05.2016 20:03, Bruce  Johnson wrote:
>
>> On May 16, 2016, at 10:15 AM, André Warnier (tomcat) <aw@ice-sa.com> wrote:
>>
>>
>> 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).
>
> The  function is meant to map a random element from the 62-element-long  array (0..9,"a".."z","A".."Z”)
(hence a rand() call to generate a number from 0 and 62), 32 times, and join them into a string.
>
> Although I think that should really be rand(9+26*2) to properly generate array indices
for the entire array and no more. With a number between 0 and 62 (63 numbers) and a 62-element
array, you’ll be retrieving nulls from the array 1/62 calls,  but all that means is that
the string is one char shorter for each time '62’ comes up...
>
> So long as rand is properly seeded, you should not get repeats, at least not frequently
enough to ever notice, I’d think.
>
> This is textbook Perl, as in I’m pretty sure it’s out of one of Larry Wall’s books;
I use it to generate random strings for cookies.
>

Maybe the textbook example was meant to show the power of the syntax, but not necessarily

the efficiency of it.
I interpret this as doing the following (if we ignore any optimisation which the perl 
compiler may make by itself) :

quote perldoc
map EXPR,LIST

Evaluates the BLOCK or EXPR for each element of LIST (locally setting $_ to each element)

and returns the list value composed of the results of each such evaluation. In scalar 
context, returns the total number of elements so generated. Evaluates BLOCK or EXPR in 
list context, so each element of LIST may produce zero, one, or more elements in the 
returned value.
unquote

LIST in this case is 1..32 = 32 elements.
EXPR is (0..9,"a".."z","A".."Z") which is another list (say LIST-2), of 62 elements.
Thus, we are 32 times evaluating (building) a list LIST-2 of 62 elements.
(Always the same one, but does perl know this and optimise it away ?)
Out of which LIST-2 then (at each of the 32 iterations) we extract just 1 "random" 
element, by virtue of the [rand(62)] index into the list LIST-2.
I am not sure immediately of the effect of the leading +(LIST-2), but it may have the 
effect of forcing some internal conversion of the elements of (LIST-2).
At the end of the 32 iterations of
map +(0..9,"a".."z","A".."Z")[rand(10+26*2)], 1..32
we have an array of 32 single-character elements.
Which we then join into a 32-character string by means of the join().

I may be wrong, but at least intuitively, this does not seem to be an optimal way to 
obtain a 32-char long random key.

Mathematically, I think such a string provides for 62 ** 32 combinations, which is ..
2,0859248397665137523388883849312 e+93
according to my pocket calculator.
That may be more than the total number of atoms in the known Universe.
Which I have also intuitively a tendency to consider a bit excessive, for generating a 
simple time-limited session key for a webapp.

Note also that the fact that there are theoretically that many possible combinations, does

not mean that all of them are equally likely.
For that to be the case, rand() would have to return a series of really random responses,

which we know it doesn't.

> If it’s properly seeded in the original code, it should either work or not work on
all five servers. Not working on one out of the five makes me think maybe there’s some sort
of weird caching issue.
>

I agree, that the seed is the main issue.
The code should insure that for each server process (+ perl interpreter), srand() is 
called once, whence that process starts (or the first time the webapp is run), and with a

different seed for each process.
(A BEGIN block with a seed based on the time (hi-res) may be a solution.)

But the fact that it does not evidently work on one of the servers only, may be due to 
many factors, such as the rate at which already-keyed and not-already-keyed requests are 
hitting each server, their order, how many server processes there are to respond to the 
requests, and how long it takes to respond to one request.
So it may also be that "it does not work" on all servers, but that it has only been so far

noticed on the one.
If all server processes on one server happen to use the same seed, then it depends
on which server process handles the next unkeyed request. If it happens to be, for that 
server process, the n-th unkeyed request that it handles (and other server processes have

already handled more than n requests before), then the key generated by this server 
process will duplicate one which has already been issued before, no matter how many 
different keys are theoretically possible.
And whether this causes problems or not (or gets noticed), may only depend on whether the

session which previously used the same key, has already concluded or not.


Mime
View raw message