Skip to content

Instantly share code, notes, and snippets.

@worthmine
Last active October 30, 2017 10:06
Show Gist options
  • Save worthmine/4a9a80b6d8a2149a0b33 to your computer and use it in GitHub Desktop.
Save worthmine/4a9a80b6d8a2149a0b33 to your computer and use it in GitHub Desktop.
既存のCGIスクリプトでより強固なパスワード認証を行う ref: http://qiita.com/worthmine/items/519fb4fd1d7f5117a255
#! /usr/local/bin/perl
use strict;
use warnings;
use lib "$ENV{DOCUMENT_ROOT}/lib/perl5"; # CPANモジュールを読み込む
use lib "$ENV{DOCUMENT_ROOT}/lib"; # 上位のモジュールを読み込む
use lib "./lib"; # ローカルなモジュールを読み込む
use CGI ':standard';
use Password;
my $encode = 'UTF-8';
my $title = "パスワード暗号化スクリプト";
my $passwd = 'Qiita';
print header(-charset=>$encode), start_html( -title => $title, -encoding => $encode, -lang => 'ja');
print h1($title);
print p("Perl version : $]");
print h2('パスワード'),"\n";
my ($password, $salt) = ($passwd, Password->nonce() );
my @t_verify = ( 'deny', 'allow' );
my $encrypt;
print "raw: " , $password ,br(),"\n";
print "salt: " , CGI::escapeHTML( $salt ), br(),"\n";
print "Password.pm: ", CGI::escapeHTML( $encrypt = Password->encrypt($password, $salt) ), br(),"\n";
print "verify: " , $t_verify[ verify Password($password, $encrypt) ],br(),br(),"\n";
my ($newpass, $newencrypt) = ( Password->generate(16) );
print "new: " , CGI::escapeHTML( join " ",$newpass, $newencrypt ), br(), "\n";
print "verify: " , $t_verify[ Password->verify($newpass, $newencrypt) ],br(),br(),"\n";
print end_html;
exit;
package Password;
use strict;
use warnings;
our $VERSION = '3.01';
use Carp;
use Crypt::PasswdMD5;
my @charset = ('A'..'Z', 'a'..'z', '0'..'9', '#', ',', qw# ! ? = + - * / _ [ ] { } ( ) < > | ~ ^ ' " % & . ; : $ #); # 強調表示の訂正用→'
our ( $Min, $Default ) = ( 4, 8 ); # パスワードとして使用を許可する入力文字列数の下限と初期値。
sub new { # 後方互換
generate(@_);
}
sub verify {
my $class = shift;
my ( $input, $data ) = @_;
die __PACKAGE__. " doesn't allow any Wide character or white space.\n" if $input =~ /[\P{ASCII}\s]/;
# MD5でない場合はperl cryptを使う
return $data eq unix_md5_crypt( $input, $data ) if $data =~ m/^\$1\$/;
return $data eq CORE::crypt( $input, $data );
}
sub nonce {
my $class = shift;
my $length = shift || 8;
my $n;
do { # 暗号強度の低い文字列の場合はやり直す
$n = '';
$n .= $charset[ rand @charset ] until length $n >= $length;
}while( $n =~ /^\w+$/ or $n =~ /^\W+$/ or $n !~ /\d/ or $n !~ /[A-Z]/ or $n !~ /[a-z]/ );
return $n;
}
sub encrypt {
my $class = shift;
my $input = shift;
croak __PACKAGE__ ." requires at least $Min length" if length $input < $Min;
die __PACKAGE__. " doesn't allow any Wide character or white space.\n" if $input =~ /[\P{ASCII}\s]/;
my $salt = shift || $class->nonce();
carp "warning: short lengths salt is set. you don't have to." if length($salt) < 8;
carp "warning: too many string lengths for salt. unix_md5_crypt() ignores more than 8." if $salt and length($salt) > 8;
return unix_md5_crypt( $input, $salt );
sub crypted { # 超個人的後方互換
encrypt(@_);
}
}
sub generate {
my $class = shift;
my $length = shift || $Default; # 文字数指定無しの場合、初期値で作成。
croak "unvalid length is set" if $length !~ /^\d+$/;
croak __PACKAGE__ ." requires list-context." unless wantarray;
croak __PACKAGE__ ." requires at least $Min length" if $length < $Min;
my $newpass;
do { # 可読性の低い文字を含む場合はやり直す
$newpass = $class->nonce( $length );
}while( $newpass =~ m#[0Oo1Il2Zz5sS6b9qCcKkUuVvWwXx.,:;~^'"{}\[\]]# );
return $newpass, __PACKAGE__->encrypt($newpass);
}
1;
__END__
=head1 NAME
Password - unix_md5_crypt()によるパスワードの作成と認証の簡素化。
=head1 VERSION
This document refers to version 3.00 of Password, released May 31, 2013
=head1 SYNOPSIS
my( $pass, $cripted ) = generate Password(6); # 新規作成
my $input = $cgi->param('pass'); # フォームから読み取り
my $data = Password->encrypt($input); # 暗号強度の高いsaltを自動生成して暗号化
my $flag = Password->verify( $input, $data ); # 認証
=head1 DESCRIPTION
=head2 Overview
OOPライクな呼び出しに対応したパスワードの作成と認証の一元化。
暗号化と認証はcrypt(認証のみ)とMD5によって実装。
my( $pass, $encript ) = generate Password(6); # セマンティクスな呼び出し
my( $pass, $encript ) = Password->generate(6); # OOPな呼び出し
どちらも可能ですが
B<オブジェクトを作りません。>
これは継続してblessすべき適当なデータが見つからないためです。
=head2 Constructor and initialization
There is no constructor.
=head2 Methods and Subroutines
=over
=item new B<(注:コンストラクタではありません。)>
same as generate( is B<NOT> a constructor )
=item generate
新しいパスワードを作らせます。
my( $pass, $cripted ) = generate Password(6); # または Password->generate(6);
指定長のランダム文字列を生成して暗号化文字列と共に返します。
人間が誤読しやすい文字(0Oo1Il2Zz5sS6b9qCcKkUuVvWwXx.,:;~^'"{}[])を含まないように自動的に処理します。
指定長の省略時は$Password::Defaultを使います。(変えなければ8)
=item encrypt
指定文字列を暗号化して返します。
saltは暗号強度の高い文字列を自動生成して使用します。
my $data = encrypt Password($input); # または Password->encrypt($input);
=item verify
暗号認証して真偽値を返します。
my $flag = verify Password( $input, $data ); # または Password->verify( $input, $data );
=back
=head1 SEE ALSO
オブジェクト指向Perlマスターコース - ダミアン・コンウェイ pp187-190
http://www.amazon.co.jp/exec/obidos/ASIN/4894713004/
=head1 Copyright
Copyright (c) since 2005, Yuki Yoshida All rights reserved.
This Module is free software.
It may be used, redistributed and/or modified under the same terms as Perl itself.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment