Flash Socket通訊的安全策略問題 843端口

一、問題描述

      將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安全性——》控制權限概述中找到)

一、針對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 進行的數據加載調用。

二、針對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>

這個策略文件是指定容許哪些域的主機經過那些端口連接。 html

參考文章

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();
   }
}
相關文章
相關標籤/搜索