这篇文章上次修改于 3029 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

参考文档:http://www.adobe.com/devnet/flashplayer/articles/socket_policy_files.html

背景介绍:

最近业务使用websocket,为了能兼容低版本浏览器 比如IE,使用了web_socket.js 。web_socket.js在低版本浏览器下面主要使用的是WebSocketMain.swf 这个flash作为socket的通信。adob公司在开发flash的时候为了安全考虑,做了一套安全策略,在通信之前先获取服务器上面的安全策略文件。所以我们需要在服务器上面搭建一套安全策略服务。

搭建:

  1、安全策略文件样例 policyfile.xml

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "/xml/dtds/cross-domain-policy.dtd">
<!-- Policy file for xmlsocket://socks.example.com -->
<cross-domain-policy>
     <allow-access-from domain="*" to-ports="*" />
</cross-domain-policy>

 

2、服务python程序 flashpolicyd.py

#!/usr/bin/env python
#
# flashpolicyd.py
# Simple socket policy file server for Flash
#
# Usage: flashpolicyd.py [--port=N] --file=FILE
#
# Logs to stderr
# Requires Python 2.5 or later
from __future__ import with_statement
import sys
import optparse
import socket
import thread
import exceptions
import contextlib
VERSION = 0.1
class policy_server(object):
    def __init__(self, port, path):
        self.port = port
        self.path = path
        self.policy = self.read_policy(path)
        self.log('Listening on port %d\n' % port)
        try:
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        except AttributeError, socket.error:
            # AttributeError catches Python built without IPv6
            # socket.error catches OS with IPv6 disabled
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind(('', port))
        self.sock.listen(5)
    def read_policy(self, path):
        with file(path, 'rb') as f:
            policy = f.read(10001)
            if len(policy) > 10000:
                raise exceptions.RuntimeError('File probably too large to be a policy file',
                                              path)
            if 'cross-domain-policy' not in policy:
                raise exceptions.RuntimeError('Not a valid policy file',
                                              path)
            return policy
    def run(self):
        try:
            while True:
                thread.start_new_thread(self.handle, self.sock.accept())
        except socket.error, e:
            self.log('Error accepting connection: %s' % (e[1],))
    def handle(self, conn, addr):
        addrstr = '%s:%s' % (addr[0],addr[1])
        try:
            self.log('Connection from %s' % (addrstr,))
            with contextlib.closing(conn):
                # It's possible that we won't get the entire request in
                # a single recv, but very unlikely.
                request = conn.recv(1024).strip()
                if request != '<policy-file-request/>\0':
                    self.log('Unrecognized request from %s: %s' % (addrstr, request))
                    return
                self.log('Valid request received from %s' % (addrstr,))
                conn.sendall(self.policy)
                self.log('Sent policy file to %s' % (addrstr,))
        except socket.error, e:
            self.log('Error handling connection from %s: %s' % (addrstr, e[1]))
        except Exception, e:
            self.log('Error handling connection from %s: %s' % (addrstr, e[1]))
    def log(self, str):
        print >>sys.stderr, str
def main():
    parser = optparse.OptionParser(usage = '%prog [--port=PORT] --file=FILE',
                                   version='%prog ' + str(VERSION))
    parser.add_option('-p', '--port', dest='port', type=int, default=843,
                      help='listen on port PORT', metavar='PORT')
    parser.add_option('-f', '--file', dest='path',
                      help='server policy file FILE', metavar='FILE')
    opts, args = parser.parse_args()
    if args:
        parser.error('No arguments are needed. See help.')
    if not opts.path:
        parser.error('File must be specified. See help.')
    try:
        policy_server(opts.port, opts.path).run()
    except Exception, e:
        print >> sys.stderr, e
        sys.exit(1)
    except KeyboardInterrupt:
        pass
if __name__ == '__main__':
    main()


3、service启动程序 flashpolicyd.init

#! /bin/sh
#
# flashpolicyd   This starts and stops the Flash socket policy server
#
# chkconfig: 345 50 50
# description: The Flash socket policy server
#
# processname: /usr/local/sbin/flashpolicyd.py
# config: /usr/local/etc/flashpolicy.xml
. /etc/init.d/functions
#####################
#BEGIN CONFIG SECTION
#Location of daemon
prog=/usr/local/sbin/flashpolicyd.py
#Location of socket policy file
policy=/usr/local/etc/policyfile.xml
#Pid file to track start/stop of process
pidfile=/var/run/flashpolicyd
#Log file for logging (e.g. /var/log/flashpolicyd)
#logfile=/var/log/flashpolicyd
logfile=/dev/null
#END CONFIG SECTION
#####################
[ "$NETWORKING" = "no" ] && exit 0
[ -f "$prog" ] || exit 1
[ -f "$policy" ] || exit 1
RETVAL=0
start() {
    echo -n "Starting flashpolicyd: "
    $prog --file="$policy" 2>>"$logfile" & 
    RETVAL=$?
    echo $! > $pidfile
    [ "$RETVAL" -eq 0 ] && success $"$base startup" || failure $"$base startup"
    echo
    touch /var/lock/subsys/flashpolicyd
}
stop() {
    echo -n "Stopping flashpolicyd: "
    killproc -p $pidfile "$prog"
    RETVAL=$?
    echo
    rm -f /var/lock/subsys/flashpolicyd
}
restart() {
    stop
    start
}
condrestart() {
    [ -e /var/lock/subsys/flashpolicyd ] && restart
}
case "$1" in
    start)
    start
    ;;
    stop)
    stop
    ;;
    status)
    status -p "$pidfile" "$prog"
    ;;
    restart|reload)
    restart
    ;;
    condrestart)
    condrestart
    ;;
    *)
    echo "Usage: flashpolicyd {start|stop|status|restart}"
    RETVAL=1
esac
exit $RETVAL

4、安装程序 install.sh

#!/bin/sh
install -m644 policyfile.xml /usr/local/etc/
install -m755 flashpolicyd.py /usr/local/sbin/
install -m755 flashpolicyd.init /etc/rc.d/init.d/flashpolicyd
chkconfig --add flashpolicyd

5、执行命令安装

chmod +x install.sh
./install.sh

6、启动

service flashpolicyd start

注:默认启动的端口是843端口。如果你的服务器运行了iptabales,需要在iptables里面开发843端口。

ok,policy server服务搭建成功