japan.internet.com The Internet & IT Network


RSSニュース検索
カテゴリ
> トップページ
> Webビジネス
> Eコマース
> Webファイナンス
> Webマーケティング
> パブリック
> Webテクノロジー
> 携帯・ワイヤレス
> Linux Today
> Linux Tutorial
> J.I.C.ブログ
キャリア
> 転職ならen
> 派遣ならen
> アルバイトならen
> IT求人情報
ヘッドライン
> 今日のヘッドライン
> 週間ヘッドライン
Special Link
> フォトコミュニティ
> ストックフォト
> クリップアート
> イラスト
> フェリカ
> Web2.0
> 写真
イベント&セミナー
> イベントカレンダー
> 書評「IT の耳」
> 出張・接待検索
> ニュースガジェット 注目
無料ニュースメール
> 新規登録
> 変更・解除
> オプトインメールの登録・変更・解除
インフォメーション
> パートナーサイト
転職ならエン
就職ならen
求人ならen
履歴書ならen
アルバイトならエン
CRM/SFAならオラクル
> グループ会社
株式会社アエリア
(株)サンゼロミニッツ
株式会社エアネット
> お問い合わせ
> 広告掲載について
> リンクについて
> 著作権について
> その他お問い合わせ
> 利用規約
> 個人情報保護方針
> 会社概要地図
デベロッパー 2005年10月5日 13:30
デベロッパー・バックナンバー
.NET とAIでスパムボットに対抗する(3)

著者: Adnan Masood  オリジナル版を読む プリンター用 記事を転送
2005年10月5日 13:30 付の記事
海外internet.com発の記事
このエントリーを含むはてなブックマーク この記事をクリップ! Buzzurlにブックマーク Yahoo!ブックマークに登録 newsing it!

 前回「企業での CAPTCHA 利用例」へ

独自 CAPTCHA アプリケーションの開発

 ASP.NETには、画像の生成・操作を行うための機能が含まれている。以前のASP 3.0とは異なり、ASP.NETは.NET Frameworkを最大限に活用することができ、外部ライブラリを使わずに動的な画像処理を行うことができる。System.Drawingクラスを使用すると、メモリ内で画像を生成し、その画像を出力ストリームを通じてブラウザ上に描画できる(このプロセスについては、次の分離コードファイル(OntheFly.aspx.vb)を参照のこと)。

 このサンプルの目的は、クエリ文字列を通じて渡されたパラメータに基づいて、画像を動的に生成することである。ビットマップ画像を描画するには、HTTPContextを使用する。これは、System.Drawing.Bitmapオブジェクトをインスタンス化するためのブラウザのストリームハンドラである。BitmapコンストラクタはpixelFormatをパラメータとして受け取り、110×50ピクセルの描画用キャンバスを返す。このプロセスはすべてメモリ内で行われ、後でpageContextがフラッシュされるときにブラウザ上に描画されるという点に注意してほしい。次に、ラスタ(つまりビットマップメモリマップ)への描画を行うグラフィックオブジェクトが必要になる。このグラフィックオブジェクトのインスタンスはFillRectangleDrawStringを呼び出して、キャンバス上に矩形とパラメータテキストを描画する。このキャンバスは、出力ストリームに対してgif MIMEタイプとしてフラッシュされる。実際に出力した画像の例を次の図に示す。

図1.19:動的な画像生成のデモ(手前はIE、後ろはVS IDE)
図1.19:動的な画像生成のデモ(手前はIE、後ろはVS IDE)
リスト:OntheFly.aspx.vb
’// Filename: onthefly.aspx.vb
’// Author: Adnan Masood
’// Last updated: 12/07/03
’// Importing the libraries for drawing operations
Imports System
Imports System.Drawing
’// Class OntheFly declaration
PublicClass OntheFly : Inherits System.Web.UI.Page
’//Page_Load event overriding 
PrivateSub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) 
    HandlesMyBase.Load
’//Getting HTTPContext
Dim pageContext As System.Web.HttpContext 
pageContext = System.Web.HttpContext.Current
’//Reading the parameter
Dim strText AsString = Request("param")
’//Create the memory map 
Dim raster As Bitmap
Dim pixFormat As Imaging.PixelFormat
pixFormat = Imaging.PixelFormat.Format32bppArgb
’// Create a memory image with dimensions 110x50
raster = New Bitmap(110, 50, pixFormat)
Dim graphicsObject As Graphics
graphicsObject = Graphics.FromImage(raster)
’// Instantiate object of brush
Dim objBrush As SolidBrush = New SolidBrush(Color.Yellow)
’//Creating a font object with Arial size 10 and bold
’//public Font(string, float, FontStyle)
Dim objFont As Font = New Font("Arial", 10, FontStyle.Bold)
’//Set the background half rectangle blue
’//Method Signature: FillRectangle (const Brush *brush, INT x, INT y, INT width, INT height);
graphicsObject.FillRectangle(New SolidBrush(Color.Blue), 0, 0, 55, 50)
’//Writing the string on image
graphicsObject.DrawString(strText, objFont, objBrush, 0, 0)
’//Flushing the graphics object
graphicsObject.Flush()
’//Setting the response header content MIME type
pageContext.Response.ContentType = "image/gif"
’//Saving the file to output stream to be displayed in browser
raster.Save(pageContext.Response.OutputStream, Imaging.ImageFormat.Gif)
’//Flushing to the Response 
pageContext.Response.Flush()
EndSub
EndClass

 OntheFly.aspx.vbは、OntheFly.aspxの分離コードファイルである。OntheFly.aspxには次の行が含まれている。

リスト:OntheFly.aspx
<%@ Page Language="vb" Src="OntheFly.aspx.vb" Inherits="OntheFly"%>

 図1.20は、出力した画像の例である。パラメータに何か文字列を指定すると、このコードによって画像が生成され、ブラウザ上に描画される。バイナリファイルの中に画像として描画されたテキストは、HTMLコードとは違って簡単に読み取ることができないため、スパムボットで何が書かれているかを判読するためには、特殊なテクニックが必要になる。この単純なサンプルを応用すれば、フォーラムやブログなどの電子メールアドレス保護機能を実現できる。キャッシュ処理を工夫すれば、パフォーマンスが大きく低下することもない。

図1.20:渡されたクエリ文字列パラメータに基づいてASP.NETファイルから動的に生成した画像
図1.20:渡されたクエリ文字列パラメータに基づいてASP.NETファイルから動的に生成した画像

辞書ベースのCAPTCHAの実装

 今度のサンプルは、本格的なCAPTCHAプログラムの機能を備えているため、先ほどのものより少し長く複雑になっている。このプログラムでは、辞書ベースのCAPTCHAを動的に生成し、画像内のテキストの入力を求めて、相手が人間かどうかの確認を行う。

 このプログラムの流れは次のとおりである。ある架空のフォーラムのログインフォームで、ユーザーが人間であるかどうかを確認するために、フォーム下部の画像内のテキストを入力するようユーザーに要求する。プログラムは、用意されているさまざまな画像の中から背景用画像を動的に選択し、「OGDEN’s Basic English」辞書から選択した任意の単語と組み合わせる。OCRでの認識を難しくするために、字体も1文字ごとに変更する。以降では、このプログラムの動作を簡単に説明し、完全なコードリストと辞書データベースファイルを紹介する。

図2.1:フォーラムのログインフォームの例
図2.1:フォーラムのログインフォームの例

 ユーザーが間違った単語を入力すると、次の画面に進むことができず、エラーメッセージが表示される。

図2.2:フォーラムへのログイン時に表示されるエラーの例
図2.2:フォーラムへのログイン時に表示されるエラーの例

 ボットが再試行しようとすると、今度は別の背景と別の単語を使用した新しい画像が表示される。

 アプリケーション設計者は、再試行を何回まで認めるかを検討しなければならない。ユーザーが再試行した回数を記録しておき、このプログラムがセキュリティ対策ではなく一般ユーザーに対する障壁になっていないかどうかを確認する必要がある。また、障害者のために、代替策(音声を使用するなど)も用意しておいた方がよい。

図2.3:フォーラムのログインフォームの例
図2.3:フォーラムのログインフォームの例

 ユーザーが正しい単語を入力した場合、このプログラムはユーザーのアクセスを許可する。その前に別の処理を挿入することもできる。

図2.4:フォーラムへのログインが成功した場合の例
図2.4:フォーラムへのログインが成功した場合の例

 それでは、このアプリケーションの内容を詳しく見ていくことにしよう。

 次の図は、OGDENのBasic English辞書をデータベース化したものである。各列に同じアルファベットから始まる単語が収録されており、ここからCAPTCHA画像に組み込む単語をランダムに選択できる。

図:「OGDEN’s Basic English」辞書をアプリケーション用にデータベース化したもの(dictionarydb)
図:「OGDEN’s Basic English」辞書をアプリケーション用にデータベース化したもの(dictionarydb)

 このアプリケーションには次の3つのメインファイルがある。

captchaForm.aspx

 このファイルには、辞書内の単語をランダムに選択してcaptcha.aspxに渡すためのコードが含まれている。captcha.aspxの分離コードファイルであるcaptcha.aspx.vbは、渡された単語を処理して、ブラウザ上に画像を描画する。このファイルには、フォームを処理するコードと、ユーザーが入力したCAPTCHAの値を検証するコードも含まれている。さらに、dictionary.mdbへの接続、ランダムな単語の読み取り、セッションの処理を行うコードも含まれている。

captcha.aspx.vb

 これはcaptcha.aspxの分離コードファイルである。画像生成の処理はこのファイルが担当する。このファイルはbackgroundsフォルダ内の背景パターンをランダムに選択し、captchaform.aspxから渡されたテキスト文字列を書き込む。さらに、機械による読み取りを難しくするために、字体とサイズをランダムに選択する。

dictionary.mdb

 このAccessデータベースリポジトリには、OGDENのBasic English辞書の項目が格納されている。

 各所のコメントを追っていけば、このコードでどんな処理をしているかはすぐにわかるだろう。

リスト:captchaForm.aspx
<!--
’// Filename: captchaForm.aspx// Author: Adnan Masood// Last updated: 12/08/03
-->
<%@ Import Namespace="System" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<%@ Page Language="C#" debug=true%>
<HTML>
<head>
    <script runat="server">
    // Pageload event
void Page_Load(object Source, EventArgs E)
{
        // If form is not posted than assign the selectWord return to session 
        if (!IsPostBack)
Session["param"] =selectWord();
        // Else check if session’s value is same as that of Captcha’s entered value
        // in the form and assign appropriate message to innertHtml of label
else
{
if (String.Compare(Convert.ToString(Session["param"]),Convert.ToString(Request.Form["CAPTCHA"]))==0) 
            lblstatus.InnerHtml= "Thanks for Registeration with our Forums";
        else
        lblstatus.InnerHtml= "Error Occured! Value of Image is not correct, " +
                "please <a href=captchaform.aspx> re-enter </a>";
}
}
    // Select word method
    // Return type String of random word from dictionary
    // Dictionary is based on OGDEN’s BASIC ENGLISH 
    // http://ogden.basic-english.org/basiceng.html
    public String selectWord () {
        
        // The Connection string referencing the MDB file
        String ConnectionString = "Provider=Microsoft.Jet.OleDb.4.0;Data Source=" 
        + Server.MapPath("dictionary.mdb") + ";";
        
        // Datareader object
        OleDbDataReader objReader;
        
        // Creating an array of 26 characters (alphabets in dictionary database as columns)
        char[] columns = newchar[26];
        
        // Adding the column names in the array
        // uses the ASCII character conversion for selecting values
        // from A- Z
        for (int a=65; a<65+26; a++)
        columns[a-65] = (char)a;
                
        // Query String for selecting a random column from spelling list database
String QuerySQL = "SELECT " + columns[(new Random().Next(26))] + " FROM spellList";
// Opening the connection
OleDbConnection objConn = new OleDbConnection(ConnectionString);
    // Creating new command object
    OleDbCommand objCmd = new OleDbCommand();
    // Assigning command text
    objCmd.CommandText = QuerySQL;
    // Assigning the connection to command object connection attribute
objCmd.Connection = objConn;
// Instantiating a random class object 
Random randomSeed = new Random();
// Creating a random seed selector
int randomSeedSelector=0;
// An string character with maximum capacity for dictionary column
String[] selectedIndex = new String[700];
String str = "";
// This code segment opens the connection and read the dictionary
try
        {
objConn.Open();
objReader = objCmd.ExecuteReader();
while (objReader.Read()) {
                str = objReader.GetValue(0).ToString();
                if (str.Length != 0) {
                    selectedIndex[randomSeedSelector] =str;
                    randomSeedSelector++;
                }
}// Ends While
str = selectedIndex[randomSeed.Next(randomSeedSelector)];
            
        } // Ends Try
catch (Exception Err)
        {
// The Error Catching operations
        }
finally
        {
objConn.Close();
        }
        // Returns the selected string
        return (str);
        
}// ends function 
    </script>
    </head>
    <body>
        <% //Checking for postback for initial processing of form.
        if (!IsPostBack) { %>
        <form runat="server">
            <P align="left"><STRONG><FONT size="5">Signup for Forums</FONT></STRONG></P>
            <P>
                <TABLE id="Table1" height="200" cellSpacing="1" cellPadding="1" width="704" border="1">
                    <TR>
                        <TD>
                            <P>Name</P>
                        </TD>
                        <TD><INPUT id="Text1" type="text" name="name"></TD>
                    </TR>
                    <TR>
                        <TD>Email Address</TD>
                        <TD><INPUT id="Text2" type="text" name="email"></TD>
                    </TR>
                    <TR>
                        <TD>
                            <P><IMG src="http://localhost/captcha/example2/captcha.aspx"></P>
                            <P>Enter the text above into the box on right.</P>
                        </TD>
                        <TD><INPUT id="Text3" type="text" name="CAPTCHA"></TD>
                    </TR>
                    <TR>
                        <TD>
                        <INPUT id="Submit1" type="submit" value="Submit" name="Submit1">
                        <INPUT id="Reset1" type="reset" value="Reset" name="Reset1">
                        </TD>
                        <TD></TD>
                    </TR>
                </TABLE>
            </P>
        </form>
        <% }
            //Setting lable’s status accordingly 
            else
        { %>
        <td id="lblstatus" runat="server"></td>
        <% }%>
    </body>
</HTML>
リスト:captcha.aspx.vb
’// Filename: captcha.aspx.vb
’// Author: Adnan Masood
’// Last updated: 12/08/03
Imports System
Imports System.Drawing
Imports System.String
Imports System.Drawing.Image
namespace com.axisebusiness.OnlineImage
’// Importing the libraries for drawing operations
’// Class OntheFly declaration
PublicClass CAPTCHA : Inherits System.Web.UI.Page
’//Page_Load event overriding 
PrivateSub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) 
    HandlesMyBase.Load
’//Getting HTTPContext
Dim pageContext As System.Web.HttpContext 
pageContext = System.Web.HttpContext.Current
’//Reading the parameter from session this time
Dim strText AsString = Session("param") 
’//Create the memory map 
Dim raster As Bitmap
Dim pixFormat As Imaging.PixelFormat
pixFormat = Imaging.PixelFormat.Format32bppArgb
’// Select an memory image from file of 290x80px
’// in the backgrounds folder named backX.jpg
Dim graphicsObject As Graphics
Dim imageObject as System.Drawing.Image = 
    System.Drawing.Image.FromFile(Server.Mappath("backgroundsack" &  
    new Random().Next(5) & ".jpg"))
