java flash 安全沙箱

flash底層安全機制強制要求flash通信或者跨域訪問時,必須從服務端拿到安全策略文件,默認是flash會向服務端843發送<policy-file-request/>報文,當服務端843不開放,或者安全時間(3秒)內無返回時,如果是socket通信,flash會向服務端socket指定端口發送請求報文<policy-file-request/>,如果服務端無返回或返回不是安全策略文件,那麼flash將報安全沙箱錯誤。安全策略文件內容如下:

<cross-domain-policy>

<allow-access-from domain="*" to-ports="*"/>

</cross-domain-policy>

其中domain指定可訪問的跨域地址,to-ports爲指定可訪問的跨域端口,

java服務端一般做法是開啓843端口服務,網上代碼如下:(此代碼測試有嚴重的bug,下面會指出)

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;
 private int stop = 0;

 public SecurityXMLServer() {
  xml = "<cross-domain-policy>"
    + "<allow-access-from domain=\"*\" to-ports=\"*\"/>"
    + "</cross-domain-policy>\0";

  // System.out.println(xml);

  // 啓動843端口
  createServerSocket(843);
  new Thread(this).start();
 }

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

 // 啓動服務器線程
 public void run() {
  while (true) {
   if (stop == 1)
    break;

   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);
     writer.flush();
     // System.out.println("將安全策略文件發送至: " +
     // client.getInetAddress());
    } else {
     writer.write("Quest Error \0");
     writer.flush();
     // System.out.println("請求無法識別: "+client.getInetAddress());
    }
    client.close();
   } catch (Exception e) {
    try {
     // 發現異常關閉連接
     if (client != null) {
      client.close();
      client = null;
     }
    } catch (IOException ex) {
     ex.printStackTrace();
    }
   }
  }
 }

 public ServerSocket getServer() {
  return server;
 }

 public void setStop(int stop) {
  this.stop = stop;
 }

}

這段代碼的bug出現在單線程監聽843,一旦客戶端假死,簡單可測試的方法就是連上後突然斷線,停電,那麼843端口被佔用,無法訪問,主要是  while ((c = reader.read()) != -1)

reader.read()當TCP異常時,是無法監測到的,斷線/停電等情況都會造成reader.read()阻塞,客戶端無消息到達,服務端也無法監測到客戶端的狀態,所以會一直阻塞,之前我的一個項目就是因爲用同樣的方式去讀取843安全請求信息,所以經常出現843阻塞,得靠重啓843服務來維護。其實Socket中有一個方法,setSoTimeout(毫秒),此方法設置了連接超時時間,

默認是setSoTimeout(0),只要在client = server.accept();後面加client.setSoTimeout(300);就不會再出現843阻塞無法連接的情況了!

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