So… I am not happy with Adobe right now. With the push of Flash Player 9,0,115,0 “moviestar”, which included such awesome features as H.264 and AAC codec support and improvements to fullscreen mode, they kind of ambushed me with some sweeping changes to their security policy.
I’d been running pre-release nightly builds of the player since 9,0,60,x… and had noticed some strange warnings. Mysterious “Socket Security Error #2048” exceptions that were being thrown at random – even though I was serving an appropriate (for the time) crossdomain.xml file, unexplained timeouts attempting to talk to an xml socket server when I was very clearly not attempting to do any such thing, etc… My regularly repeated attempts to find documentation on what the warnings actually meant proved fruitless. I believe that is because the appropriate document was not actually released to the public until 9,0,115,0 was released.
Now, the bit where they improved the format for crossdomain.xml files doesn’t really affect me one way or the other. I approve of the improvements but could really care less in this case. They don’t really affect anything I’m doing.
The part that really chaps my hide is the fact that they’ve completely redone the way that socket security policies are handled. The important parts:
- A SWF file may no longer make a socket connection to its own domain without a socket policy file. Prior to version 9,0,115,0, a SWF file was permitted to make socket connections to ports 1024 or greater in its own domain without a policy file.
- HTTP policy files may no longer be used to authorize socket connections. Prior to version 9,0,115,0, an HTTP policy file, served from the master location of /crossdomain.xml on port 80, could be used to authorize a socket connection to any port 1024 or greater on the same host.
That’s right. Your socket policy data can’t live in the sitewide crossdomain.xml file that Apache serves any more.
Flash Player 9,0,115,0 introduces a concept of socket master policy files, which are served from the fixed TCP port number 843.
Socket policy files may be obtained from the same port as a main connection (the socket connection being made by ActionScript, which is authorized by a socket policy file), or from a different port, separate from the main connection. If you opt to serve a socket policy file from the same port as a main connection, the server listening on that port must understand socket policy file requests (which are indicated by a transmission of from Flash Player), and must respond differently for policy file requests and main connection requests.
- When a SWF file attempts to make a socket connection, even to its own domain, Flash Player will first attempt to contact port 843 to see if the host is serving a socket master policy file.
So… regardless of whether you’re even using a custom port 843 client, the Flash Player is going to try to hit it. What if your firewall doesn’t allow/route traffic to sub-1024 ports w/o special configuration? What if you don’t have the access to bind to a sub-1024 port and can’t rewrite your other server process to serve the policy data on its port?
- Socket meta-policies can only be declared in a socket master policy file. The syntax is the same as for declaring a meta-policy in an URL master policy file, using the <site-control> tag. Socket meta-policies cannot be declared in HTTP response headers, as HTTP is not involved.
This implies that you can’t even tell apache to listen to port 843 and serve up the data. You HAVE to either maintain a separate server process specifically for the purpose of serving this policy data, or you have to edit the process that SWF’s are connecting to and make them serve the data..
As of the time of this writing (10 days after moviestar’s release), they have yet to release promised help on how to deploy a solution to these new changes. Granted, the one article they did release explains what needs to be done in high level terms. It was sufficient to help me out. I wrote a server that simply listens on port 843 and spews the required xml. But… I’d have really appreciated specific examples, and I suspect plenty of people would appreciate drop-in solutions to the issue.
A 5-minute skeleton implementation (not recommended for production use by any means) written as a PHP cli script might look something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
|
#!/usr/bin/php <? /** * Ugly Flash socket policy file service. This script must be run as root from * the command line. It binds to port 843 on all interfaces and waits * indefinitely for connections. When a connection is detected, the script spits * out a chunk of xml and disconnects. It can only serve one request at a time, * but that shouldn't be much of a problem. * * One potential problem with this script is that you can easily lock port 843 * up for an indeterminate amount of time if the script doesn't exit cleanly. * The OS should clear the port up for you eventually, but you could be stuck * playing the waiting game. * * This particular version of the script has only been tested very lightly. * Deploy at your own peril ;) YMMV. * * - Ammon Lauritzen [12/13/07] */ // define the xml policy "file" $policy_file = '<'.'?xml version="1.0" encoding="UTF-8"?'.'>'. '<cross-domain-policy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.adobe.com/xml/schemas/PolicyFileSocket.xsd">'. '<allow-access-from domain="*" to-ports="*" secure="false" />'. '<site-control permitted-cross-domain-policies="master-only" />'. '</cross-domain-policy>'; // make sure everything launches correctly if( posix_getuid() != 0 ) die( "You must run this script as root.\\\n" ); $sock = @socket_create( AF_INET, SOCK_STREAM, SOL_TCP ); if( !$sock ) die( "Unable to create socket.\\\n" ); $succ = @socket_bind( $sock, "0.0.0.0", 843 ); if( !$succ ) die( "Unable to bind to port 843.\\\n" ); $succ = @socket_listen( $sock ); if( !$succ ) die( "Unable to start listening.\\\n" ); // start serving policies while( true ) { $r = $w = $e = array( $sock ); if( @socket_select( $r, $w, $e, null ) !== false ) { $conn = @socket_accept( $sock ); if( $conn !== false ) { // somebody connected, just dump the xml and close socket_write( $conn, $policy_file ); socket_close( $conn ); } else { echo "socket_accept() failed?\\\n"; break; } } else { echo "socket_select() failed?\\\n"; break; } }// end: listen forever // clean up socket_close( $sock ); ?> |
I’ll try to make my production version of this a bit more suitable for public consumption and release it as soon as I can.
The random #2048 security errors continue, despite having deployed my port 843 policy xml server. Granted, they happen less than before… but they still happen. And even when my policy server isn’t running, the errors aren’t thrown 100% of the time. This just baffles me. If they were consistent, that would be one thing. But when you get a security error 1 time in 20… that’s not security, that’s not even a lame deterrent. It’s just incentive to hammer the same port over and over again until something finally gives.
Now, I admit that I could be wrong here… but I’ve re-re-read the documentation on these policies a few times now, and cannot find any reason for the behaviors I’m seeing.
update
On April 22nd, 2008, I released a much better, much more reliable version of this daemon. Head over there for more details and source code.