fast-serialization 反序列化时缺少字节数据的完整性检查

先一段简单的测试代码,看看fast-serialization在反序列化时缺少数据完整性检查是什么样一个情况:


//对字符串Hello World进行反序列化
 String str = "Hello World !";
 FSTConfiguration conf = FSTConfiguration.getDefaultConfiguration();
 ByteArrayOutputStream outStream = new ByteArrayOutputStream();
 conf.getObjectOutput(outStream).writeObject(str);
 byte[] bytes = outStream.toByteArray();


 //此处模拟数据失真,故意只截取序列化结果中的一部分数据
 byte[] copy = new byte[bytes.length - 5];
 System.arraycopy(bytes, 0, copy, 0, copy.length);


 //对失真的序列化结果进行反序列化,反序列化过程中并没有抛出异常
 ByteArrayInputStream inStream = new ByteArrayInputStream(copy);
 str = (String) conf.getObjectInput(inStream).readObject();
 
 System.out.println(str);

以上代码输出结果为“Hello Wo     ”。

咋一看似乎一切正常,因为故意截取了5个字节,所以反序列化的输出结果中丢失了5个字符,这样反序列化后的结果就失真了。

可仔细想想就发现不对的地方,如果是丢失了5个字节的话,输出结果应该是“Hello Wo”-8个字符,而不是“Hello Wo+5个空格“-13个字符,既然FST知道序列化时字符串length是13个字符,那为何没有因为反序列化的字节数据不完整而抛出异常,反而输出了一个失真的结果呢?

以上问题,最终在de.ruedigermoeller.serialization.util.FSTInputStream和de.ruedigermoeller.serialization.FSTObjectInput类中找到了答案:

public final class FSTInputStream extends InputStream {
    public int chunk_size = 1000;
    ... ...
    public void initFromStream(InputStream in) {
        try {
            this.in = in;
            if (buf==null) {
                buf = cachedBuffer.get();
                if ( buf == null ) {
                    buf = new byte[chunk_size];
                    cachedBuffer.set(buf);
                }
            }
            int read = in.read(buf);
            count+=read;
            //1.将所有反序列化的字节数据读取到本地的buffer中
            while( read != -1 ) {
                try {
                    //实际字节数据大小超出buffer容量时,buffer扩充到目前的2倍,默认是每次扩充1000个字节
                    //所以buffer中的字节数据并不都是有效数据
                    if ( buf.length < count+chunk_size ) {
                        ensureCapacity(buf.length*2);
                    }
                    read = in.read(buf,count,chunk_size);
                    if ( read > 0 )
                        count += read;
                } catch ( IndexOutOfBoundsException iex ) {
                    read = -1; // many stream impls break contract
                }
            }
            in.close();
        } catch (IOException e) {
            FSTUtil.rethrow(e);
        }
    }
    ... ...
}



public class FSTObjectInput extends DataInputStream implements ObjectInput {
   ... ...
   FSTInputStream input;
   ... ...
   public String readStringUTF() throws IOException {
        //2.获取反序列化的字符串长度
        int len = readCInt();
        char[] charBuf = getCharBuf(len*3);
        ensureReadAhead(len * 3);
        byte buf[] = input.buf;
        int count = input.pos;
        int chcount = 0;
        //3.以下是对字符串进行反序列化,首先从Input stream的buffer中读取到字符串的bytes数组,
        for (int i = 0; i < len; i++) {
             //这里从buffer中获取字节时并没有判断是否已经超出有效字节数据的范围
             //这就解释了为什么测试代码反序列化的结果是“Hello Wo     ”,是因为拿到无效的字节数据
            char head = (char) ((buf[count++] + 256) &0xff);
            if (head < 255) {
                charBuf[chcount++] = head;
            } else {
                int ch1 = ((buf[count++] + 256) &0xff);
                int ch2 = ((buf[count++] + 256) &0xff);
                charBuf[chcount++] = (char) ((ch1 << 8) + (ch2 << 0));
            }
        }
        input.pos = count;
        return new String(charBuf, 0, chcount);
    }
    ... ...
}




转载于:https://my.oschina.net/dakev/blog/220832

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值