java與FlashSocket通信安全(轉載)

  在Adobe Flash Player升級到9.0.124後,由於安全策略的更改,使得在socket或xmlsocket的應用裏,原先如用http方式加載安全策略的手段不能繼續使用了,類似此類應用必須使用xmlsocket://方式來提供安全策略。flashplayer的安全策略檢測過程如下:

1,首先檢測目標服務器的843端口是否提供安全策略
2,如果1沒有檢測到策略,則檢測actionscript是否使用了Security.loadPolicyFile(xmlsocket://) 手段提供安全策略,如果還沒檢測到,則使用第3步檢測
3,檢測目標服務器目標端口是否提供安全策略

如果上述檢測都不成功,則socket或xmlsocket則拒絕連接目標服務器。

 

昨天做測試的時候遇到一個問題,做好的SWF在Flash AS3中調試通過,但是發佈到html中之後就無法得到數據了。查了一些資料之後找到了解決辦法。這裏感謝 劍心 提供幫助,以及同事若水三千提供Java代碼及日誌記錄。

1、問題描述

      將flash發佈爲html格式後,加載頁面後,swf無法與服務器進行socket通信。Flash端顯示的錯誤爲:
securityErrorHandler信息: [SecurityErrorEvent type="securityError" bubbles=false cancelable=false eventPhase=2 text="Error #2048"]

      在服務器端顯示的信息是由客戶端嘗試進行連接,但是無法接受數據。接受的數據顯示爲空。

2.問題原因:

        最新的Flash player 9.0.124.0,當flash文件要進行socket通信的時候,需要向服務器端獲取crossdomain.xml文件。如果找不到就出現客戶端無法連接服務器的現象。

瞭解flash發起socket通信的三個過程

      當封裝在頁面的flash發起socket通信請求的時候會先尋找服務器端的843端口,獲取Crossdomain.xml文件,當服務器沒有開啓 843的時候,flashPlayer會檢查發起請求的swf文件中中有沒有使用Security.loadPolicyFile來加載策略文件 Crossdomain.xml,如果還是沒有就會看這個發起請求的swf要連接的目標端口有沒有策略文件。如果都沒有那麼連接失敗,返回如上的出錯提 示。

爲什麼老版本的Flash player沒有這個問題?

      從一些官方的一些資料中瞭解了一下。以前的Flash Player無論你採用urlRequest的http請求方式或者xmlsocket socket方式,他們都共用一個安全策略文件。這個策略文件只要你放在主域的目錄下就行了。而現在不行了,現在的策略文件如果你使用http請求方式那 麼需要把策略文件放在目錄下面,如果你使用socket請求方式就必須通過socket端口來接收這個策略文件。

      對應調用的方式爲:
      http請求——》Security.loadPolicyFile(“http://www.xxx.com/crossdomain.xml”)
      socket或xmlsocket請求——》Security.loadPolicyFile(“xmlsocket://www.xxx.com:port”)

怎麼將Socke策略文件發給Flash Player

      Flash Player在你的socket.connect("domain",port)運行之前,會按照前面描述的三個過程向你的socket服務器的843端 口(據說Adobe已經向相關管理機構申請保留843端口給Flash Player用)發送一個字符串 "<policy-file-request/>",這個時候如果你有一個服務在監聽843端口那麼收到這個字符串之後,直接按照XML格式 發回策略文件就解決了。(注意發回的時候記得加一個截止字符"/0")

    當然你也可以不用843端口自己設置一個端口。因爲Flash Player如果在843端口得不到信息,就會檢查你是否在你的Flash文件裏面自己添加了指定的獲取通道,你可以定義一個自己的端口。不過這個時候你 不能用http方式,而要用xmlsocket方式。(相當於自動幫你新建了一個xmlsocket對象,然後鏈接你指定的主機和端口)。比如你想用 1234端口可以在你的Flash裏面加這一句 Security.loadPolicyFile(“xmlsocket://www.xxx.com:1234”),需要注意的是這一句要加在你的 socket.connect前面。

    還有最後一個辦法,就是在你的socket連接端口監聽這個請求。比如你用的是 socket.connect("192.168.1.100",8888),那麼在你的服務器加一段接收字符串"<policy-file- request/>"的代碼,當接到這個字符串時將策略文家按照xml格式發到客戶端。

關於策略文件的格式(可以在Flash CS3幫助裏面的Flash Player安全性——》控制權限概述中找到)

1、針對web應用的策略文件

下面的示例顯示了一個策略文件,該文件允許訪問源自 *.iflashigame.com 和 192.0.34.166 的 SWF 文件。

<?xml version="1.0"?>
<cross-domain-policy>
    <allow-access-from domain="*.iflashigame.com" />
    <allow-access-from domain="192.0.34.166" />
</cross-domain-policy>

注意事項:
      默認情況下,策略文件必須命名爲 crossdomain.xml,並且必須位於服務器的根目錄中。但是,SWF 文件可以通過調用 Security.loadPolicyFile() 方法檢查是否爲其它名稱或位於其它目錄中。跨域策略文件僅適用於從其中加載該文件的目錄及其子目錄。因此,根目錄中的策略文件適用於整個服務器,但是從任 意子目錄加載的策略文件僅適用於該目錄及其子目錄。

      策略文件僅影響對其所在特定服務器的訪問。例如,位於 https://www.adobe.com:8080/crossdomain.xml 的策略文件只適用於在端口 8080 通過 HTTPS 對 www.adobe.com 進行的數據加載調用。

2、針對Socket的策略文件

<cross-domain-policy>
   <allow-access-from domain="*" to-ports="507" />
   <allow-access-from domain="*.example.com" to-ports="507,516" />
   <allow-access-from domain="*.example2.com" to-ports="516-523" />
   <allow-access-from domain="www.example2.com" to-ports="507,516-523" />
   <allow-access-from domain="www.example3.com" to-ports="*" />
</cross-domain-policy>

這個策略文件是指定允許哪些域的主機通過那些端口鏈接。

參考文章

flash xmlsocket policy 問題
Policy file changes in Flash Player 9
Setting up a socket policy file server
Understanding Flash Player 9 April 2008 Security Update compatibility

獲取策略文件的Java服務器端代碼

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class SecurityXMLServer implements Runnable {

   private ServerSocket server;
   private BufferedReader reader;
   private BufferedWriter writer;
   private String xml;
  
   public SecurityXMLServer()
   {
     String path = "policyfile文件路徑";
     //此處的換成相應的讀取xml文檔的方式如dom或sax
     //xml = readFile(path, "UTF-8");
       /**
         注意此處xml文件的內容,爲純字符串,沒有xml文檔的版本號
        */
     xml="<cross-domain-policy> "
        +"<allow-access-from domain=/"*/" to-ports=/"1025-9999/"/>"
     +"</cross-domain-policy> ";
     System.out.println("policyfile文件路徑: " + path);
     System.out.println(xml);
    
     //啓動843端口
     createServerSocket(843);
     new Thread(this).start();
   }

   //啓動服務器
   private void createServerSocket(int port)
   {
     try {
       server = new ServerSocket(port);
       System.out.println("服務監聽端口:" + port);
     } catch (IOException e) {
       System.exit(1);
     }
   }

   //啓動服務器線程
   public void run()
   {
     while (true) {
       Socket client = null;
       try {
        //接收客戶端的連接
         client = server.accept();

         InputStreamReader input = new InputStreamReader(client.getInputStream(), "UTF-8");
         reader = new BufferedReader(input);
         OutputStreamWriter output = new OutputStreamWriter(client.getOutputStream(), "UTF-8");
         writer = new BufferedWriter(output);

         //讀取客戶端發送的數據
         StringBuilder data = new StringBuilder();
         int c = 0;
         while ((c = reader.read()) != -1)
         {
           if (c != '/0')
             data.append((char) c);
           else
             break;
         }
         String info = data.toString();
         System.out.println("輸入的請求: " + info);
        
         //接收到客戶端的請求之後,將策略文件發送出去
         if(info.indexOf("<policy-file-request/>") >=0)
         {
           writer.write(xml + "/0");
           writer.flush();
           System.out.println("將安全策略文件發送至: " + client.getInetAddress());
         }
         else
         {
           writer.write("請求無法識別/0");
           writer.flush();
           System.out.println("請求無法識別: "+client.getInetAddress());
         }
         client.close();
       } catch (Exception e) {
         e.printStackTrace();
         try {
           //發現異常關閉連接
           if (client != null) {
             client.close();
             client = null;
           }
         } catch (IOException ex) {
           ex.printStackTrace();
         } finally {
           //調用垃圾收集方法
           System.gc();
         }
       }
     }
   }
  
   //測試主函數
   public static void main(String[] args)
   {
     new SecurityXMLServer();
   }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章