Perl-Critic-Policy-Security-RandBytesFromHash

 view release on metacpan or  search on metacpan

lib/Perl/Critic/Policy/Security/RandBytesFromHash.pm  view on Meta::CPAN

package Perl::Critic::Policy::Security::RandBytesFromHash;

# ABSTRACT: flag common anti-patterns for generating random bytes

use v5.24;
use warnings;

use parent 'Perl::Critic::Policy';

use List::Util qw( any );
use Perl::Critic::Utils qw( :severities :classification :ppi );
use PPI 1.281; # signatures support
use Readonly 2.01;
use Ref::Util qw( is_plain_arrayref );

# RECOMMEND PREREQ: Ref::Util::XS

our $VERSION = 'v0.1.3';

Readonly my $DESC => 'random bytes generated using a hash';
Readonly my $EXPL => 'A hash seeded with poor sources of entropy is still a poor source of entropy, use system entropy instead.';

use experimental qw( signatures );

sub supported_parameters { () }

sub default_severity { $SEVERITY_HIGH }

sub default_themes { return qw( security cpansec ) }

sub applies_to { 'PPI::Token::Word' }

Readonly my $DIGEST_REGEX => qr/\A (
        ( \w+:: )*
        ( md[2456] | sha( 1 | 224 | 256 ) | digest_data | (hex|b64)?digest(_hash)? | join )
        ( _ ( hex | b64u? | base64 | sum | bytes ) )?
        ) \z/anx;

sub violates ( $self, $elem, $ ) {

    if ( $elem =~ $DIGEST_REGEX && ( is_function_call($elem) || is_method_call($elem) ) )
    {

        my @args = parse_arg_list($elem);

        if ( $self->_is_bad_seed_source( \@args ) ) {
            return $self->violation( $DESC, $EXPL, $elem );
        }

    }

    return ();
}

sub _is_bad_seed_source( $self, $elem ) {

    if ( is_plain_arrayref($elem) ) {
        return any { $self->_is_bad_seed_source($_) } $elem->@*;
    }

    return 0 if $elem->isa("PPI::Token::Whitespace");

    return 1
      if $elem =~ /\A ( (CORE::)?rand | (Time::HiRes::)? (time|gettimeofday|localtime|gmtime|clock_gettime) | refaddr ) \z/anx
      && ( is_perl_builtin_with_optional_argument($elem)
        || is_function_call($elem) );

    return 1 if $elem eq '$$' && is_perl_global($elem);

    return 1 if $elem =~ /\A \$ (PID|PROCESS_ID) \z/anx && $elem->isa("PPI::Token::Symbol");

    if ( $elem->isa("PPI::Structure") ) {
        return any { $self->_is_bad_seed_source($_) } $elem->children
    }
    elsif ( $elem->isa("PPI::Statement") ) {
        return any { $self->_is_bad_seed_source($_) } $elem->children



( run in 2.385 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )