« GoogleSitemapsジェネレータ  |   index   |  インストール型ブログ »

2005年07月17日

セキュリティコード

登録認証時のセキュリティコード

登録するときに、画像の文字を入力してくださいっていうのがあります
あれは、自動登録などを防ぐためにあるそうです
「submission code」(サブミッション・コード)とも言うそうです
いまひとつ仕組みがわからないので、自分で考えてみることにしました

約束事として、
HTMLファイルのソースを直接見られても、セキュリティコードがわかってはならない
暗号化するにしても、方法がわかってはならない


[1] まず最初に、かなり回りくどい方法から
これは、HTML,JavaScript,Flash,CGIをつかいます
フローとしては
  1. HTMLファイルを表示
  2. その際JavaScriptで乱数を生成
  3. 生成された乱数をFlashへの引数と次画面(登録CGI)へのhiddenパラメータとして渡す
  4. Flashの方は、受け取った乱数を書き込み用のCGIへ渡し、戻り値として文字列を受け取り表示する
  5. 書き込み用のCGIでは受け取った乱数と更に表示用に生成した6桁の乱数文字列、現在の日付をファイルに書き出し、ここで表示用に生成した6桁の文字列を返す
  6. ユーザはFlashで書き出された文字列を読み入力フィールドに書き送信
  7. 登録CGIでは、受け取った乱数とセキュリティコード、日付の差をファイルと比較、その他の入力項目も確認して真偽を決定
  8. 真なら更に現在の時間フィールドを追加してファイルに保存 (日付超過データを削除)
  9. 真ならユーザに登録内容を確認させて、アクティベーション用のURLを書いてメール送信
  10. アクティベーションURL用のCGIで正規のコードを受け取った時点で先ほどのデータを削除して、ユーザ登録をする
この方法の利点は
 ・HTMLでの表示
 ・このHTMLで見られる乱数は、表示されるセキュリティーコードとはまったく無関係である

欠点として
 ・JavaScriptとFlashが必須
 ・作る側は、かなりめんどうなことになる


[2] 上記のものを改良
これは、Flashを使わずGIFアニメーションを生成する(gifcat.pl使用)
フローはほぼ同じ
Flashの部分をなくして、<img>タグでCGIに乱数を渡す

この方法の利点は
 ・Flashがいらなくなる

欠点として
 ・ばらばらのGIF画像を大量に作っておく必要がある
 ・出かたが変 (gifcat.plの特徴)

考察の余地
Image::Mgickをつかって一つのGIF画像を作成するという手法がある


[3] 更に改良
HTML表示ではなくCGIによる表示 (普通はこっちかも)
これもJavaScript部分をCGIで書き出すだけで、Flashなら[1]とほぼ同じ、GIF画像なら[2]とほぼ同じ

この方法の利点は
JavaScriptがいらなくなる


では、[1]から検証
HTML,JavaScript,Flash,CGIを使ったサンプル
以下のファイル(4+1)をまとめたものをダウンロードできます
File: secur_code.zip


入力用のHTML[index.html]

Code: download

  1. <h1>セキュリティコード認証のテスト</h1>
  2.  
  3. <form action="check.cgi" method="POST">
  4. <fieldset><legend>Regist Form</legend><br />
  5. <h2>登録するユーザ名を入力してください(半角英数字20文字以内)</h2>
  6. Name : <input type="text" name="name" size="20"><br /><br />
  7. <h2>右側の画像に表示されている、文字列を入力してください</h2>
  8. Code : <input type="text" name="code" size="10">
  9. <script>
  10.  var rand = Math.floor(Math.random()*10000000000);
  11.  document.write('<OBJECT classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" '+
  12.  'codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0" '+
  13.  'width="90" height="25" id="code.swf" align="middle"><param name="allowScriptAccess" value="sameDomain">'+
  14.  '<param name="quality" value="high"><param name="bgcolor" value="#000000">'+
  15.  '<param name="movie" value="code.swf"><param name="FlashVars" value="code=' + rand +'">'+
  16.  '<embed src="code.swf" quality="high" bgcolor="#000000" width="90" height="25"'+
  17.  ' name="code.swf" align="middle" allowScriptAccess="sameDomain" FlashVars="code=' + rand + '" '+
  18.  'type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer">'+
  19.  '</object><input type="hidden" name="ccode" value="'+rand+'">');
  20. </script>
  21. <noscript><h2>JavaScriptを有効にしてください</h2></noscript><br /><p><input type="submit" value="送 信"></p>
  22. </fieldset></form>
  23.  
  24. <h3>* 画像が見えにくい場合は、<a href="./">読み込みなおして</a>ください</h3>
  25. <h3>* 送信後、確認画面を表示します</h3>
ほとんどがFlash(code.swf)を引数つきで呼び出すだけのタグです

10行目でJavaScriptで10桁の乱数を生成して(rand)
それを、15行目と17行目でFlashへの引数として書き出しています
更に、19行目ではhiddenフォームとして次画面のCGIへ渡すよう書き出しています
21行目はJavaScriptが使えない場合の警告です



Flash[code.swf]内のAction Script

Code: download

  1. cginame = "ccode.cgi?code=";
  2. inval = _root.code;
  3. lv = new LoadVars();
  4. lv.onLoad = function() {
  5. tfCount.text = this.secure_num;
  6. };
  7. lv.load(cginame + inval);
1行目で、書き込み用のCGIまでのパスを指定
2行目では、先ほどJavaScriptで書き出した引数を取得
5行目で、書き込み用CGIからの戻り値を表示 (secure_numは書き込み用CGIからの戻り値パラメータ)
7行目で、書き込み用のCGIへ引数を渡しています

Flashの作り方は、リンク集を参考にしてください
File: code.fla は、「Macromedia Flash MX 2004」で作成しています


Made with Macromedia Flash MX



書き込み用CGI [ccode.cgi]

Code: download

  1. use CGI  qw(:standard);
  2.  
  3. $code_file = 'code.txt';
  4. $limit = 7200;
  5. $incode = (param('code') =~ /\d+/) ? param('code') : die;
  6. $rand_code = sprintf("%d%d%d%d%d", int(rand(10)),int(rand(10)),int(rand(10)),int(rand(10)),int(rand(10)));
  7. $time = time;
  8.  
  9. open(CODE, "+< $code_file") or open(CODE, ">$code_file");
  10. flock(CODE,2);
  11. while(<CODE>) {
  12.  $date = (split("\t",$_))[2];
  13.  chomp($date);
  14.  next if (($time-$date)>$limit);
  15.  push @out, $_;
  16. }
  17.  
  18. push @out, "$incode\t$rand_code\t$time\n";
  19. seek(CODE, 0, 0);
  20. print CODE @out;
  21. truncate(CODE, tell(CODE));
  22. close CODE;
  23.  
  24. print "Content-type: text/plain\n\nsecure_num=$rand_code";
今回表示する文字列は、数字に限定しました(0〜9)

3行目で、データ保存ファイル名を指定
4行目で、有効期限を秒数で指定(ここでは2時間以内)
5行目では、JavaScript→Flashの順で経由してきた乱数を取得しています
6行目で、Flashで表示用の5桁の乱数を生成
7行目は、現在の日付(エポックタイム)
9〜16行目までで、新規書き込みと 有効期限が過ぎたデータを削除
18行目での、データの並び順は
    1. JavaScriptで生成された乱数
    2. 表示用に生成した乱数文字列(5桁)
    3. 現在の日付(エポックタイム)
24行目で、Flashへの戻り値として、secure_num=表示用文字列 を返す



入力確認CGI [check.cgi]

Code: download

  1. use CGI  qw(:standard);
  2.  
  3. $code_file = 'code.txt';
  4. $limit = 7200;
  5. $re_date = time;
  6. $que = param('que');
  7. $in{code} = param('code');
  8. $in{ccode} = param('ccode');
  9. $in{name} = param('name');
  10. $secur = sprintf("%d%d%d%d%d", int(rand(10)),int(rand(10)),int(rand(10)),int(rand(10)),int(rand(10)));
  11.  
  12. open(FH, "+< $code_file") or die "Can't open $code_file: $!";
  13. flock(FH,2);
  14. while(<FH>) {
  15.  chomp;
  16.  my($ccode,$code,$date,$dmy) = split("\t");
  17.  if(($ccode eq $in{ccode}) && ($code eq $in{code}) && (($re_date-$date)<$limit)) {
  18.    push @out, qq($ccode\t$code\t$re_date\t$secur\n);
  19.    $flag = 1;
  20.    $ok_code = $code;
  21.    $save_rand = $ccode;
  22.    $save_time = $date;
  23.    $now = $re_date;
  24.  }
  25.  elsif(($re_date-$date)>$limit) {
  26.   next;
  27.  }
  28.  else {
  29.   $flag = 2 if ($ccode eq $in{ccode});
  30.   push @out, "$_\n";
  31.  }
  32. }
  33. seek(FH,0,0);
  34. print FH @out;
  35. truncate(FH, tell(FH));
  36. close(FH);
  37.  
  38. if($flag == 1) {
  39.  $sec_code = qq(セキュリティーコードが一致しました) }
  40. elsif($flag == 2) {
  41.  $sec_code = qq(セキュリティーコードが一致しません) }
  42. else {
  43.  $sec_code = qq(セキュリティコードの有効期限が過ぎているか無効です) }
  44.  
  45.  print <<HTML;
  46. Content-type: text/html\n\n
  47. <html><head>
  48. <title>test - check</title></head><body>
  49. <h1>セキュリティコード認証のテスト - 確認</h1>
  50. <br />
  51. <h2>$sec_code</h2>
  52. <table width="400" border="1" cellspacing="0" cellpadding="3">
  53. <tr><td>ユーザ名</td><td>$in{name}</td></tr>
  54. <tr><td class="col">保存されているセキュリティーコード</td><td class="col">$in{code}</td></tr>
  55. <tr><td>表示されたセキュリティコード</td><td>$ok_code</td></tr>
  56. <tr><td class="col">保存されている乱数</td><td class="col">$save_rand</td></tr>
  57. <tr><td>JavaScriptで生成された乱数</td><td>$in{ccode}</td></tr>
  58. <tr><td class="col">保存されていた日付</td><td class="col">$save_time</td></tr>
  59. <tr><td>現在の日付(書き換えた日付)</td><td>$now</td></tr>
  60. </table>
  61. <br />
  62. <h3>* 通常はここで確認ボタンを表示してメール送信画面に進みますが省略</h3>
  63. <br />
  64. <p><a href="javascript:window.close()">閉じる</a></p>
  65. </body></html>
  66. HTML
3行目は、データ保存ファイル名を指定
4行目で、有効期限を秒数で指定します(ここでは2時間以内)
5行目、有効期限の比較用に現在の日付を取得
6〜9行目では、HTMLからの引数を取得しています
10行目で、アクティベーション用に新たに追加する乱数生成
17行目で、セキュリティコードと乱数、有効期限を確認
19行目の$flagは、表示用の確認フラグです (コード、乱数、有効期限ともに真)
25,26行目の処理は、有効期限切れを削除するためです
29行目、表示用の確認フラグで入力ミスを検出(コードは偽だが、乱数は真)
38〜43行目までで、フラグによる可否表示情報を作成

今回は、これらの情報をHTMLファイルとして確認用に書き出しています



投稿者 edams : 2005年07月17日 01:19

トラックバック

このエントリーのトラックバックURL: http://sieg.xeong.com/mt-tb.cgi/23
このエントリーを含むはてなブックマークこのエントリーを含むはてなブックマーク


コメント

サイン・インを確認しました、 さん。コメントしてください。 (サイン・アウト)

(いままで、ここでコメントしたとがないときは、コメントを表示する前にこのウェブログのオーナーの承認が必要になることがあります。承認されるまではコメントは表示されません。そのときはしばらく待ってください。)


情報を登録する?