’// Creating the raster image object
raster = new Bitmap (imageObject)
’//Creating graphics object
graphicsObject = Graphics.FromImage(raster)
’// Instantiate object of brush with black color
Dim objBrush As SolidBrush = New SolidBrush(Color.Black)
Dim objFont As Font
dim a asInteger, myFont asString, str asString
’//Creating an array for most readable yet cryptic fonts for OCR’s
’// This is entirely up to developer’s discretion
dim crypticFonts(11)
crypticFonts (0) = "Arial"
crypticFonts (1) = "Verdana"
crypticFonts (2) = "Comic Sans MS"
crypticFonts (3) = "Impact"
crypticFonts (4) = "Haettenschweiler"
crypticFonts (5) = "Lucida Sans Unicode"
crypticFonts (6) = "Garamond"
crypticFonts (7) = "Courier New"
crypticFonts (8) = "Book Antiqua"
crypticFonts (9) = "Arial Narrow"
crypticFonts (10) = "Estrangelo Edessa"
’//Loop to write the characters on image
’// with different fonts.
For a=0 to strText.Length-1
myFont = crypticFonts(new Random().Next(a))
objFont = New Font(myFont, 20, new FontStyle().Bold)
str = strText.substring(a, 1)
graphicsObject.DrawString(str, objFont, objBrush, a*20, 35)
graphicsObject.Flush()
next
’//Flushing the graphics object
graphicsObject.Flush()
’//Setting the response header content MIME type
pageContext.Response.ContentType = "image/gif"
’//Saving the file to output stream to be displayed in browser
raster.Save(pageContext.Response.OutputStream, Imaging.ImageFormat.Gif)
’//Flushing to the Response 
pageContext.Response.Flush()
EndSub
EndClass
Endnamespace

 Captcha.aspxファイルには次のように記述されている。

リスト:Captcha.aspx
<%@ Page Language="C#" Src="Captcha.aspx.vb" Inherits="com.axisebusiness.OnlineImage.Captcha"%>

 お気付きのとおり、このコードは1つのプログラム内で複数の言語(この場合はC#とVB.NET)を使用する方法のサンプルでもある。このプログラムで生成したCAPTCHAは絶対に破られないとは言えないが、通常のスパムボットへの対策としてはかなり有効である。

 次回「CAPTCHA を Web サービスから配布または呼び出す方法」へ

著者紹介

Adnan Masood(Adnan Masood)
ロンドンのUKIMのソフトウェア開発者。UNW Stratford Londonキャンパスにてソフトウェア工学の理学修士号を取得。複数のソフトウェア開発技術にまたがるハイブリッド的な視野を持って開発に臨み、主にMicrosoftおよびSunプラットフォームのサーバーサイドプログラミングを専門とする。ここ5年間はASPおよびJavaの開発者として活躍。コンピュータ工学の理学士号とSun Java-II Certification(SCJP-II)の資格を持つ。ブログのURLはwww.axisebusiness.com/adnano。電子メールアドレスはamasood@bcs.org.uk


関連テーマ
  • ブラウザ
  • スパム
  • Sun
  • Microsoft
  • Java


  • ★最新トップニュース
    海外 MySpace.com、ディスプレイ広告配信数で首位に(Webマーケティング 8月28日 11:10)
    ソーシャル ネットワークは広告による利益化が難しいという見方があるが、これを覆す調査結果が明らかになった。
    海外 SAP、SMB 向けオンデマンド スイートを大幅に革新(Webビジネス 8月28日 11:10)
    SAP は、中小企業 (SMB) 向けオンデマンド製品『Business ByDesign』に多くの革新技術を投入し、積極的に新しい市場を開拓していく計画だ。
    海外 Nokia、キャリア縛りのない携帯電話3機種を発売(携帯・ワイヤレス 8月28日 11:10)
    Nokia が、特定の移動体通信事業者と提携しない形で『N』シリーズ端末の新モデル3種を発売した。同社はこの販売形態について選択肢を増やすものと位置づけている。
    海外 『iPhone 3G』訴訟が拡大、原告が2人に(携帯・ワイヤレス 8月28日 10:50)
    『iPhone 3G』をめぐり、Apple が虚偽の宣伝約束のもとに欠陥品を販売したとして提訴されている訴訟に、2人目の原告が加わった。
    コラム 【書評】『1回の会議・打ち合わせで必ず結論を出す技術』――無意味な会議を撲滅する(CyberAtlas 8月28日 10:10)
    退屈な会議、無意味に長引く会議、会議って本当に必要なの?と疑問をお持ちのかたがたに、本書、『1回の会議・打ち合わせで必ず結論を出す技術』は非常に有効だ。
    トピックス
    > オススメのIT系求人情報【毎週月曜日更新】
    footer_301.gif


    リサーチ
    > デイリーリサーチDLサイト
    > OnlineResearchPortal (リサーチデータバンク)
    > モバイルリサーチ with goo
    footer_301.gif
    キーワード
    > iPhone > Youtube
    > Google > モバイルノート
    > 半導体 > ウィルコム
    > テーマ一覧はこちら
    footer_301.gif
    セミナー情報
    > 第2回インターネットコムマーケティングセミナー
    〜モバイルマーケティングの世界〜
    9月24日(水)13:00〜17:00 ITS 山王健保会館
    ※詳しくはこちら
    footer_301.gif
    デベロッパー
    > DevX
    > CodeGuru
    > developer.com
    footer_301.gif
    j.i.c.ブログ
    ブログ一覧
    データメーション 【データメーション】
    Apple は顧客の忠誠心にあぐらをかいているのか? (8月27日)
    Graphic Design Forum 【Graphic Design Forum】
    次へとつながる輪 (8月27日)
    ベンチャー専門家の目利きブログ「なぜこの企業は伸びるのか?」 【ベンチャー専門家の目利きブログ「なぜこの企業は伸びるのか?」】
    「成長の絵を描いていかないとビジネスモデルは育たない」/ビジネスオンライン株式会社(8月27日)
    最新テクノロジーの意外な処方箋 【最新テクノロジーの意外な処方箋】
    あなたが舌なめずりしたくなるようなもの(8月26日)
    エンジニアの独り言 【エンジニアの独り言】
    データをローカルに保存するWebアプリケーション(8月22日)
    デスマーチからの脱却 【デスマーチからの脱却】
    30min. iPhoneアプリリリース(8月18日)
    footer_301.gif
    最新コラム一覧
    「IT の耳」 「IT の耳」

    【書評】『1回の会議・打ち合わせで必ず結論を出す技術』――無意味な会議を撲滅する(8月28日)
    ハードウェアから見たデータベース ハードウェアから見たデータベース

    巨大テーブル活用術1(8月28日)
    百式のネットビジネス研究 百式のネットビジネス研究

    この音楽を嫌いな人はこの音楽を聴いています、を実現する「TuneFad」(8月28日)
    ウチのサイトを SEO ウチのサイトを SEO

    検索エンジンが見ている世界(8月27日)
    developer.com developer.com

    デザインパターンの使い方: Singleton(8月26日)
    エンジニア転職ノウハウ開発室 エンジニア転職ノウハウ開発室

    目指せecoエンジニア!グリーンITで地球を救え(8月26日)
    アイレップの SEM フロンティア アイレップの SEM フロンティア

    円滑に SEO を導入・実施するための組織体制を構築しよう(3)(8月26日)
    グローバル企業のセキュリティ事情 グローバル企業のセキュリティ事情

    グローバル企業のセキュリティ対策と将来(8月25日)
    ウィジェット・ガジェットビジネス研究所 ウィジェット・ガジェットビジネス研究所

    海外ウィジェット、ガジェットビジネス(8月25日)
    週刊-サイト別アクセス状況データ 週刊-サイト別アクセス状況データ

    米企業の約8割、社内に XBRL の専門家なし(ビデオリサーチインタラクティブコラム)(8月25日)
    footer_301.gif
    専門チャンネル
    > セキュリティチャネル > テレコムチャネル
    > サーチエンジンウォッチ
    footer_301.gif
    海外のインターネットコム アメリカ韓国ドイツトルコ
    関連企業のサイト:ストックフォト イラスト ネットストリート ホテル予約サイト タウン情報 出張 事業継承 シミュレーション トランクルーム 優待映画チケット 田舎暮らしガイド オリジナルデザインTシャツ ニタコエ
    Copyright 2008 Jupitermedia Corporation All Rights Reserved. http://www.internet.com/
    space.gif space.gif