【问题标题】:AS3: Obscuring Loaded ResourcesAS3:隐藏加载的资源
【发布时间】:2010-09-11 17:06:44
【问题描述】:

这是一个两部分的问题。我正在构建一个 Flash 图像查看器作为便携式年龄限制模块(暴力视频游戏)。基本上,它会从 CDN 加载任意数量的图像,并要求用户在查看之前输入他们的生日。简单的东西。问题是,根据公司政策,我们不能允许通过任何嗅探方式直接访问这些图像(例如,查看 Webkit/Firebug 中的 Resources/Net 选项卡,或者如果我们以这种方式加载它们,则查看 XHR)。所以,我想就解决这个问题的最佳方法征求您的意见。

起初我以为有一个服务器端脚本,它通过传递一个可以解密但带有动态盐的 var 来加载图像(例如通过 PHP),例如,使用一种不太可能被发现的方法(例如,将盐嵌入到整个字符串中),但这违背了 CDN 的目的,因为所有请求都将被定位到服务器。

然后我认为通过套接字加载图像会是一个很好的解决方案,但是,我无法将二进制图像(在删除响应标头后)转换为位图。

有没有更好的方法来解决这个问题?我知道实际上不可能完全阻止内容被链接到(例如,有人可以截取 Flash),但我的目标只是采取措施站在我们这边,以防止这种情况通过本地方式发生。任何想法将不胜感激。下面是套接字代码(删除了不相关的部分),如果有帮助的话。

package com.std.socket {
    import flash.system.Security;
    import flash.net.Socket;
    import flash.events.*;
    import flash.errors.*;
    import flash.display.Bitmap;
    import flash.display.MovieClip;
    import flash.display.Loader;
    import flash.utils.ByteArray;

    public class SocketRequest {
        private var root:MovieClip;
        private var sock:Socket;
        private var data:ByteArray = new ByteArray();
        private var request:Object = {
            'host': null,
            'port': null,
            'uri': null,
            'callback': null,
            'response_parts': [] };

        public function SocketRequest(root:MovieClip, host:String, port:int, uri:String, callback:Function):void {
            Security.allowDomain('*');
            Security.loadPolicyFile('http://foo.bar/crossdomain.xml');

            this.request.root = root;
            this.request.host = host;
            this.request.port = port;
            this.request.uri = uri;

            this.sock = new Socket();
            this.sock.addEventListener(Event.CONNECT, this.evt_socketConnect);
            this.sock.addEventListener(Event.CLOSE, this.evt_socketClose);
            this.sock.addEventListener(ProgressEvent.SOCKET_DATA, this.evt_socketResponse);
            this.sock.connect(this.request.host, this.request.port);
        }

        private function evt_socketConnect(evt:Event):void {
            // Send the request headers
            this.sock.writeUTFBytes('GET ' + this.request.uri + " HTTP/1.1\n");
            this.sock.writeUTFBytes('Host: ' + this.request.host + ':' + this.request.port + "\n\n");
        }

        private function evt_socketClose(evt:Event):void {
            // Since this is an image, just split on header \r\n and get the last member 
            var response:Array = this.request.response_parts.join('').split("\r\n");
            var body:String = response[response.length - 1];
            var loader = new Loader();
            var ba:ByteArray = new ByteArray();
            var mc:MovieClip = new MovieClip();

            this.data.writeMultiByte(body, 'utf-8');

            loader.loadBytes(this.data);
            mc.addChild(loader);

            // Pass the resulting MovieClip back to the caller
            if(typeof(this.request.callback) == 'function')
                this.request.callback.apply(this.request.root, [mc])
        }

        private function evt_socketResponse(evt:ProgressEvent):void {
            if(!this.sock.bytesAvailable)
                return;
            this.request.response_parts.push(this.sock.readUTFBytes(this.sock.bytesAvailable));
        }
    }
}

在我写这篇文章的时候,我在想SocketRequest::evt_socketResponse() 中的this.sock.readUTFBytes() 位应该是:

this.request.response_parts.push(this.sock.readBytes(this.data, this.data.length, evt.bytesLoaded));

然后从this.data 中删除标题,但TBH 我不是超级精通字节数组。有人有什么想法吗?

【问题讨论】:

    标签: flash actionscript-3


    【解决方案1】:

    您的代码有几处看起来有问题。

    首先,您使用的是 read/writeUTF8Bytes。这不适用于二进制数据。你需要读/写字节。

    其次,标头由\r\n\r\n 序列终止,而不是\r\n

    我会这样做:

    private function evt_socketClose(evt:Event):void {
    
        _buffer.position = 0;
        var pos:int = 0;
    
        while(_buffer.bytesAvailable >= 4) {
    
            if(_buffer.readUnsignedByte() == 0xd && _buffer.readUnsignedByte() == 0xa
                && _buffer.readUnsignedByte() == 0xd && _buffer.readUnsignedByte() == 0xa) {
    
                var bodyBytes:ByteArray = new ByteArray();
                bodyBytes.writeBytes(_buffer,_buffer.position);
                var loader:Loader = new Loader();
                var mc:MovieClip = new MovieClip();
                loader.loadBytes(bodyBytes);
                mc.addChild(loader); 
                if(this.request.callback is Function) {
                    this.request.callback.apply(this.request.root, [mc]);
                }
                // this return isn't really neccesary...
                return;
            }
        }
    
    }
    
    private var _buffer:ByteArray = new ByteArray();
    
    private function evt_socketResponse(evt:ProgressEvent):void {
        if(!this.sock.bytesAvailable) {
            return;
        }
        var bytesToRead:uint = this.sock.bytesAvailable;
        this.sock.readBytes(_buffer,_buffer.position,bytesToRead);
        _buffer.position += bytesToRead;
    }
    

    基本上,当您接收数据时,会将其存储在缓冲区中。数据完成后,您开始读取此缓冲区,直到找到标头的结尾(\r\n\r\n0xd,0xa,0xd,0xa)。此时,您的缓冲区位置是正文/有效负载的第一个字节。因此,您从该点到最后读取缓冲区并将其存储在 ByteArray 中。然后将此 ByteArray 传递给Loader::loadBytes,如果您加载的是有效图像或 swf,则应该加载它。

    【讨论】:

    • 现在更清楚了。这些修复工作完美。感谢您的帮助!
    • @mway。没问题。我很高兴这对您有所帮助。
    猜你喜欢
    • 2010-10-20
    • 2020-03-30
    • 2012-03-21
    • 2011-08-06
    • 1970-01-01
    • 2012-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多