Skip to content

Use Crypt::SysRandom to generate session ids #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

robrwo
Copy link
Contributor

@robrwo robrwo commented Jun 25, 2025

This replaces convoluted code for generating session ids with a simple call to retrieve random bytes from the system source of randomness.

Besides simplifying the code, this also improves security by using high quality randomness to generate a sessionid rather than a hash of a lot of data, much of which is predictable.

It uses Crypt::SysRandom, which is a lighter-weight alternative to Crypt::URandom, though either is fine.

@robrwo robrwo force-pushed the rrwo/improve-sessionid-generation branch from 7b8c9ab to 6a259ce Compare June 25, 2025 17:52
@robrwo
Copy link
Contributor Author

robrwo commented Jun 26, 2025

Perhaps instead this should just use UUID to generate identifiers?

@jjn1056
Copy link
Member

jjn1056 commented Jun 26, 2025

I think we need to be careful to change the dependencies of this 20+ year old module that is used in nearly every Catalyst application I've consulted on.

I think the main thing we are trying to say here is the old code could be a security problem. If that is completely true, like there are known exploits, that's good reason to change.

Crypt::SysRandom seems to have a pretty ok compatibility profile, but it's also fairly new. I don't personally know enough about this security topic to be sure it's an actual improvement.

I'd not be excited to change this unless we are sure of all the above.

As a total aside, I've never been happy with the design of the session plugin as it gloms too much into the application class directly. If the existing one is problematic, could be a good excuse to rethink.

@robrwo
Copy link
Contributor Author

robrwo commented Jun 26, 2025

I think we need to be careful to change the dependencies of this 20+ year old module that is used in nearly every Catalyst application I've consulted on.

In your consulting, have you ever run across users that this change might break?

I imagine most customisations would be to use some variant of /dev/random for the seed or generated id anyway.

I think the main thing we are trying to say here is the old code could be a security problem. If that is completely true, like there are known exploits, that's good reason to change.

This is a potential security problem. Session ids are often used to grant access to resources. (Note that securing sessions from cookie stealing attacks or forgery is another issue.)

What seemed secure in 2005 is now practical to attack with today's hardware. Digest algorithms like MD5 and SHA are from the early 1990s and not considered secure, and there are data used to seed the hash is not very secret.

Crypt::SysRandom seems to have a pretty ok compatibility profile, but it's also fairly new. I don't personally know enough about this security topic to be sure it's an actual improvement.

The "standard" is Crypt::URandom. That's been around for a long time. But I think Crypt::SysRandom is lighter weight, with XS handled as a separate module that users can install. We can use either though.

Unless someone is running Catalyst on a very old system without /dev/urandom (before mid-1990s), I don't see it as being a problem.

One alternative is to

  • modify the session_hash_seed method to return data from one of the randomness modules,
  • add an option to use the session_hash_seed as the id, and
  • modify the generator to check the option, and use the hash seed if true, otherwise default to use a simple hash of the random data (I think in this case MD5 is good enough, and it's already used by Object::Signature anyway, but we can also make the hash configurable.

If users are customising the session_hash_seed, then it should work.

If they are customising the generate_id to use session_hash_seed, then again it should work.

Otherwise they can update their config to just use the random data from the seed.

As a total aside, I've never been happy with the design of the session plugin as it gloms too much into the application class directly. If the existing one is problematic, could be a good excuse to rethink.

I remember being told in 2013 when I was submitting patches to improve this that it was "deprecated" and that I should consider moving to "Plack::Middleware::Session". I have been tempted to write a wrapper that just uses the Plack middleware.

@robrwo
Copy link
Contributor Author

robrwo commented Jun 26, 2025

I have made some changes in d10be86 that I think will be safer for backwards compatability:

  • session_hash_seed returns data from the random device
  • generate_session_id will return a SHA-1 hash of that data, unless configured to return the raw data as a hex string
  • the hash digest algorithm can be configured
  • the size of the hash data can be configured

@robrwo robrwo requested review from haarg and jjn1056 June 26, 2025 17:40
@robrwo
Copy link
Contributor Author

robrwo commented Jul 2, 2025

It might be worth updating the documentation to say that the session_hash_seed method is deprecated and that a future release may not use it at all.

@haarg
Copy link
Member

haarg commented Jul 15, 2025

I personally think this is over-complicating things. I think an adequate solution would be:

sub generate_session_id {
    return unpack( "H*", Crypt::SysRandom::random_bytes(20) );
}

sub session_hash_seed {
    Crypt::SysRandom::random_bytes( 20 )
}

This provides proper random session IDs of the same form (length, characters) they would have had previously, provides a proper hash seed for any subclass trying to use session_hash_seed, and keeps things properly simple.

I can't imagine anyone overriding session_hash_seed to do anything other than provide proper entropy. And if that is the case, there is no need to continue calling it. I suppose we'd want to document that it is no longer used. Using a digest rather than the raw random data should be indistinguishable to a user, so it just seems a waste.

Crypt::SysRandom is definitely an appropriate module to use. It is simple and straightforward in its design and goals, and written by a reputable author.

robrwo added a commit to robrwo/perl-Catalyst-Plugin-Session that referenced this pull request Jul 16, 2025
robrwo added a commit to robrwo/perl-Catalyst-Plugin-Session that referenced this pull request Jul 16, 2025
@robrwo robrwo force-pushed the rrwo/improve-sessionid-generation branch from 076a61e to 8d2df31 Compare July 16, 2025 07:56
This replaces convoluted code for generating session ids with a simple
call to retrieve random bytes from the system source of randomness.
@robrwo robrwo force-pushed the rrwo/improve-sessionid-generation branch from 8d2df31 to c0e2b4a Compare July 16, 2025 08:57
@haarg haarg merged commit 636943c into perl-catalyst:master Jul 16, 2025
@robrwo robrwo deleted the rrwo/improve-sessionid-generation branch July 16, 2025 09:58
collision. It basically takes C<session_hash_seed> and hashes it using SHA-1,
MD5 or SHA-256, depending on the availability of these modules.
This method will return a string that can be used as a session ID. It
is simply a hexidecimal string of raw bytes from the system entropy
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is 'hexidecimal' a typo which should read 'hexadecimal'?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy