首先,先提供 flash 原始碼如下,與先前文章中的差別在於,分別使用了 open source 的 com.hurlant.crypto.tls.TLSSocket 與 SecureSocket 來作測試。
TestSecureSocket.as
package
{
import com.hurlant.crypto.tls.SSLSecurityParameters;
import com.hurlant.crypto.tls.TLSConfig;
import com.hurlant.crypto.tls.TLSEngine;
import com.hurlant.crypto.tls.TLSSocket;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.net.SecureSocket;
import flash.net.Socket;
import flash.system.Security;
public class TestSecureSocket extends Sprite
{
private var socket:Socket;
public function TestSecureSocket()
{
trace(SecureSocket.isSupported);
Security.allowDomain("*");
if(false){
var secureSocket:SecureSocket = new SecureSocket();
socket = secureSocket;
}else{
var tlsConfig:TLSConfig = new TLSConfig(TLSEngine.CLIENT, null, null, null, null, null, SSLSecurityParameters.PROTOCOL_VERSION);
tlsConfig.trustAllCertificates = true;
tlsConfig.trustSelfSignedCertificates = true;
tlsConfig.ignoreCommonNameMismatch = true;
socket = new TLSSocket(null, 0, tlsConfig);
}
trace("timeout=" + socket.timeout);
socket.connect("inner.FlashTeam.com", 8888);
socket.addEventListener(Event.CONNECT, onConnect);
socket.addEventListener(Event.CLOSE, onClose);
socket.addEventListener(IOErrorEvent.IO_ERROR, onError);
socket.addEventListener(ProgressEvent.SOCKET_DATA, onResponse);
socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecError);
}
private function onConnect(e:Event):void {
trace("onConnect()");
socket.writeUTFBytes("GET / HTTP/1.1\n");
socket.writeUTFBytes("Host: inner.flashteam.com\n");
socket.writeUTFBytes("<EOF>");
socket.flush();
}
private function onClose(e:Event):void {
// Security error is thrown if this line is excluded
trace("onClose()");
socket.close();
}
private function onError(e:IOErrorEvent):void {
trace("onError(), e=" + e);
if(socket is SecureSocket){
var serverCertificateStatus:String = (socket as SecureSocket).serverCertificateStatus;
trace("serverCertificateStatus=" + serverCertificateStatus);
}
}
private function onSecError(e:SecurityErrorEvent):void {
trace("onSecError(), e=" + e);
}
private function onResponse(e:ProgressEvent):void {
trace("onResponse()");
if (socket.bytesAvailable>0) {
trace(socket.readUTFBytes(socket.bytesAvailable));
}
}
}
}
接下來,以下是 .NET Socket Server 程式碼。會起兩個執行緒分別監聽 843 與 8888 port,若是 flash client 走 843 送來 <policy-file-request/>,就會於 Proc1() 得到對應的 policy file,若從 843 port 送來其他內容則會忽略。若 flash client 走 8888 送來 <policy-file-request/>,就會於 Proc2() 得到對應的 policy file,否則 Server 會將收到的資料改大寫後再送回給 flash client。
此外,Proc2() 中,是以 SslStream 處理資料,所以若從這裡能正常解碼出的資料就表示送來的資料有編碼加密過,證明 flash 使用 SecureSocket 要求 policy file 時是有 SSL 的。
MyTcpListener.cs
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
class MyTcpListener
{
static X509Certificate serverCertificate = null;
public static void Main()
{
X509Store store = new X509Store(StoreName.Root, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
for (int i = 0; i < store.Certificates.Count; i++)
{
X509Certificate cer = store.Certificates[i];
Console.WriteLine("[" + i + "]" + cer.Subject);
}
X509CertificateCollection collection = store.Certificates.Find(X509FindType.FindBySubjectName, "inner.FlashTeam.com", false);
Console.WriteLine("X509CertificateCollection.Count=" + collection.Count);
if (collection.Count == 0)
return;
serverCertificate = collection[0];
Thread t = new Thread(new ThreadStart(Proc1));
t.Start();
Thread t2 = new Thread(new ThreadStart(Proc2));
t2.Start();
}
private static void Proc1()
{
TcpListener server = null;
try
{
// TcpListener server = new TcpListener(port);
server = new TcpListener(IPAddress.Any, 843);
// Start listening for client requests.
server.Start();
// Buffer for reading data
Byte[] bytes = new Byte[256];
String data = null;
// Enter the listening loop.
while (true)
{
Console.WriteLine("[Proc1]Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("[Proc1]Connected!");
data = null;
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.UTF8.GetString(bytes, 0, i);
Console.WriteLine("[Proc1]Received: {0}", data);
if (data.StartsWith("<policy-file-request/>"))
{
data = "<?xml version=\"1.0\"?><cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>\0\r\n";
byte[] msg = System.Text.Encoding.UTF8.GetBytes(data);
// Send back a response.
stream.Write(msg, 0, msg.Length);
Console.WriteLine("[Proc1]Sent: {0}", data);
}
else
{
Console.WriteLine("[Proc1]ignore!!");
}
}
// Shutdown and end connection
client.Close();
}
}
catch (SocketException e)
{
Console.WriteLine("[Proc1]SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
Console.WriteLine("\n[Proc1]Hit enter to continue...");
Console.Read();
}
private static void Proc2()
{
TcpListener server = null;
try
{
// TcpListener server = new TcpListener(port);
server = new TcpListener(IPAddress.Any, 8888);
// Start listening for client requests.
server.Start();
// Buffer for reading data
Byte[] bytes = new Byte[2048];
String data = null;
// Enter the listening loop.
while (true)
{
Console.WriteLine("[Proc2]Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("[Proc2]Connected!");
data = null;
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
SslStream sslStream = new SslStream(stream, false);
sslStream.AuthenticateAsServer(serverCertificate, false, SslProtocols.Ssl3, true);
int i;
// Loop to receive all the data sent by the client.
while ((i = sslStream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.UTF8.GetString(bytes, 0, i);
Console.WriteLine("[Proc2]Received: {0}", data);
if (data.StartsWith("<policy-file-request/>"))
{
data = "<?xml version=\"1.0\"?><cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>\0\r\n";
byte[] msg = System.Text.Encoding.UTF8.GetBytes(data);
// Send back a response.
sslStream.Write(msg, 0, msg.Length);
Console.WriteLine("[Proc2]Sent: {0}", data);
}
else
{
data = "RECEIVE: [" + data.ToUpper() + "]";
byte[] msg2 = System.Text.Encoding.UTF8.GetBytes(data);
// Send back a response.
sslStream.Write(msg2, 0, msg2.Length);
Console.WriteLine("[Proc2]Sent: {0}", data);
}
}
// Shutdown and end connection
client.Close();
}
}
catch (SocketException e)
{
Console.WriteLine("[Proc2]SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
Console.WriteLine("\n[Proc2]Hit enter to continue...");
Console.Read();
}
}
進行測試~
首先,flash client 以 open source 的 TLSSocket 進行測試,會先向 843 以明碼索取 policy file:
因為 843 已經拿到需要的 policy file,所以可以正常的向 8888 進行溝通:
以下畫面是 Server log:
接下來,flash client 改以 SecureSocket 來測試,一開始會走 843 以加密過的 xml 來要求資料,但因為 server 不認得,所以沒有回傳正確的 policy file:
於是 flash client 只好向 8888 再用加密過的 xml 要一次,這時候 server 就看得懂了,便可以回傳加密過的 policy file 內容:
最後,flash client 就可以順利的向 8888 溝通資料了:
以下是 Server log,可以看出 Proc1() 不認得 xml 要求後,Proc2() 再次處理 <policy-file-request/> 的情況:
完成!







0 意見:
張貼意見