Last active
October 30, 2017 10:06
-
-
Save worthmine/4a9a80b6d8a2149a0b33 to your computer and use it in GitHub Desktop.
既存のCGIスクリプトでより強固なパスワード認証を行う ref: http://qiita.com/worthmine/items/519fb4fd1d7f5117a255
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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