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


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();
   }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM