当方法返回的类型未implement java.io.Serializable时,会throw exception;
原因: SerializerFactory中以下方法:
/** * Returns the default serializer for a class that isn't matched * directly. Application can override this method to produce * bean-style serialization instead of field serialization. * * @param cl the class of the object that needs to be serialized. * * @return a serializer object for the serialization. */ protected Serializer getDefaultSerializer(Class cl) { if (_defaultSerializer != null) return _defaultSerializer; if (! Serializable.class.isAssignableFrom(cl) && ! _isAllowNonSerializable) { throw new IllegalStateException("Serialized class " + cl.getName() + " must implement java.io.Serializable"); } if (_isEnableUnsafeSerializer && JavaSerializer.getWriteReplace(cl) == null) { return UnsafeSerializer.create(cl); } else return JavaSerializer.create(cl); }
其中_isAllowNonSerializable默认为false。那如果返回的类型不想implement java.io.Serializable 怎么办呢?
查看HessianServlet中的代码,没有修改SerializerFactory的_isAllowNonSerializable的值,也就是不能通过web.xml中的配置来设置这个开关了,所以只能使用自己继承HessianServlet的servlet了,然后在自定义的servlet中把SerializerFactory的_isAllowNonSerializable值改为true;
public boolean isAllowNonSerializable()
{
return _isAllowNonSerializable;
}
再看看isAllowNonSerializable()被调用的情况,发现没有被任何对象调用,说明_isAllowNonSerializable只会在getDefaultSerializer()方法中起作用,也从另一方面说明hessian的序列化跟java.io.Serializable无关,只是有个_isAllowNonSerializable的开关而已,hessian实现了自己的序列号方式:
Hessian2Output.java:
/** * Writes any object to the output stream. */ public void writeObject(Object object) throws IOException { if (object == null) { writeNull(); return; } Serializer serializer = findSerializerFactory().getObjectSerializer(object.getClass()); serializer.writeObject(object, this); }
UnsafeSerializer.java:
public void writeObject(Object obj, AbstractHessianOutput out) throws IOException { if (out.addRef(obj)) { return; } Class<?> cl = obj.getClass(); int ref = out.writeObjectBegin(cl.getName()); if (ref >= 0) { writeInstance(obj, out); } else if (ref == -1) { writeDefinition20(out); out.writeObjectBegin(cl.getName()); writeInstance(obj, out); } else { writeObject10(obj, out); } } final public void writeInstance(Object obj, AbstractHessianOutput out) throws IOException { try { FieldSerializer []fieldSerializers = _fieldSerializers; int length = fieldSerializers.length; for (int i = 0; i < length; i++) { fieldSerializers[i].serialize(out, obj); //序列化方法返回结果到输出流 } } catch (RuntimeException e) { throw new RuntimeException(e.getMessage() + "\n class: " + obj.getClass().getName() + " (object=" + obj + ")", e); } catch (IOException e) { throw new IOExceptionWrapper(e.getMessage() + "\n class: " + obj.getClass().getName() + " (object=" + obj + ")", e); } } @Override final void serialize(AbstractHessianOutput out, Object obj) throws IOException { try { Object value = _unsafe.getObject(obj, _offset); //获取obj对象中的属性值 out.writeObject(value);//把属性值写入out,由于属性值是基本类型(比如:字符串),则writeObject会调用字符串相应的serializer(BasicSerializer)的serialize(out, obj)方法(见后面)
} catch (RuntimeException e) {
throw new RuntimeException(e.getMessage() + "\n field: "
+ _field.getDeclaringClass().getName()
+ '.' + _field.getName(),
e);
} catch (IOException e) {
throw new IOExceptionWrapper(e.getMessage() + "\n field: "
+ _field.getDeclaringClass().getName()
+ '.' + _field.getName(),
e);
}
}
基本类型对应的BasicSerializer的serializer(out,obj)方法:
public void writeObject(Object obj, AbstractHessianOutput out) throws IOException { switch (_code) { case BOOLEAN: out.writeBoolean(((Boolean) obj).booleanValue()); break; case BYTE: case SHORT: case INTEGER: out.writeInt(((Number) obj).intValue()); break; case LONG: out.writeLong(((Number) obj).longValue()); break; case FLOAT: case DOUBLE: out.writeDouble(((Number) obj).doubleValue()); break; case CHARACTER: case CHARACTER_OBJECT: out.writeString(String.valueOf(obj)); break; case STRING: out.writeString((String) obj); break; case DATE: out.writeUTCDate(((Date) obj).getTime()); break; case BOOLEAN_ARRAY: { if (out.addRef(obj)) return; boolean []data = (boolean []) obj; boolean hasEnd = out.writeListBegin(data.length, "[boolean"); for (int i = 0; i < data.length; i++) out.writeBoolean(data[i]); if (hasEnd) out.writeListEnd(); break; } case BYTE_ARRAY: { byte []data = (byte []) obj; out.writeBytes(data, 0, data.length); break; } case SHORT_ARRAY: { if (out.addRef(obj)) return; short []data = (short []) obj; boolean hasEnd = out.writeListBegin(data.length, "[short"); for (int i = 0; i < data.length; i++) out.writeInt(data[i]); if (hasEnd) out.writeListEnd(); break; } case INTEGER_ARRAY: { if (out.addRef(obj)) return; int []data = (int []) obj; boolean hasEnd = out.writeListBegin(data.length, "[int"); for (int i = 0; i < data.length; i++) out.writeInt(data[i]); if (hasEnd) out.writeListEnd(); break; } case LONG_ARRAY: { if (out.addRef(obj)) return; long []data = (long []) obj; boolean hasEnd = out.writeListBegin(data.length, "[long"); for (int i = 0; i < data.length; i++) out.writeLong(data[i]); if (hasEnd) out.writeListEnd(); break; } case FLOAT_ARRAY: { if (out.addRef(obj)) return; float []data = (float []) obj; boolean hasEnd = out.writeListBegin(data.length, "[float"); for (int i = 0; i < data.length; i++) out.writeDouble(data[i]); if (hasEnd) out.writeListEnd(); break; } case DOUBLE_ARRAY: { if (out.addRef(obj)) return; double []data = (double []) obj; boolean hasEnd = out.writeListBegin(data.length, "[double"); for (int i = 0; i < data.length; i++) out.writeDouble(data[i]); if (hasEnd) out.writeListEnd(); break; } case STRING_ARRAY: { if (out.addRef(obj)) return; String []data = (String []) obj; boolean hasEnd = out.writeListBegin(data.length, "[string"); for (int i = 0; i < data.length; i++) { out.writeString(data[i]); } if (hasEnd) out.writeListEnd(); break; } case CHARACTER_ARRAY: { char []data = (char []) obj; out.writeString(data, 0, data.length); break; } case OBJECT_ARRAY: { if (out.addRef(obj)) return; Object []data = (Object []) obj; boolean hasEnd = out.writeListBegin(data.length, "[object"); for (int i = 0; i < data.length; i++) { out.writeObject(data[i]); } if (hasEnd) out.writeListEnd(); break; } case NULL: out.writeNull(); break; case OBJECT: ObjectHandleSerializer.SER.writeObject(obj, out); break; case BYTE_HANDLE: out.writeObject(new ByteHandle((Byte) obj)); break; case SHORT_HANDLE: out.writeObject(new ShortHandle((Short) obj)); break; case FLOAT_HANDLE: out.writeObject(new FloatHandle((Float) obj)); break; default: throw new RuntimeException(_code + " unknown code for " + obj.getClass()); } }
再看看out怎么写基本类型的:
public void writeBoolean(boolean value)
throws IOException
{
if (SIZE < _offset + 16)
flushBuffer();
if (value)
_buffer[_offset++] = (byte) 'T';
else
_buffer[_offset++] = (byte) 'F';
}
public void writeInt(int value)
throws IOException
{
int offset = _offset;
byte []buffer = _buffer;
if (SIZE <= offset + 16) {
flushBuffer();
offset = _offset;
}
if (INT_DIRECT_MIN <= value && value <= INT_DIRECT_MAX)
buffer[offset++] = (byte) (value + BC_INT_ZERO);
else if (INT_BYTE_MIN <= value && value <= INT_BYTE_MAX) {
buffer[offset++] = (byte) (BC_INT_BYTE_ZERO + (value >> 8));
buffer[offset++] = (byte) (value);
}
else if (INT_SHORT_MIN <= value && value <= INT_SHORT_MAX) {
buffer[offset++] = (byte) (BC_INT_SHORT_ZERO + (value >> 16));
buffer[offset++] = (byte) (value >> 8);
buffer[offset++] = (byte) (value);
}
else {
buffer[offset++] = (byte) ('I');
buffer[offset++] = (byte) (value >> 24);
buffer[offset++] = (byte) (value >> 16);
buffer[offset++] = (byte) (value >> 8);
buffer[offset++] = (byte) (value);
}
_offset = offset;
}
public final void flushBuffer()
throws IOException
{
int offset = _offset;
OutputStream os = _os;
if (! _isPacket && offset > 0) {
_offset = 0;
if (os != null)
os.write(_buffer, 0, offset);
}
else if (_isPacket && offset > 3) {
int len = offset - 3;
_buffer[0] = (byte) 0x80;
_buffer[1] = (byte) (0x80 + ((len >> 7) & 0x7f));
_buffer[2] = (byte) (len & 0x7f);
_offset = 3;
if (os != null)
os.write(_buffer, 0, offset);
_buffer[0] = (byte) 0x56;
_buffer[1] = (byte) 0x56;
_buffer[2] = (byte) 0x56;
}
}
public final static int SIZE = 4096;
可见项buffer中写数据前,都会判断_offset大写,如果足够大,则flushBuffer。
相关推荐
NULL 博文链接:https://qinghua0208.iteye.com/blog/493516
介绍自己不会查吗?这里有一个点就是Hessian的序列化与反序列化与原生序列化与反序列化不同,就以使用的Resin链而言,其中的javax.naming.spi
Hessian 2.0序列化协议规范
Nacos JRaft Hessian 反序列化 RCE 分析.pdf
NULL 博文链接:https://inter12.iteye.com/blog/1555678
hessian序列化.pdf
主要通过对二者简单的实现方式的对比,介绍了Java序列化和hessian序列化的差异,具有一定参考价值,需要的朋友可以了解下。
NULL 博文链接:https://san-yun.iteye.com/blog/1688510
a --args gadget入参,多个参数使用多次该命令传入,例-a -a Calc-p --protocol [dubbo|http] 通讯协议名称,默认缺省dubbo-s --serialization [hessian|java] 序列化类型,默认缺省hessian-t --target 目标,例:...
默认就是⾛ dubbo 协议,单⼀⻓连接,进⾏的是 NIO 异步通信,基于 hessian 作为序列化协议。使⽤的场景是:传输数据量⼩ (每次请求在 100kb 以内),但是并发量很⾼。 为了要⽀持⾼并发场景,⼀般是服务提供者就⼏...
hessian.jar,Hessian的序列化输出 ,
hessian轻量级 rpc实现
java hessian-3.0.38.jar。修改了原生的jar包,解决了hessian 序列化BigDecimal的精度问题。注意,请在hessian服务端和客户端中分别替换此jar包哦!! 只替换服务端hessian jar包还是会有问题。
SOFA-Hessian 基于原生Hessian v4.0.51进行改进,目前已经蚂蚁金服内部稳定运行多年。我们修复了一些bug,增强了一些功能,并且添加了一些特性。包括:增加泛化序列化。增加 ClassNameResolver 和 ClassNameFilter ...
Hessian 2.0序列化协议规范 翻译: Edison peng 目录 1.概述 4 2.设计
远程调用方法就是HttpInvoker:他也是将参数和返回值通过Java的序列化机制进行编组和反编组,它具有RMI的支持所有可序列化对象的优点。试使用Http协议传输二进制流的,同时又具有Hessian、Burlap(传输xml文本)的...
-a:生成exploit下的所有payload(例如:hessian下的SpringPartiallyComparableAdvisorHolder, SpringAbstractBeanFactoryPointcutAdvisor, Rome, XBean, Resin) -t:对生成的payloads进行解码测试 -v:verbose mode...
该案例有hessian java python,该案例有hessian java python,该案例有hessian java python
Hessian多个版本下载,包括Hessian3.1.6,Hessian3.2.1,Hessian4.0.7