MSXML2.xmlhttpで送信したデータがPHP側でおかしくなる

解決


まさあき  2007-05-10 12:30:14  No: 98713

VB6からMSXML2.xmlhttpを利用しDESで暗号化したデータを送信。
その後php側で復号化する処理をしています。

短い電文は問題なかったのですが少し長い物に関しては復号化で
PHPで文字化けするようになりました。

VB6側で作成した暗号文(16進数に変更してあります。)
E91EBF24F61D481E82DDF83849846DA0F459BCB47A3744487A338E3C361D7AA604F102581C396989D888E3A14DACB33F2839959F4E2E23B7DB30B611 2   78E1324A0884AE7CF0D9C48

PHP側のPOSTで受け取った時の暗号文
E91EBF24F61D481E82DDF83849846DA0F459BCB47A3744487A338E3C361D7AA604F102581C396989D888E3A14DACB33F2839959F4E2E23B7DB30B611 5C2 78E1324A0884AE7CF0D9C48

スペースで空けている部分が異なる部分です。
VB6  では  2
PHP  では  5C2

5Cが不必要なものです。
これが入っている為復号化の時に文字化けがしてしまいます。

VB6側で送信前のバイト配列の内容は問題ありませんでした。
PHP側の問題かもしれません。

よろしくお願いします。

環境  VB6SP6 , PHP5.2.1 , WinXP

Public Function Execute(ByVal sql As String) As clsMysql
    
    Dim cDes                As clsPhpDES
    Dim xmlhttp             As MSXML2.xmlhttp
    Dim cMysql              As clsMysql
    
    Dim sqlByte()           As Byte
    Dim SendByte()          As Byte
    Dim getByte()           As Byte
    
    '送信データ電文作成
    Call StringAppend("&q=")
    '暗号化するかどうか
    If EncryptFlg = False Then
        Call StringAppend(sql)
    Else
        Set cDes = New clsPhpDES
        sqlByte = cDes.Triple_Des_Encrypt(DesKey, sql)
        If InStr(Command, "-t") > 0 Then
            Debug.Print cDes.StringToHex(sqlByte)
        End If
        Call ByteAppend(sqlByte)
        Call StringAppend("&enc=1")
        Set cDes = Nothing
    End If
    Set xmlhttp = New MSXML2.xmlhttp
    'POSTで対象URLに接続    3番目の引数は同期モードか非同期モードかの区別
    Call xmlhttp.Open("POST", TargetURL, False)
    'ヘッダー送信
    Call xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
    '文字コード変換(Shift_JISからUTF-8へ)
    SendByte = ShiftJIStoUFT8(SendNoSqlByte)
    If InStr(Command, "-t") > 0 Then
        Set cDes = New clsPhpDES
        Debug.Print cDes.StringToHex(SendByte)
        Set cDes = Nothing
    End If

    '送信
    Call xmlhttp.send(SendByte)
    'データを受け取る
    getByte = xmlhttp.responseBody()

    Set xmlhttp = Nothing
    'デバック用
    Call debug_Chk(getByte)
    '受け取ったバイナリーデータを加工する
    Set cMysql = New clsMysql
    '暗号化しているかどうかセットする
    cMysql.setEncrypt = EncryptFlg
    If cMysql.DataChg(getByte) = True Then
        Set Execute = cMysql
    End If

End Function

Private Sub StringAppend(ByVal s As String)

    Dim adoStream               As ADODB.Stream
    Dim NewByte()               As Byte
    Dim i                       As Long
    
    Set adoStream = New ADODB.Stream
    With adoStream
        .Charset = "Shift_JIS"
        .Type = adTypeText
        Call .Open
        Call .WriteText(s)
        .Position = 0
        .Type = adTypeBinary
        NewByte = .Read()
        Call .Close
    End With
    Set adoStream = Nothing
    
    For i = 0 To UBound(NewByte)
        ReDim Preserve SendNoSqlByte(UBound(SendNoSqlByte) + 1)
        SendNoSqlByte(UBound(SendNoSqlByte)) = NewByte(i)
    Next
End Sub
Private Sub ByteAppend(ByRef data() As Byte)

    Dim i                       As Long

    For i = 0 To UBound(data)
        ReDim Preserve SendNoSqlByte(UBound(SendNoSqlByte) + 1)
        SendNoSqlByte(UBound(SendNoSqlByte)) = data(i)
    Next
End Sub

Private Function ShiftJIStoUFT8(ByRef data() As Byte) As Byte()

    Dim adoStream           As ADODB.Stream
    
    Set adoStream = New ADODB.Stream
    With adoStream
        .Charset = "UTF-8"
        .Type = adTypeBinary
        Call .Open
        Call .Write(data)
        .Position = 0
        ShiftJIStoUFT8 = .Read()
        Call .Close
    End With
    Set adoStream = Nothing
End Function


魔界の仮面弁士  2007-05-10 18:54:45  No: 98714

> 5Cが不必要なものです。
5C って、エスケープ文字としても使われる「\」のコードですね…。

> VB6側で送信前のバイト配列の内容は問題ありませんでした。
このような時は、どの時点でデータが破損したかを、正確に突き止める必要があるでしょう。

(a) そもそも、処理前の元データは正しいのか?
(b) エンコードした後のバイト配列の内容は正しいか?
(c) それを xmlhttp.send した際、Web 上に流されたデータは正しいか?
(d) Web サーバ側で受け取ったとき、それをデータ破損せずに受け取れているか?

なお、手順 c の確認には、フリーソフトの InetSpy 等が便利です。

> PHP側の問題かもしれません。
もし、上記 d で問題があるとしたら、この掲示板では板違いですね。

> Private Function ShiftJIStoUFT8(ByRef data() As Byte) As Byte()
これ、プロシージャの名前のスペルミスはさておき、実装がおかしいです。
バイナリモードで書きこんで、バイナリモードで読み直しているだけなので、
何の変換にもなっていません。(Charset プロパティは、テキストモード専用です)

Shift_JIS バイナリを UTF-8 バイナリにするなら、この部分の処理は、
下記のいずれかに置き換える必要があるでしょう。

=== 案(1) String → UTF-8 Binary にする手法 ===

1. Shift_JIS バイナリを、StrConv 関数の vbUnicode で、
  VB の標準的な文字列に変換する。
2. それを adTypeText / UTF-8 モードの Stream に WriteText する。
3. その Stream の Position を 0 に戻す。
4. Type プロパティを、adTypeBinary に変更。
5. 先頭の BOM 3 バイトも必要なら、Position は 0 のままにしておき、
  先頭の EF BB BF が不要なら、Position を 3 にしておく。
6. Read メソッドで取り出せば、UTF-8 バイナリの取得が完了。

=== 案(2) Shift_JIS Binary → UTF-8 Binary にする手法 ===
こちらは、任意の文字コード変換に使える手法です。

1. adTypeBinary で開いた Stream を用意する。
2. そこに、変換元のバイナリ(Shift_JISデータ)を Write する。
3. Position を 0 に戻す。
4. Type を adTypeText に変更。
5. Charset に、変換元の文字コード "Shift_JIS" を指定。
6. ReadText で、VB の標準的な文字列として取得する。
7. もうひとつ、別の Stream を用意し、adTypeText / UTF-8 モードで開いておく。
8. 手順 6 で得た文字列を、手順 7 の Stream に WriteText。
  あとは、案(1)の手順 2 以降の手法と同様。


まさあき  2007-05-11 23:59:38  No: 98715

魔界の仮面弁士さま

スペルミス指摘されるまでまったく気づきませんでした・・・・
恥ずかしい限りです。

ADODB.Streamの変換手順ありがとうございました。
案(2)今後使えそうなので関数化しました。

過去ログ内容を見たのですが前回掲ヲしたプログラムではsendの際Byte配列を渡していたので
結局Shift_JISのコードの入ったものを送っていたんですね。

http://madia.world.coocan.jp/cgi-bin/VBBBS2/wwwlng.cgi?print+200501/05010059.txt

>「内部処理形ョがStringのVariant型」をsendすると、
>文字列がUTF-8で送信されます。
>この場合はStrConv関数を併用して、sendの引数に、
>「内部処理形ョがByte配列のVariant型」を渡してみてください。

>(a) そもそも、処理前の元データは正しいのか?
VB側で秘密Key(24Byte)と平文をunicode→shift_jisに変換後3DESで暗号化。
変換した時点で文字として意味のないバイナリデータになります。

>(b) エンコードした後のバイト配列の内容は正しいか?
単体でVB6版とPHP版で同じキーで同じ文字列を暗号化したものは同じ内容のバイト配列になりました。
今回の「5C」が入らないものをPHP側で作成し複合化するとVB側で暗号化した文字列が出てきました。

>(c) それを xmlhttp.send した際、Web 上に流されたデータは正しいか?
InetSpy導入しました。
VB6側でMSXML2.XMLHTTPのsendで送る時のSendByteの内容をウォッチリストで確認しました。
sendbyte(64)「17=&h11」
sendbyte(65)「39=&h27」
になっていて「92=&h5C」が入っていませんでした。

PHP側のスクリプトでPOSTで受け取った物を16進数に変換して出力。
不必要な「5C」が混入していました。

InetSpyの情報
リクエスト情報
test=・ソ$・Hみ・I・瑶Y軸z7DHz3・6zヲ・X9i華遺@M?(9福N.#頚0カ'・$焉E舅

応答情報
 16進数データ: E91EBF24F61D481E82DDF83849846DA0F459BCB47A3744487A338E3C361D7AA604F102581C396989D888E3A14DACB33F2839959F4E2E23B7DB30B6115C278E1324A0884AE7CF0D9C48
受信データ:
・ソ$・Hみ・I・瑶Y軸z7DHz3・6zヲ・X9i華遺@M?(9福N.#頚0カ\'・$焉E舅

>(d) Web サーバ側で受け取ったとき、それをデータ破損せずに受け取れているか?
ローカル、レンタルサーバーでも同じ動きをします。
「5C」が付加される理由がわかりません。
これさえなければデータは破損していないと思うのですが。

(c)で確認のために利用したソースです。

***********************************************************
VB6ソース
***********************************************************
Option Explicit
Private Const TargetURL     As String = "http://127.0.0.1/test.php"

Private Sub Form_Load()
    Dim xmlhttp             As Object
    Dim SendByte            As Variant
    Dim desByte()           As Byte
    Dim getByte()           As Byte
    Dim bSendByte()         As Byte
    
    Set xmlhttp = CreateObject("MSXML2.XMLHTTP")
    With xmlhttp
        SendByte = "": getByte = "": desByte = "": bSendByte = ""
        Call .open("POST", TargetURL, False)
        Call .setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
        desByte = HexToByte("E91EBF24F61D481E82DDF83849846DA0F459BCB47A3744487A338E3C361D7AA604F102581C396989D888E3A14DACB33F2839959F4E2E23B7DB30B611278E1324A0884AE7CF0D9C48")
        Call StringAppend(bSendByte, "test=")
        Call ByteAppend(bSendByte, desByte)
        SendByte = bSendByte
        Call .send(SendByte)
        getByte = .responseBody()
    End With
    Set xmlhttp = Nothing
End Sub

Private Sub StringAppend(ByRef addByte() As Byte, ByVal s As String)
    Dim adoStream               As Object
    Dim NewByte()               As Byte
    Set adoStream = CreateObject("ADODB.Stream")
    With adoStream
        .Type = 2: .Charset = "SHIFT_JIS": Call .open: Call .Writetext(s): .position = 0
        .Type = 1: NewByte = .Read(): Call .Close
    End With
    Set adoStream = Nothing
    Call ByteAppend(addByte, NewByte)
End Sub

Private Sub ByteAppend(ByRef addByte() As Byte, ByRef data As Variant)
    Dim i                       As Long
    For i = 0 To UBound(data)
        ReDim Preserve addByte(UBound(addByte) + 1): addByte(UBound(addByte)) = data(i)
    Next
End Sub

Public Function HexToByte(ByVal s As String) As Byte()  '16進数表記の文字列をバイト配列に
    Dim NewByte()                  As Byte, i As Long
    NewByte = ""
    For i = 1 To Len(s) Step 2
        ReDim Preserve NewByte(UBound(NewByte) + 1): NewByte(UBound(NewByte)) = CLng("&h" & Mid(s, i, 2))
    Next
    HexToByte = NewByte
End Function

***********************************************************
PHPソース
***********************************************************
<?php
$test = $_POST["test"];

echo "\n 16進数データ: ";
echo stringToHex( $test );
echo "\n受信データ:\n";
echo $test ;

function stringToHex ($s) {
  $hexes = array ("0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F");
  for ($i=0; $i<strlen($s); $i++) { $r .= ($hexes [(ord($s{$i}) >> 4)] . $hexes [(ord($s{$i}) & 0xf)]); }
  return $r;
}
?>


まさあき  2007-05-12 05:32:02  No: 98716

phpソースに下記のものを追加で解決できました。
PHP側のマジッククオートがONのためバイナリの意味のないデータでしたが
エスケープされてしまったようです。

VB6の送信データを下記のように変えても前に「5C」が付着します。
        'desByte = HexToByte("27")
        'desByte = HexToByte("5C")

-----phpソース---------
$test = stripslashes($_POST["test"]);

完全にこれは(d)の問題でした。
板違いですね。
またまたご迷惑をおかけしました。

魔界の仮面弁士さまADODB.Streamの利用方法
本当に勉強になりました。
ありがとうございます。


魔界の仮面弁士  2007-05-12 05:36:18  No: 98717

>> VB6側でMSXML2.XMLHTTPのsendで送る時のSendByteの内容をウォッチリストで確認しました。
> sendbyte(64)「17=&h11」
> sendbyte(65)「39=&h27」
> になっていて「92=&h5C」が入っていませんでした。

入っていないのが正しいのでしょうか?
それとも、入っているのが正しいのでしょうか?

入っているのが正しいなら、VB 側の事前処理上の問題でしょうね。

逆に入っていないのが正しいなら、何らかのモジュールの障害等により、
そのデータが、Send で送られる時に化けてしまっているか…、または
PHP 側で受信するときの処理方法に問題がある、ということでしょう。

> InetSpyの情報
> リクエスト情報
非可読文字列を掲示板に貼りつけないでくださいませ。
他のテキスト部に悪影響を与える可能性がありますので。

というか、送信データが非可読のバイナリになっている時点で、何かがおかしいです。

私は PHP の知識が無いので判断が付かないのですが、お使いの Web サーバは、
本当に application/x-www-form-urlencoded なデータを要求しているのでしょうか? 
(なにか別の Content-Type を要求されていたりはしませんか?)

もし、本当に Content-Type: application/x-www-form-urlencoded が要求されているなら、
バイナリデータは流せないでしょう。「URL エンコードされた ASCII データ」が必要です。

> VB6ソース
あれ。前のコードでは、『文字コード変換(Shift_JISからUTF-8へ)』と
ありましたが……今回はそれに相当する処理が無くなっていますね。

とりあえず、URL エンコードが必要かどうかは別としても、その Web サーバ側では、
どの文字コードのデータが送信されてくることが期待されているのでしょうか?
それによって、文字コード変換処理の部分が大きく変わってくるかと思います。

> PHPソース
私は PHP の文法を全く知らないのですが、こちらはノーコメントで。

ただ、PHP 側にも手を加えられるなら、バイナリ値を送信する代わりに、
(たとえば 16 進数表現に変更するなどして)ASCII テキストとして送信し、
PHP 側で、それをバイナリに復元するような設計にするというのはどうでしょう?
逃げの手ではありますが、これなら 0x5C が入る余地は無さそうですし。


まさあき  2007-05-12 09:19:06  No: 98718

>非可読文字列を掲示板に貼りつけないでくださいませ。
>他のテキスト部に悪影響を与える可能性がありますので。

掲示板の管理者様、皆様、大変ご迷惑をおかけしました。
今後気をつけます。

>送信データが非可読のバイナリになっている時点で、何かがおかしいです。

下記事情により非可読バイナリにしています。
少し脱線しますが・・・・・

///////////////////////////////
1.友人が経営する店でネットで確認できる会員制ポイントシステムを導入したい。
2.趣味程度で触っていたPHPで管理画面を作成。
3.PHPで管理画面を作成するも制御面やデザイン時間がかかる。セッションの管理も面倒でした。
4.VBからデータベースにアクセスする方法に切り替える(MyODBC経由)。
5.ところがレンタルサーバーによってはMYSQLの標準ポート3306が閉じられている。
6.VBからPHPスクリプトにアクセスしそこからMySQLの情報を取り出しVB側に渡す。
  PHPスクリプトがアダプターの役割をします。
7.問題点1:安いレンタルサーバーを利用しているのでSSLが使えない。
8.7の事情によりVBとPHPのやり取りを暗号化しようという考えになりました。
///////////////////////////////

6内にデータベース接続情報を持たせても良かったのですが外部アクセスでクエリーを
はじらせられたらまずいのでVB側からデータベース接続パラメーターを渡すようにしました。

VB側からはクエリーをMSXML2.xmlhttpでsendしresponseBodyで受け取ったデータを加工クラスに
渡すだけでフィールド名Key付きオブジェクトコレクションを生成できるようにしました。

ポイントデータやブログデータに関しては個人情報などの情報が付加されていないのですが顧客
情報に関しては個人情報満載です。
登録時やデータ検索時に平文でやり取りは盗聴の可能性があります。
そこで特定のクエリーや特定の結果だけ暗号化すれば盗聴の可能性がなくなると思いました。
(↑の心配していましたがInetSpy知りませんでした。) 

登録時
クライアント(insert into userm values('0115','48aa','まさあき','061515','大阪')etc )
↓  ↑結果(Mysqlの情報)
WWWサーバー

データ取得時
クライアント(select * from userm where id='0115')
↓  ↑結果('0115','48aa','まさあき','061515','大阪')
WWWサーバー

POSTで送る内容
サンプル
host=localhost&port=3306&login=XXX<暗号化>XXX&etc=XXX<暗号化>XXX

上記の理由で非可読のメッセージを送りたかったのです。

3番以降は私の勝手な自己満足で製作に取り掛かっています。
私の気づいていない問題点などありましたらご指摘くださいませ。

>本当に application/x-www-form-urlencoded なデータを要求しているのでしょうか? 
>(なにか別の Content-Type を要求されていたりはしませんか?)
>もし、本当に Content-Type: application/x-www-form-urlencoded が要求されているなら、
>バイナリデータは流せないでしょう。「URL エンコードされた ASCII データ」が必要です。

この辺勉強不足なので・・・
出直してきます。


魔界の仮面弁士  2007-05-12 19:43:48  No: 98719

ありゃ。入れ違いで解決してたんですね。

> 6.VBからPHPスクリプトにアクセスしそこからMySQLの情報を取り出しVB側に渡す。
>   PHPスクリプトがアダプターの役割をします。
私も VB6 で同様の実装を行った事があります。サーバ側が IIS だったので、あまり参考には
ならないと思いますが、その時には ADODB.Recordset を直接交換していました。
受け取った側は Call rs.Open(stream) だけで開きなおせますし、更新の手間も楽だったので。
http://support.microsoft.com/kb/296772/ja

非IIS だと、SOAP でデータ交換する手法もありますが…VB6 の場合は手間がかかるんですよね。
http://www.microsoft.com/japan/msdn/vstudio/downloads/soaptoolkit/

> 7.問題点1:安いレンタルサーバーを利用しているのでSSLが使えない。
> 8.7の事情によりVBとPHPのやり取りを暗号化しようという考えになりました。

3DES で施錠しているようなので、データを解読される可能性は低いと思われますが、
そのキーが固定値になっていたりはしませんか?

たとえばログイン要求のように、同一リクエストを繰り返すページがあるとすれば、
そのリクエスト内容が毎回一緒であると、盗聴者による「なりすまし」を防げません。
同じデータを送信すればログインできる仕様になっているなら、ログイン情報が
平文であっても暗号化データであっても、攻撃者にとっては同じことですから。

# 私の場合は実装が面倒だったので、結局、SSL を導入しました。(^_^;)

>> もし、本当に Content-Type: application/x-www-form-urlencoded が要求されているなら、
>> バイナリデータは流せないでしょう。「URL エンコードされた ASCII データ」が必要です。
> この辺勉強不足なので・・・

クライアント側は(汎用のブラウザではなく)自作の VB6 製ツール、サーバも固定的となれば、
その間で交換されるデータ形式は、独自のフォーマットでも構わない、という見方もありますね。

ただ本来であれば、Content-Type: application/x-www-form-urlencoded にて POST されるデータは、
通常は「name1=value1&name2=value2」のような US-ASCII 形式のデータとなるはずです。
この場合、名前や値に「=」や「&」あるいはバイナリを含める事ができないため、そのような
データが含まれる場合には、URL エンコードが施されて送信されます。

これにより、「-」「_」「.」および英数字はそのまま送信されますが、空白文字は「+」となり、
その他のバイナリは「%00」〜「%FF」形式のテキストに変換されて送られる事になります。
たとえば、アンパサンド(&)記号は「%29」となり、チルダ(~)記号は「%7E」となります。

なお、URL エンコードされたバイナリを送る以上、文字列を送る事も可能ですが、
文字の符号化に関する規定は特に定義されておらず、どの文字コードが使われるかは、
処理系依存となっています。たとえば、"弁士"という漢字 2文字を name という名前で送る場合、
EUC-JP なら「name=%CA%DB%BB%CE」、UTF-8 なら「name=%E5%BC%81%E5%A3%AB」となります。


まさあき  2007-05-13 15:17:32  No: 98720

魔界の仮面弁士さま

本当にわかりやすい説明ありがとうございます。
いろいろな知識を吸収できました。

>非IIS だと、SOAP でデータ交換する手法もありますが…VB6 の場合は手間がかかるんですよね。
>http://www.microsoft.com/japan/msdn/vstudio/downloads/soaptoolkit/

SOAPの名前は聞いたことがあったのですが難しそうなのでPASSしていました。
今回のプログラムが完成したらチャレンジしてみます?!
余力があればAESも作成してみたいです。
http://www.ipa.go.jp/security/enc/CRYPTREC/fy15/cryptrec20030425_spec01.html

>たとえばログイン要求のように、同一リクエストを繰り返すページがあるとすれば、
>そのリクエスト内容が毎回一緒であると、盗聴者による「なりすまし」を防げません。
>同じデータを送信すればログインできる仕様になっているなら、ログイン情報が
>平文であっても暗号化データであっても、攻撃者にとっては同じことですから。

現在固定24byteキーにしています。
考えられるアイデアとしてはPOSTでデータを送る際ランダムにキーを生成することぐらいしか
思い浮かびません。

クライアント
(固定20Byte(秘密鍵)+ランダム4Byte)

サーバー
(固定20Byte(秘密鍵)+POSTで受け取った4Byte)で復号化

サーバー
結果データを送るときは(固定20Byte(秘密鍵)+POSTで受け取った4Byte)で暗号化

クライアント
メモリーに残っている4Byteキーを固定20Byteとあわせて復号化

>ただ本来であれば、Content-Type: application/x-www-form-urlencoded にて POST されるデータは、
>通常は「name1=value1&name2=value2」のような US-ASCII 形式のデータとなるはずです。
>この場合、名前や値に「=」や「&」あるいはバイナリを含める事ができないため、そのような
>データが含まれる場合には、URL エンコードが施されて送信されます。

解決してからいろいろなクエリーを送っていたのですが問題発生しました。
途中でクエリー切れていたのです。
送信POSTを確認したところ「&」(&h26=38)でカットされていました。
復号化も途中で失敗。
対策として前回の暗号化の部分を下記のように変更しました。
        sqlByte = cDes.Triple_Des_Encrypt(DesKey, sql)
        sqlByte = Byte_Replace(sqlByte, Chr(38), "00000000")  '&
        sqlByte = Byte_Replace(sqlByte, Chr(61), "11111111")  '=
暗号化しているデータなので画像データのように連続して8Byte同じデータが続かない、
また8Byte単位で暗号化しているので連続した8バイトデータはないという考えで安易に対応しました。
盲点があるかもしれません。
PHP側もこの対応に伴って修正しました。

>たとえば、アンパサンド(&)記号は「%29」となり、チルダ(~)記号は「%7E」となります。
今回の場合下記の認識でよろしいでしょうか。

クライアント:「name1=value1&name2=valu&e2」

サーバー:「name1=%76%61%6C%75%65%31%29name2=%76%61%64%75%29%65%32」

name1は「%76%61%6C%75%65%31」 = value1
name2は「=%76%61%64%75」= valu

private Function Byte_Replace(ByRef expression() As Byte, _
                                ByRef find As String, _
                                ByRef replacewith As String) As Byte()
                                
    Dim i                       As Long
    Dim j                       As Long
    Dim findByte()              As Byte
    Dim replacewithByte()       As Byte
    Dim newByte()               As Byte
    
    findByte = find
    replacewithByte = replacewith
    findByte = CodeChgFromTo(findByte, "unicode", "SHIFT_JIS")
    replacewithByte = CodeChgFromTo(replacewithByte, "unicode", "SHIFT_JIS")
    newByte = ""
    For i = 0 To UBound(expression)
        For j = 0 To UBound(findByte)
            If expression(i + j) <> findByte(j) Then
                Exit For
            End If
        Next
        If j = UBound(findByte) + 1 Then
            For j = 0 To UBound(replacewithByte)
                ReDim Preserve newByte(UBound(newByte) + 1)
                newByte(UBound(newByte)) = replacewithByte(j)
            Next
            i = i + UBound(findByte)
        Else
            ReDim Preserve newByte(UBound(newByte) + 1)
            newByte(UBound(newByte)) = expression(i)
        End If
    Next
    Byte_Replace = newByte
End Function


魔界の仮面弁士  2007-05-14 01:59:42  No: 98721

> 現在固定24byteキーにしています。
VB の話から離れつつあるので、続けるべきかどうか悩みますが、深く考えるのであれば、
どのレベルのセキュリティレベルを求める必要があるか、線引きしておく必要があります。
今回の場合、どこまでの対策を必要とする情報を扱っているのでしょうか?

暗号化を施せば、送信時および受信時の「盗聴」に対する、情報漏洩対策にはなるでしょうが、
それだけでは十分とは言えないでしょう。
通信途中でデータが横取りされ、内容が書きかえれているかも知れませんから。

たとえば暗号化を行うだけで、復元したあとのデータ検証チェックが行われていなければ、
それも脆弱性となりえます。検証機構が無いと、ゴミデータをサーバに投げられてしまい、
生の SQL エラーが表示され、そのメッセージからデータ構造が漏洩……なんて可能性もあるわけで。

> (固定20Byte(秘密鍵)+POSTで受け取った4Byte)で復号化
秘密鍵が固定的とのことで、ネットワーク上には送信しないつもりかと思いますが、
残る 4 バイトについては、ランダムであろうとなかろうと、鍵自体を無保護で
送信している以上、そこがセキュリティホールとなりえる可能性があります。
(そのランダムキーが、こっそり別のキーに改竄されて送信されていたらどうなりますか?)

で……そもそもこれって、共通鍵暗号化方式ですよね。

共通鍵暗号化方式の場合、盗聴者が秘密鍵を拾えばデータを開けてしまいますので、
より安全に通信を行うために、公開鍵暗号化を使った方が良いのではないでしょうか。
# 共通鍵との併用という手もアリですが。

なお実装には、CryptoAPI を使用できます。(PHP 側の実装手法は知りませんが…)

さらに、電子署名として、「元データのハッシュ値を自身の秘密鍵で暗号化したもの」も、
データ本体と一緒に送信しておくと、データが改竄されていない事の確認もできます。

> 今回の場合下記の認識でよろしいでしょうか。
> クライアント:「name1=value1&name2=valu&e2」
えぇと、どこまで[キー]で、どこからが[値]なのでしょうか?
それとも、すべて一つの値としたいのでしょうか?

もし、
  キー名 "name1" に対して "value1" という値
  キー名 "name2" に対して "value2" という値
を渡したいなら、送信データは「name1=value1&name2=value2」ですし、
  キー名 "name1" に対して "value1" という値
  キー名 "name2" に対して "valu&e2" という値
を渡したいなら、送信データは「name1=value1&name2=valu%26e2」となり、
  キー名 "name" に対して "name1=value1&name2=valu&e2" という値
を渡したいなら、「name=name1%3Dvalue1%26name2%3Dvalu%26e2」となります。

> ReDim Preserve newByte(UBound(newByte) + 1)
バイト配列で管理するよりも、Stream オブジェクトのまま管理した方が楽ですよ。
Stream であれば、「x バイト目から y バイト取得する」といった作業や、
末尾へのデータ追加や切捨てなども、ループ無しで容易に行えますので。


まさあき  2007-05-15 08:03:27  No: 98722

魔界の仮面弁士さま

プログラム完成いたしました。

いろいろ勉強になりました。
ありがとうございます。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加