Hatena::ブログ(Diary)

赤羽橋日記 RSSフィード

2011-01-13

saアカウント

コーディングを行う上で、Web上からサンプルを探すなんてのは、当たり前のようにやっている思う。普通の(?)プログラマならそんなことはないが、経験・見識のないプログラマだったら、下手したらコピペで済ませるヤツもいるだろう。

むやみに管理者権限使うな。

たとえば、WebアプリなどでDB接続に管理者アカウントを使っているなんてのは論外。

当たりまえのことのように思えるが、管理者アカウントを使用しているサンプルコードが多すぎる。

ちなみに、以下はSQL Serverに対してDB接続するためのサンプルコードだが、全部「sa」で接続している。

http://support.microsoft.com/kb/317880(←これなんかMS

http://keicode.com/cgi/sql-server-driver-for-php-reference.php

http://blogs.msdn.com/b/osamum/archive/2010/09/27/php-ms-sql-server.aspx

http://www.triconsole.com/dotnet/sqlparametercollection_class.php

http://www.vacant-eyes.jp/tips/tadonet/040.aspx

http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?forum=7&topic=25169

http://homepage1.nifty.com/k-umezu/nikki/niiki000506.htm

http://www.geocities.jp/ak09z/vec/vba/xlodbc.htm

http://keicode.com/cgi/how-to-connect-to-mssql.php

http://d.hatena.ne.jp/yourvoice/?of=5

もちろん、サンプルはあくまでサンプルなので、利用する側のリテラシーが第一だが載せるほうも考えよう。

2010-11-19

「暗号化」と「ハッシュ」

「暗号化」と「ハッシュ」について、よく混同されていると思う。

ここで、一度定義を整理してみる。

ハッシュ・・・あるデータが与えられた場合にそのデータを代表する数値を得る操作

暗号化・・・第3者に内容を知られないように行う方法のうち、特別な知識なしでは読めないように変換する表記法

「ハッシュ」は「暗号化みたいなもの」という説明をよく聞くが、正確には異なる。

確かに、元々の意味や実体を一見してわかりづらくするという観点から言えば、

「ハッシュ」も暗号化の一部として捉えることもできなくない。

しかしながら、ハッシュとは本来「秘匿」を目的にしたものではない。

あるデータを端的に表すために行う特殊な計算で、概念としてはチェックサムとかチェックディジットとか

と同様なものだ。セキュリティの世界ではよく改ざんの検知に使用される。

このハッシュ化するアルゴリズムの代表的なものとして「MD5」と「SHA1」がある。

aaa」という文字列をMD5変換すると、「47bce5c74f589f4867dbd57e9ca9f808」となり、

SHA1変換すると「7e240de74fb1ed08fa08d38063f6a6a91462a815」となる。

そして、ポイントはハッシュは「不可逆」であるということ。

上記、「47bce5c74f589f4867dbd57e9ca9f808」から「aaa」を導くことは不可能なのだ。

暗号化は「第3者に内容を知られないようにする方法」である。

つまり、第3者以外、通信する本人と相手方は内容を知る必要がある(当然といえば当然だが)。

ハッシュは不可逆であるが故に、相手方すら内容がわからない。

「47bce5c74f589f4867dbd57e9ca9f808」を受け取っても、それから「aaa」を導くことが

不可能なため、秘匿通信という要件を満たさない。よって、これは暗号化とは呼べない。

よくMD5は脆弱だ。解読可能だ。という話が出ているが、

これも「47bce5c74f589f4867dbd57e9ca9f808」から直接なんらかの計算で「aaa」を

導くわけではなく、大量のサンプリングを得た結果から導くものだ。

通信するお互い(だけ)が内容を知る必要があるため、暗号は「可逆」だ。

それを可能にするのが「鍵」である。

平文を「鍵」を使用して特殊な計算をして暗号化する。

受け取った側はまた「鍵」を用いて暗号文を、これまた特殊な計算で平文にする。

この「鍵」は、送受信側で共通のものであったり、異なったものであったりする。

暗号化には必ず「鍵」が必要になる。

内容を秘匿するために「パスワードつきZIP」をかけて、メール送信することはよくある。

これも暗号化に他ならない。パスワードが「鍵」になるわけだ。

ハードディスクの暗号化もパスワード(鍵)を必ず必要とする。

古典的な暗号化の方法として、アルファベットを1文字ずらすなんていう方法もある。

あらかじめ、送信者と受信者でその約束を共有しておく。

abc」という内容を相手方に知らせるために「bcd」と送る。

相手方は1文字ずらしているということを知っているので、「abc」という内容

だということがわかる。

この場合、「一文字ずらず」という約束事が「鍵」になるわけだ。

当然、この程度のアルゴリズム(とまでは言えないが)であれば、

暗号文を見ただけで、あっという間に解読されてしまうだろうが、

現在使われている暗号化も原則は変わらない。

当人しか知り得ないものがあって、初めて暗号化が成立する。

アルゴリズムがいくら強力であっても、その「当人しか知りえないもの」が漏洩

してしまっては、基も子もない。

巷にはさまざまな暗号化ソリューションがあふれているが、

どんな優秀な製品を導入しようとも、この「鍵」管理を怠ってしまっては、

まったく意味のないものになってしまう。

ハッシュと暗号化の違いも含めて、一見難しそうだと敬遠しがちな部分だと思う。

これは、MD5だの、SHAだの、RSAだの、SSLだの、ビット長だのとアルゴリズムの

方にフォーカスがいきがちだからだと思われる。

しかしながら、原理・原則は単純なものなので、しっかりと把握したい。

2010-11-05 Visual Studio 2010 での ISAPI 開発

このたび、えらく昔に開発したISAPIフィルタを更新する必要がでてきた。そのため、開発環境も新たに Visual Studio 2010 (以下、VS2010) に移行することとした。さて、とりあえず、現状のプロジェクトを VS2010 で開いて、自動アップグレードを実行。

とくに問題なく終わった。さて、ビルド。すると、「afxisapi.h」がないと怒られる。どうやら、VS2008から ISAPI開発用のMFCラッパが無くなってしまったようだ。

CHttpServer not included in Visual Studio 2008

http://blogs.msdn.com/b/jpsanders/archive/2007/12/10/chttpserver-not-included-in-visual-studio-2008.aspx

この記事によると、必要なファイルやライブラリをVS2005が頂戴すればいいらしいが、MFCをスタティックリンク設定しなければならないらしい。

これは、これで問題がある。なんとか、MFCを共有ライブラリとしてビルドしながら、従来通りのAFXラッパを使用してVS2010でISAPIの開発ができないものか。

いろいろ、ためしてみたところ、上記、記事にあるヘッダファイルやライブラリをVS2005から頂戴してくるところはそのままに、MFC共有ビルド可能なようにするには、以下のような定義を StdAfx.h に入れることで、可能なようだ。

namespace ATL
{
#ifndef _CONVERSION_DONT_USE_THREAD_LOCALE
typedef UINT (WINAPI *ATLGETTHREADACP)();

inline UINT WINAPI _AtlGetThreadACPFake() throw()
{
	UINT nACP = 0;
	LCID lcidThread = ::GetThreadLocale();
	char szACP[7];
	if (::GetLocaleInfoA(lcidThread, LOCALE_IDEFAULTANSICODEPAGE, szACP, 7) != 0)
	{
		char* pch = szACP;
		while (*pch != '\0')
		{
			nACP *= 10;
			nACP += *pch++ - '0';
		}
	}
	if (nACP == 0)
	nACP = ::GetACP();

	return nACP;
}
inline UINT WINAPI _AtlGetThreadACPReal() throw()
{
	return( CP_THREAD_ACP );
}

extern ATLGETTHREADACP g_pfnGetThreadACP;

inline UINT WINAPI _AtlGetThreadACPThunk() throw()
{
	OSVERSIONINFO ver;
	ATLGETTHREADACP pfnGetThreadACP;
	ver.dwOSVersionInfoSize = sizeof( ver );
	::GetVersionEx( &ver );
	if( (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) && (ver.dwMajorVersion >= 5) )
	{
		pfnGetThreadACP = _AtlGetThreadACPReal;
	}
	else
	{
		pfnGetThreadACP = _AtlGetThreadACPFake;
	}
	InterlockedExchangePointer( reinterpret_cast< void** >(&g_pfnGetThreadACP), reinterpret_cast< void** >(pfnGetThreadACP) );

	return( g_pfnGetThreadACP() );
}

ATLGETTHREADACP g_pfnGetThreadACP = _AtlGetThreadACPThunk;

#else

inline UINT WINAPI _AtlGetConversionACP() throw()
{
	return( CP_ACP );
}

#endif
};  

お困りの方、試してみてください。

2010-04-23

FTPクライアントソフトのパスワード盗難

さて、Gumblar。さまざまなFTPクライアントソフトからパスワードを盗み出す。IEなんかのオートコンプリートの情報からも盗み出す。オートコンプリートについては前回の記事に書いたとおり前々から危険性があった。おそらくこの方法に近いことをしてパスワードを盗んでいるのだろう。

被害にあったFTPクライアントアプリは結構大きな数で、有名どころはほとんど含まれている。その中にFFFTPも入っている。これはオープンソースなので容易に解析される。FFFTPはホストごとに設定したパスワード情報を暗号化してレジストリに格納している。


f:id:digisecdog:20100423163310j:image


デコード方法もソースを見ればそこに書かれているので、その通りやればパスワードを平文でいとも簡単に取得できる。

以下は以前のバージョン(ver.1.96d)のソースで、デコード処理の部分。

static void DecodePassword(char *Str, char *Buf)
{
  unsigned char *Get;
  unsigned char *Put; 
  int Rnd;
  int Ch;

  Get = (unsigned char *)Str;
  Put = (unsigned char *)Buf;
  while(*Get != NUL)
  {
    Rnd = ((unsigned int)*Get >> 4) & 0x3;
    Ch = (*Get & 0xF) | ((*(Get+1) & 0xF) << 4);
    Ch <<= 8;
    if((*Get & 0x1) != 0)
      Get++;
    Get += 2;
    Ch >>= Rnd;
    Ch = (Ch & 0xFF) | ((Ch >> 8) & 0xFF);
    *Put++ = Ch;
  }
  *Put = NUL;
  return;
}

今回のGumblar騒ぎでFFFTPはバージョンアップされた。現在の最新バージョンはVer.1.97aだ。このバージョンから暗号化にAESが使用されている。

AESだから安心なのではなく重要なのはキーだ。本人しか知り得ないキーを暗号化の際に使用することが大事なわけで、そのあたりも開発者は当然ながらわかっているので、「マスターパスワードを設定してください。」と言っている。この「マスターパスワード」が使用されてFTPパスワードがAES暗号化される。

いまさらながら、前回までのバージョンについて、アルゴリズム上、キー設定もなく、デコードコードが公開されている状態で「暗号化」とは.....

「マスターパスワード」はSHA1ハッシュ後、レジストリに格納している。毎回、起動時に設定したパスワードを入力させ、入力値のSHA1ハッシュとレジストリに設定されているハッシュとを比較している。これは認証処理の王道だね。

ちなみに以下が新バージョンのソース内のデコード処理部分のコード。

static void DecodePassword3(char *Str, char *Buf, const char *Key)
{
  char *Get;
  unsigned char *EncBuf;
  size_t StrLen;
  size_t IvIndex;
  size_t EncBufIndex;
  size_t EncBufLen;
  unsigned char AesKey[32];
  unsigned char AesCbcIv[AES_BLOCK_SIZE];
  aes_decrypt_ctx Ctx;

  Buf[0] = NUL;

  Get = Str;
  StrLen = strlen(Str);

  if(AES_BLOCK_SIZE * 2 + 1 < StrLen)
  {

    EncBufLen = (StrLen - 1 ) / 2 - AES_BLOCK_SIZE;
    if((EncBuf = malloc(EncBufLen)) != NULL)
    {
      for(IvIndex = 0; IvIndex < AES_BLOCK_SIZE; IvIndex++)
      {
        AesCbcIv[IvIndex]  = hex2bin(*Get++) << 4;
        AesCbcIv[IvIndex] |= hex2bin(*Get++);
      }

     if(*Get++ == ':')
     {
       if(CreateAesKey(AesKey, Key) == SUCCESS)
       {
         aes_decrypt_key(AesKey, 32, &Ctx);

         for(EncBufIndex = 0; EncBufIndex < EncBufLen; EncBufIndex++)
         {
           EncBuf[EncBufIndex]  = hex2bin(*Get++) << 4;
           EncBuf[EncBufIndex] |= hex2bin(*Get++);
         }

         if(aes_cbc_decrypt(EncBuf, Buf, EncBufLen, AesCbcIv, &Ctx) == EXIT_SUCCESS)
         {
           Buf[EncBufLen] = NUL;
         }
       }
     }

     free(EncBuf);
   }
 }
 return;
}

マスターパスワードを設定しなければ、↑の第3引数が固定(空文字かな)になるので意味がない。なので、FFFTPを使用している人は「バージョンアップしたから大丈夫」ではなく、ちゃんと「マスターパスワード」を設定しましょう。



と、それはそれで置いておいて、言いたいのはこれではなく、同じパスワードを使いまわすな!ということ。さんざんセキュリティ上よろしくないと言われているけど、なかなか徹底できていないんじゃないかな。

今回の場合だと、この「マスターパスワード」に設定したパスワードと同じパスワードをどこかのまったく別のサイトで使用していて、IEのオートコンプリートに保存されていたら、前回の記事で書いたこととの合わせ技でFTPパスワードが盗まれてしまう。

確かにパスワードをいっぱい覚えるのは面倒くさいけどね。でも、とくにサイト管理をしているような人はそれなりの責任を背負っているわけだから、しっかりと意識してね。

2009-09-04

IEのオートコンプリートは無効にしたほうがいいことを再認識した

毎回パスワード入力するのがめんどい。IEとかにはユーザが入力したIDとパスワードを記憶させることができる。キーパンチしないのでキーロガーの対策にはいいのではと思いがち。でも、このオートコンプリートの情報は簡単に取り出せるといわれて久しい。どのくらい簡単なんだろうと思って調べてみた。

保存されているパスワード情報を確認できるソフトは昔からけっこうある。


[HideSeek]

http://www.vector.co.jp/soft/win95/util/se312032.html

[認術修業]

http://www.vector.co.jp/soft/win95/util/se290270.html


ほんとに簡単に取り出せそうだ。

このIEオートコンプリートやOutlookのクレデンシャルの情報はWindowsによって暗号化され、レジストリの保存されている。この部分を司さどっているのがProtected Storage Service。このサービスがクレデンシャル情報の暗号・複合を行っているが、APIが用意されていて、基本的にどんなアプリケーションからも利用できるようだ。

このAPIを利用してIE7以降からオートコンプリート文字列を取得するサンプルがあった(↓)。


[IE7におけるパスワード等の操作要領]

http://www.sapporoworks.ne.jp/ie7_pass/


ソースをダウンロードしたところ、実はそのままでは動かなかったがチョチョッと修正したら見事に動いた。ソースを見たところ、ログインしているユーザのIEのオートコンプリート情報は「HKEY_CURRENT_USERS\Software\Microsoft\Internet Explorer\IntelliForms\Storage2」に保存されているらしい。


f:id:digisecdog:20090904165940j:image


値の名前がURLハッシュ値SHA1)。値がオートコンプリート情報で暗号化されバイナリで保存されている。URL部分はハッシュなので不可逆。じゃあ、どうやってURL文字列を取り出しているかというと、実はアクセスされたURLの履歴情報を別途取得し、その値をSHA1でハッシュしたものと比較しているのだ。

このURL履歴情報はCOMの「IUrlHistoryStg2」インターフェースを使用することで取得可能だ。URLが判明したところで、肝心の暗号化されているオートコンプリート情報だが、「CryptUnprotectData」という「Crypt32.dll」に含まれるAPI一発で複合化できてしまうらしい。

いや、やってみると、ほんとに簡単だ。以下取得したオートコンプリート情報。なんだが、平文でパスワードが表示されているとゾッとする。


f:id:digisecdog:20090904170000j:image


今更ながらこれは怖い。そういえば Windows Fire Wall の穴もそれ用のAPIあっさり空けることができたっけ。Windows APIってけっこうオープンだ。なんか制限できないのかな。実行しているプロセスの権限トークンを使ったファイル単位でのファイルシステムのアクセス制御ではなく、もっと、なんかこう、MSの証明書がついてないプログラムからのアクセスは不可とか。そもそも公開APIを絞るとか。開発できるアプリの柔軟性とか拡張性とか考えるとなかなか難しいのかな。

ちなみに、IEのオートコンプリートを無効にするには、メニューバーから「ツール」-「インターネットオプション」-「コンテンツ」タブ-「オートコンプリート」-「設定」で行うことができる。


f:id:digisecdog:20090904171228j:image