SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

.NETとAIでスパムボットに対抗する

画像認識によるスパム対策.NET編

ダウンロード ソースコード (574.5 KB)

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

 Webサービスとは、URIでアドレスを指定できるソフトウェアコンポーネントである。Webサービスでは、さまざまなニッチな需要を満たす多様なサービスを提供することができる。ここでは、他のアプリケーションのためにCAPTCHA画像を提供するWebサービスの作成方法について説明する。具体的には、Webメソッドの公開、BLOB(binary large object)またはBase64エンコードデータの転送、Webメソッドの呼び出しを行うためのテクニックを紹介する。

 これから説明するのはcaptchaWebServiceというWebサービスである。このWebサービスには、getCaptchaselectWordgenerateImageという3つの公開メソッド(Webメソッド)が含まれている。.NET Frameworkには、メソッドシグネチャを表すasmxファイルを調べる機能がある。invoke.aspxと同様に、このWebサービスは、画像を使ったユーザー確認を必要とするどのWebアプリケーションからでも実行できる。この機能はASP.NET以外からも利用可能である。これはWebサービスであるため、実質的にすべてのプログラミング言語およびプラットフォームに対するクロスプラットフォームサポートを提供している。

 このプラットフォーム非依存のコンポーネントアーキテクチャには、もう1つ大きな利点がある。それは、CAPTCHアルゴリズムはボットに対抗して一元的に修正、拡張、強化することができ、すべてのクライアントがその恩恵を受けることができるということだ。CAPTCHAアプリケーションサービスプロバイダは、このサービスを低価格で提供してもよいし、定額制または従量制で提供してもよい。どのような形で提供するかはビジネスプロセスモデルしだいである。

図3.1:提供可能なWebサービス一覧の例
図3.1:提供可能なWebサービス一覧の例

 関数に関するWSDL(web service description language)ファイルについてはここを参照。このファイルには、関数シグネチャとパラメータの詳細がそれぞれのデータ型と共に記されている。

 関数getCaptchaselectWordgenerateImageはそれぞれ個別に実行できるが、内部的にはお互いを呼び出しながら処理を行っている。

selectWord()

[WebMethod(Description="Get an Word from OGDEN's dictionary")]
public String selectWord ()

 このWebメソッドは、既に紹介したものによく似ている。唯一異なるのは、WebMethod属性を公開して、外部から呼び出せるようにしている点だ。このメソッドは辞書データベースに接続し、次の図のようにランダムな単語を文字列として返す。

図3.5:selectWordメソッドを呼び出した結果
図3.5:selectWordメソッドを呼び出した結果

 selectWord Webメソッドに関するSOAP要求および応答の詳細を見るには、ここをクリック。このメソッドはGET、POST、SOAP要求を通じて個別に呼び出すことができる。

 selectWordを再度呼び出した結果は次の通り。返される単語が変わっていることに注意。

図3.4:selectWordメソッドを再び呼び出した結果
図3.4:selectWordメソッドを再び呼び出した結果

generateImage()

[WebMethod(Description="Generates a CAPTCHA Image and returns filename")]
public String generateImage ()

 このメソッドは画像を生成し、物理的にディスクに格納する。画像の生成に成功すると、次の図のようにファイル名を返す。

図3.6:生成された画像のファイル名
図3.6:生成された画像のファイル名

getCaptcha()

[WebMethod(Description="Returns a CAPTCHA Image in Base64-Encoding")]
publicbyte[] getCaptcha() 

 getCaptchaは、このWebサービスの統合機能を実現するコアメソッドである。CAPTCHAの機能を必要とするアプリケーションは、このメソッドを呼び出すことになる。このメソッドは、クライアントに対して画像をストリーミングするバイト配列を返す。invoke.aspxはこのWebメソッドを呼び出して、提供されたCAPTCHAを取得する。

図3.7:invoke.aspxとgetCaptchaメソッドの使用例
図3.7:invoke.aspxとgetCaptchaメソッドの使用例

 次の図は、invoke.aspxを何度か実行した結果である。さまざまな種類のCAPTCHA画像が描画されることに注目してほしい。

 本稿ではこのWebサービスのすべてのソースコードを提供しているので、自由に実装したり、試したりしてほしい。ただし、このサンプルではプロキシクラスとアセンブリをprocess.batで生成している。これは、Visual Studio.NETを使わずにプロキシクラスを生成する人にとっては便利な方法である。このプロセスは次のようになる。

図3.9:process.bat
図3.9:process.bat

 次にprocess.bat、invoke.aspx、captchaWebService.asmxのコードリストを示す。コードの詳細についてはコメントを見てほしい。

リスト:process.bat
wsdl /l:cs /o:captchaWebService.cs http://localhost/captchawebservice/captchaWebService.asmx?WSDL
     /n:captchaWebService
csc /out:captchaWebService.dll /t:library /r:system.web.dll,system.xml.dll,system.web.services.dll
     captchaWebService.cs
リスト:invoke.aspx
<%@ Page Language="c#" debug="True" %>
<%@ Import namespace="captchaWebService" %>
<script language="c#" runat="server">
publicvoid Page_Load(System.Object sender,System.EventArgs e)
{
Page.Response.BinaryWrite(new captchaWebService().getCaptcha());
}
</script>
リスト:captchaWebService.asmx
<%@ webservice class="captchaWebService" language="c#" %>
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Web.Services;
using System.IO;
using System.Data.OleDb;
using System.Drawing;
using System.Drawing.Imaging;
    ///<summary>
    /// This is the basic Service for CAPTCHA provision.
    ///</summary>
    
[WebService(Namespace="http://axisebusiness.com/webservices/")]
publicclass captchaWebService : System.Web.Services.WebService
{
    [WebMethod(Description="Returns a CAPTCHA Image in Base64-Encoding")]
    publicbyte[] getCaptcha() 
    {
        return getBytesFromRaster(Server.MapPath(generateImage()));
    }
    
    // Returns byte from Image file
    
    publicbyte[] getBytesFromRaster(string filename) 
    {            
        if(File.Exists(filename)) 
        {
            try
            {
                FileStream s =File.OpenRead(filename);
                byte[] bytes = newbyte[s.Length];
                s.Read(bytes, (int)0, (int)s.Length);
                return bytes;
            } 
            catch(Exception e) 
            {
                returnnewbyte[0];
            }
        } 
        else
        {
            returnnewbyte[0];
        }
    }
    
    [WebMethod(Description="Generates a CAPTCHA Image and returns filename")]
    public String generateImage ()
    {
        //Reading the parameter from session this time
        String strText = selectWord ();// = Session("param") 
        //Create the memory map 
        Bitmap raster;
        System.Drawing.Imaging.PixelFormat pixFormat = 
            System.Drawing.Imaging.PixelFormat.Format32bppArgb;
        // Select an memory image from file of 290x80px
        // in the backgrounds folder named backX.jpg
        Graphics graphicsObject;
        System.Drawing.Image imageObject = 
            System.Drawing.Image.FromFile(Server.MapPath(@"backgrounds\back" + 
            new Random().Next(9) + ".jpg"));
        // Creating the raster image object
        raster = new Bitmap (imageObject);
        //Creating graphics object
        graphicsObject = Graphics.FromImage(raster);
        // Instantiate object of brush with black color
        SolidBrush objBrush = new SolidBrush(Color.Black);
        Font objFont;
        int a;
        String myFont, str;
        //Creating an array for most readable yet cryptic fonts for OCR's
        // This is entirely up to developer's discretion
        String[] crypticFonts = new String[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; a<=strText.Length-1; a++)
        {
            myFont = crypticFonts[new Random().Next(a)];
            objFont = new Font(myFont, 20, FontStyle.Bold);
            str = strText.Substring(a, 1);
            graphicsObject.DrawString(str, objFont, objBrush, a*20, 35);
            graphicsObject.Flush();
        }
        String filename= new Random().Next().ToString() + ".gif";
        raster.Save(Server.MapPath(filename), System.Drawing.Imaging.ImageFormat.Gif);
        raster.Dispose();
        graphicsObject=null;
        return filename;
    
    } // End of Function
    // *************************************
    // Select word web method
    // Return type String of random word from dictionary
    // Dictionary is based on OGDEN's BASIC ENGLISH 
    // http://ogden.basic-english.org/basiceng.html
    [WebMethod(Description="Get an Word from OGDEN's dictionary")]
    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 web method
} // Ends Class

まとめ

 CAPTCHAは「Completely Automated Public Turing Test to Tell Computers and Humans Apart(コンピュータと人間を区別する完全に自動化された公開チューリングテスト)」の略であり、人間のふりをする自動ボットやインテリジェントエージェントからデジタル資産を守るためのテストである。この戦いは今後も続いていくだろう。CAPTCHAを破るためには、洗練されたアプリケーションと、より高度なOCR機能による、機械の「視覚」が新たな進化を遂げる必要がある。

 CAPTCHAは、障害者や弱視の人には敷居の高いテストである。したがって、W3Cのアクセシビリティガイドラインに従う必要がある。

 本稿は、スパムを排除するための科学的ソリューションに焦点を当てた記事シリーズの第1弾である。本シリーズの第2弾では、C#.NETでベイズ式テキスト分類APIライブラリを開発する方法について取り上げる。シリーズ最後となる第3弾では、そのベイズ式テキスト分類ライブラリを使用して、Webサービスを使ったスパムフィルタを実装してみる。読者の皆さんもぜひ実際に試していただきたい。

デモ

 このページからデモを体験できる。

参考資料

  1. CAPTCHAホームページ
  2. Breaking a visual CAPTCHA Greg Mori and Jitendra Malik, UC Berkeley Computer Vision Group
  3. [Telling Humans & Computers apart (to appear in CACM)[[http://www.cs.cmu.edu/~biglou/captcha.pdf]]
  4. CAPTCHA:Using Hard AI Problems for Security (Eurocrypt)
  5. Protect Your Online Forms By John Clyman
  6. CAPTCHA-ing the Spammer By Cade Metz

ニュース

  1. Human or Computer? Take This Test, The New York Times, December 10, 2002.
  2. Up to the Challenge: Computer Scientists Crack a Set of AI-Based Puzzles, SIAM News, November 2002.
  3. Robot solves Internet robot problem By Byron Spice, Pittsburgh Post-Gazette, October 21, 2001
  4. Computer or Human? New Programs can tell By Matt O'Brien, University of Miami Newspaper, November 20, 2001
  5. Can Hard AI Problems Foil Internet Interlopers? By Sara Robinson, SIAM News, April 2002
  6. Researchers battle e-mail stealing Web bots with identity checks By Mike Crissey, The Associated Press, December, 2002
  7. Computer Pioneer Aids Spam Fight, The BBC News, January, 2003
  8. Recognizing Objects in Adversarial Clutter: Breaking a Visual CAPTCHA (2003) Greg Mori, Jitendra Malik

チューリングテスト

  1. A. M. Turing (1950) Computing Machinery and Intelligence. Mind 49: 433-460.
  2. The Turing test page
  3. Alan Turing Homepage
  4. AI Glossary - Syracuse University
  5. Technical Solutions for Controlling Spam
  6. BaffleText:a Human Interactive Proof
  7. Gimpy High Level Description
  8. Gimpy Paper
  9. Telling Humans and Computers apart OR How Lazy Cryptographers do AI
  10. Luis von Ahn_ Manuel Blum_ John Langford_

関連団体

  1. Computer Science Dept., Carnegie Mellon University, Pittsburgh
  2. The UC Berkeley Computer Vision Group
  3. Shape Matching and Object Recognition
  4. Detecting Natural Image Boundaries
  5. British Computing Society Artificial Intelligence Group

その他

  1. Yahoo!でのEZGimpyの使用例
  2. Practical A.I. - Introduction - Ben Garcia
  3. Web Methods returning something else than XML?
  4. Sapience Validation(XML RPCベースのサービス)
  5. Sapienceの中核は、Paul Tremblettが『Dr Dobb's Journal』2003年10月号で発表した画像ジェネレータである。Dav ColemanがこれをXML RPCサービスに変換し、Sapienceシステムを開発した。
  6. View the Real World in Your Application, with TerraServer, by Karl Moore
  7. CityView App: Build Web Service Clients Quickly and Easily with C#, MSDN Magazine
  8. Demonstration of using Base64 encoding, in a Web Service using the .NET Framework, by Robert Chartier
  9. Baffling the Bots, by Lee Bruno

ボット関連のWebサイト

  1. http://www.runabot.com/
  2. http://www.activebuddy.com/
  3. http://members.aol.com/adamkb/aol/imbots
  4. http://www.pandorabots.com/pandora
  5. Botspot
  6. How to build a Bot Trap and keep bad bots away from a web site
  7. Robot Exclusion
  8. Computer Vision and Image Understanding: Palo Alto Research Center
  9. Stopping Spambots:A Spambot Trap
  10. Using Linux, Apache, mod_perl, Perl, MySQL, ipchains and Embperl, By Neil Gunton
  11. SECURITY and CRYPTOGRAPHY 15-827 Lecture #17
  12. OGDEN's BASIC ENGLISH
  13. Base64 content-Transfer-encoding
  14. CAPTCHAについて初めて言及した論文:
  15. L. Coates, H. S. Baird, R. Fateman, "Pessimal Print:a Reverse Turing Test," Proc., 6th IAPR Int'l
  16. Conf.On Document Analysis & Recognition, Seattle, WA, Sept. 10-13, 2001.
  17. Hosted first professional event:1st NSF Int'l Workshop on HIPs, Jan. 9-11, 2002, Palo Alto, CA.
  18. ImageMagik: Image Manipulation API
  19. Securing passwords against dictionary attacks

この記事は参考になりましたか?

連載通知を行うには会員登録(無料)が必要です。
既に会員の方はを行ってください。
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Adnan Masood(Adnan Masood)

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

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/34 2005/10/05 16:48

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー